blob: 0da924a77309e4f633d1fc82e7763fc7e398e1a1 [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 Lezcano15627482011-06-15 15:45:12 +020021#define VALUE_MAX 16
22
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020023#define _GNU_SOURCE
24#include <stdio.h>
25#undef _GNU_SOURCE
26#include <sys/types.h>
27#include <stdbool.h>
28#include <dirent.h>
29#include <string.h>
30#include <stdlib.h>
Daniel Lezcanob301b082011-06-15 15:45:12 +020031#include "display.h"
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020032#include "powerdebug.h"
33#include "tree.h"
34#include "utils.h"
Daniel Lezcano2e6ecca2011-03-26 22:05:51 +010035
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020036struct regulator_info {
37 char name[NAME_MAX];
38 char state[VALUE_MAX];
39 char status[VALUE_MAX];
40 char type[VALUE_MAX];
41 char opmode[VALUE_MAX];
42 int microvolts;
43 int min_microvolts;
44 int max_microvolts;
45 int microamps;
46 int min_microamps;
47 int max_microamps;
48 int requested_microamps;
49 int num_users;
50};
51
52struct regulator_data {
53 const char *name;
54 const char *ifmt;
55 const char *ofmt;
56 bool derefme;
57};
58
59static struct regulator_data regdata[] = {
60 { "name", "%s", "\tname: %s\n" },
61 { "status", "%s", "\tstatus: %s\n" },
62 { "state", "%s", "\tstate: %s\n" },
63 { "type", "%s", "\ttype: %s\n" },
64 { "num_users", "%d", "\tnum_users: %d\n", true },
65 { "microvolts", "%d", "\tmicrovolts: %d\n", true },
66 { "max_microvolts", "%d", "\tmax_microvolts: %d\n", true },
67 { "min_microvolts", "%d", "\tmin_microvolts: %d\n", true },
68};
69
70static struct tree *reg_tree;
71
72static struct regulator_info *regulator_alloc(void)
Amit Arora17552782010-12-02 12:23:14 +053073{
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020074 struct regulator_info *regi;
Amit Arora17552782010-12-02 12:23:14 +053075
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020076 regi = malloc(sizeof(*regi));
77 if (regi)
78 memset(regi, 0, sizeof(*regi));
Daniel Lezcano4aab2fe2011-03-26 22:05:53 +010079
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020080 return regi;
Amit Arora17552782010-12-02 12:23:14 +053081}
82
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020083static int regulator_dump_cb(struct tree *tree, void *data)
Amit Arora17552782010-12-02 12:23:14 +053084{
85 int i;
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020086 char buffer[NAME_MAX];
87 size_t nregdata = sizeof(regdata) / sizeof(regdata[0]);
Amit Arora17552782010-12-02 12:23:14 +053088
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020089 if (!strncmp("regulator.", tree->name, strlen("regulator.")))
90 printf("\n%s:\n", tree->name);
91
92 for (i = 0; i < nregdata; i++) {
Sanjay Singh Rawat9fe0c052013-02-22 17:57:18 +053093 int val;
Daniel Lezcanob25be4a2011-06-15 15:45:12 +020094
95 if (file_read_value(tree->path, regdata[i].name,
96 regdata[i].ifmt, buffer))
97 continue;
98
Sanjay Singh Rawat9fe0c052013-02-22 17:57:18 +053099 if (regdata[i].derefme) {
100 val = atoi(buffer);
101 printf(regdata[i].ofmt, val);
102 } else
103 printf(regdata[i].ofmt, buffer);
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200104 }
105
106 return 0;
107}
108
109int regulator_dump(void)
110{
Amit Arora422c52f2010-12-02 16:22:29 +0530111 printf("\nRegulator Information:\n");
112 printf("*********************\n\n");
113
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200114 return tree_for_each(reg_tree, regulator_dump_cb, NULL);
Amit Arora17552782010-12-02 12:23:14 +0530115}
116
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200117static int regulator_display_cb(struct tree *t, void *data)
Amit Arora17552782010-12-02 12:23:14 +0530118{
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200119 struct regulator_info *reg = t->private;
120 int *line = data;
121 char *buf;
Amit Arora17552782010-12-02 12:23:14 +0530122
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200123 /* we skip the root node of the tree */
124 if (!t->parent)
125 return 0;
Amit Arora17552782010-12-02 12:23:14 +0530126
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200127 if (!strlen(reg->name))
128 return 0;
Amit Arora17552782010-12-02 12:23:14 +0530129
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200130 if (asprintf(&buf, "%-11s %-11s %-11s %-11s %-11d %-11d %-11d %-12d",
131 reg->name, reg->status, reg->state, reg->type,
132 reg->num_users, reg->microvolts, reg->min_microvolts,
133 reg->max_microvolts) < 0)
134 return -1;
Amit Arora17552782010-12-02 12:23:14 +0530135
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200136 display_print_line(REGULATOR, *line, buf, reg->num_users, t);
137
138 (*line)++;
139
140 free(buf);
141
142 return 0;
Amit Arora17552782010-12-02 12:23:14 +0530143}
144
Daniel Lezcanofa453332011-06-21 00:57:08 +0200145static int regulator_print_header(void)
146{
147 char *buf;
148 int ret;
149
150 if (asprintf(&buf, "%-11s %-11s %-11s %-11s %-11s %-11s %-11s %-12s",
151 "Name", "Status", "State", "Type", "Users", "Microvolts",
152 "Min u-volts", "Max u-volts") < 0)
153 return -1;
154
Daniel Lezcano372ffba2011-06-21 00:57:08 +0200155 ret = display_column_name(buf);
Daniel Lezcanofa453332011-06-21 00:57:08 +0200156
157 free(buf);
158
159 return ret;
160
161}
162
Daniel Lezcanod577aaa2011-06-21 00:57:08 +0200163static int regulator_display(bool refresh)
Amit Arora17552782010-12-02 12:23:14 +0530164{
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200165 int ret, line = 0;
Amit Arora17552782010-12-02 12:23:14 +0530166
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200167 display_reset_cursor(REGULATOR);
Amit Arora17552782010-12-02 12:23:14 +0530168
Daniel Lezcanofa453332011-06-21 00:57:08 +0200169 regulator_print_header();
Amit Arora17552782010-12-02 12:23:14 +0530170
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200171 ret = tree_for_each(reg_tree, regulator_display_cb, &line);
Amit Arora17552782010-12-02 12:23:14 +0530172
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200173 display_refresh_pad(REGULATOR);
Amit Arora17552782010-12-02 12:23:14 +0530174
175 return ret;
176}
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200177
178static int regulator_filter_cb(const char *name)
179{
180 /* let's ignore some directories in order to avoid to be
181 * pulled inside the sysfs circular symlinks mess/hell
182 * (choose the word which fit better)
183 */
184 if (!strcmp(name, "device"))
185 return 1;
186
187 if (!strcmp(name, "subsystem"))
188 return 1;
189
190 if (!strcmp(name, "driver"))
191 return 1;
192
193 return 0;
194}
195
196static inline int read_regulator_cb(struct tree *t, void *data)
197{
198 struct regulator_info *reg = t->private;
199
200 file_read_value(t->path, "name", "%s", reg->name);
201 file_read_value(t->path, "state", "%s", reg->state);
202 file_read_value(t->path, "status", "%s", reg->status);
203 file_read_value(t->path, "type", "%s", reg->type);
204 file_read_value(t->path, "opmode", "%s", reg->opmode);
205 file_read_value(t->path, "num_users", "%d", &reg->num_users);
206 file_read_value(t->path, "microvolts", "%d", &reg->microvolts);
207 file_read_value(t->path, "min_microvolts", "%d", &reg->min_microvolts);
208 file_read_value(t->path, "max_microvolts", "%d", &reg->max_microvolts);
209 file_read_value(t->path, "microamps", "%d", &reg->microamps);
210 file_read_value(t->path, "min_microamps", "%d", &reg->min_microamps);
211 file_read_value(t->path, "max_microamps", "%d", &reg->max_microamps);
212
213 return 0;
214}
215
216static int fill_regulator_cb(struct tree *t, void *data)
217{
218 struct regulator_info *reg;
219
220 reg = regulator_alloc();
221 if (!reg)
222 return -1;
223 t->private = reg;
224
225 /* we skip the root node but we set it expanded for its children */
226 if (!t->parent)
227 return 0;
228
229 return read_regulator_cb(t, data);
230}
231
232static int fill_regulator_tree(void)
233{
234 return tree_for_each(reg_tree, fill_regulator_cb, NULL);
235}
236
Daniel Lezcanob301b082011-06-15 15:45:12 +0200237static struct display_ops regulator_ops = {
238 .display = regulator_display,
239};
240
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200241int regulator_init(void)
242{
Daniel Lezcano25fc4a32011-08-25 15:46:13 +0200243 reg_tree = tree_load(SYSFS_REGULATOR, regulator_filter_cb, false);
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200244 if (!reg_tree)
245 return -1;
246
Daniel Lezcanocaafece2011-06-27 22:59:17 +0200247 if (fill_regulator_tree())
248 return -1;
249
250 return display_register(REGULATOR, &regulator_ops);
Daniel Lezcanob25be4a2011-06-15 15:45:12 +0200251}