blob: d4b41e1a8bc2e6aaf9c08e3e1dd375eeb4f32370 [file] [log] [blame]
Amit Arora17552782010-12-02 12:23:14 +05301/*******************************************************************************
Amit Kucheriac0e17fc2011-01-17 09:35:52 +02002 * Copyright (C) 2010, Linaro Limited.
Amit Arora17552782010-12-02 12:23:14 +05303 *
4 * This file is part of PowerDebug.
5 *
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 * Contributors:
12 * Amit Arora <amit.arora@linaro.org> (IBM Corporation)
13 * - initial API and implementation
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020014 * Daniel Lezcano <daniel.lezcano@linaro.org> (IBM Corporation)
15 * - rewrote code and API based on the tree
Amit Arora17552782010-12-02 12:23:14 +053016 *******************************************************************************/
17
18#include "regulator.h"
19
Daniel Lezcano2e6ecca2011-03-26 22:05:51 +010020#define SYSFS_REGULATOR "/sys/class/regulator"
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020021#define _GNU_SOURCE
22#include <stdio.h>
23#undef _GNU_SOURCE
24#include <sys/types.h>
25#include <stdbool.h>
26#include <dirent.h>
27#include <string.h>
28#include <stdlib.h>
29#include "powerdebug.h"
30#include "tree.h"
31#include "utils.h"
Daniel Lezcano2e6ecca2011-03-26 22:05:51 +010032
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020033struct regulator_info {
34 char name[NAME_MAX];
35 char state[VALUE_MAX];
36 char status[VALUE_MAX];
37 char type[VALUE_MAX];
38 char opmode[VALUE_MAX];
39 int microvolts;
40 int min_microvolts;
41 int max_microvolts;
42 int microamps;
43 int min_microamps;
44 int max_microamps;
45 int requested_microamps;
46 int num_users;
47};
48
49struct regulator_data {
50 const char *name;
51 const char *ifmt;
52 const char *ofmt;
53 bool derefme;
54};
55
56static struct regulator_data regdata[] = {
57 { "name", "%s", "\tname: %s\n" },
58 { "status", "%s", "\tstatus: %s\n" },
59 { "state", "%s", "\tstate: %s\n" },
60 { "type", "%s", "\ttype: %s\n" },
61 { "num_users", "%d", "\tnum_users: %d\n", true },
62 { "microvolts", "%d", "\tmicrovolts: %d\n", true },
63 { "max_microvolts", "%d", "\tmax_microvolts: %d\n", true },
64 { "min_microvolts", "%d", "\tmin_microvolts: %d\n", true },
65};
66
67static struct tree *reg_tree;
68
69static struct regulator_info *regulator_alloc(void)
Amit Arora17552782010-12-02 12:23:14 +053070{
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020071 struct regulator_info *regi;
Amit Arora17552782010-12-02 12:23:14 +053072
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020073 regi = malloc(sizeof(*regi));
74 if (regi)
75 memset(regi, 0, sizeof(*regi));
Daniel Lezcano4aab2fe2011-03-26 22:05:53 +010076
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020077 return regi;
Amit Arora17552782010-12-02 12:23:14 +053078}
79
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020080static int regulator_dump_cb(struct tree *tree, void *data)
Amit Arora17552782010-12-02 12:23:14 +053081{
82 int i;
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020083 char buffer[NAME_MAX];
84 size_t nregdata = sizeof(regdata) / sizeof(regdata[0]);
Amit Arora17552782010-12-02 12:23:14 +053085
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020086 if (!strncmp("regulator.", tree->name, strlen("regulator.")))
87 printf("\n%s:\n", tree->name);
88
89 for (i = 0; i < nregdata; i++) {
90
91 if (file_read_value(tree->path, regdata[i].name,
92 regdata[i].ifmt, buffer))
93 continue;
94
95 printf(regdata[i].ofmt, regdata[i].derefme ?
96 *((int *)buffer) : buffer);
97 }
98
99 return 0;
100}
101
102int regulator_dump(void)
103{
Amit Arora422c52f2010-12-02 16:22:29 +0530104 printf("\nRegulator Information:\n");
105 printf("*********************\n\n");
106
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200107 return tree_for_each(reg_tree, regulator_dump_cb, NULL);
Amit Arora17552782010-12-02 12:23:14 +0530108}
109
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200110static int regulator_display_cb(struct tree *t, void *data)
Amit Arora17552782010-12-02 12:23:14 +0530111{
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200112 struct regulator_info *reg = t->private;
113 int *line = data;
114 char *buf;
Amit Arora17552782010-12-02 12:23:14 +0530115
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200116 /* we skip the root node of the tree */
117 if (!t->parent)
118 return 0;
Amit Arora17552782010-12-02 12:23:14 +0530119
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200120 if (!strlen(reg->name))
121 return 0;
Amit Arora17552782010-12-02 12:23:14 +0530122
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200123 if (asprintf(&buf, "%-11s %-11s %-11s %-11s %-11d %-11d %-11d %-12d",
124 reg->name, reg->status, reg->state, reg->type,
125 reg->num_users, reg->microvolts, reg->min_microvolts,
126 reg->max_microvolts) < 0)
127 return -1;
Amit Arora17552782010-12-02 12:23:14 +0530128
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200129 display_print_line(REGULATOR, *line, buf, reg->num_users, t);
130
131 (*line)++;
132
133 free(buf);
134
135 return 0;
Amit Arora17552782010-12-02 12:23:14 +0530136}
137
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200138int regulator_display(void)
Amit Arora17552782010-12-02 12:23:14 +0530139{
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200140 int ret, line = 0;
Amit Arora17552782010-12-02 12:23:14 +0530141
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200142 display_reset_cursor(REGULATOR);
Amit Arora17552782010-12-02 12:23:14 +0530143
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200144 print_regulator_header();
Amit Arora17552782010-12-02 12:23:14 +0530145
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200146 ret = tree_for_each(reg_tree, regulator_display_cb, &line);
Amit Arora17552782010-12-02 12:23:14 +0530147
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200148 display_refresh_pad(REGULATOR);
Amit Arora17552782010-12-02 12:23:14 +0530149
150 return ret;
151}
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200152
153static int regulator_filter_cb(const char *name)
154{
155 /* let's ignore some directories in order to avoid to be
156 * pulled inside the sysfs circular symlinks mess/hell
157 * (choose the word which fit better)
158 */
159 if (!strcmp(name, "device"))
160 return 1;
161
162 if (!strcmp(name, "subsystem"))
163 return 1;
164
165 if (!strcmp(name, "driver"))
166 return 1;
167
168 return 0;
169}
170
171static inline int read_regulator_cb(struct tree *t, void *data)
172{
173 struct regulator_info *reg = t->private;
174
175 file_read_value(t->path, "name", "%s", reg->name);
176 file_read_value(t->path, "state", "%s", reg->state);
177 file_read_value(t->path, "status", "%s", reg->status);
178 file_read_value(t->path, "type", "%s", reg->type);
179 file_read_value(t->path, "opmode", "%s", reg->opmode);
180 file_read_value(t->path, "num_users", "%d", &reg->num_users);
181 file_read_value(t->path, "microvolts", "%d", &reg->microvolts);
182 file_read_value(t->path, "min_microvolts", "%d", &reg->min_microvolts);
183 file_read_value(t->path, "max_microvolts", "%d", &reg->max_microvolts);
184 file_read_value(t->path, "microamps", "%d", &reg->microamps);
185 file_read_value(t->path, "min_microamps", "%d", &reg->min_microamps);
186 file_read_value(t->path, "max_microamps", "%d", &reg->max_microamps);
187
188 return 0;
189}
190
191static int fill_regulator_cb(struct tree *t, void *data)
192{
193 struct regulator_info *reg;
194
195 reg = regulator_alloc();
196 if (!reg)
197 return -1;
198 t->private = reg;
199
200 /* we skip the root node but we set it expanded for its children */
201 if (!t->parent)
202 return 0;
203
204 return read_regulator_cb(t, data);
205}
206
207static int fill_regulator_tree(void)
208{
209 return tree_for_each(reg_tree, fill_regulator_cb, NULL);
210}
211
212int regulator_init(void)
213{
214 reg_tree = tree_load(SYSFS_REGULATOR, regulator_filter_cb);
215 if (!reg_tree)
216 return -1;
217
218 return fill_regulator_tree();
219}