summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/regulator/core.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index cc242aa368ef..5aae1bd61151 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -3954,6 +3954,124 @@ static const struct file_operations supply_map_fops = {
#endif
};
+#ifdef CONFIG_DEBUG_FS
+static void regulator_summary_show_subtree(struct seq_file *s,
+ struct regulator_dev *rdev,
+ int level)
+{
+ struct list_head *list = s->private;
+ struct regulator_dev *child;
+ struct regulation_constraints *c;
+ struct regulator *consumer;
+
+ if (!rdev)
+ return;
+
+ mutex_lock(&rdev->mutex);
+
+ seq_printf(s, "%*s%-*s %3d %4d %6d ",
+ level * 3 + 1, "",
+ 30 - level * 3, rdev_get_name(rdev),
+ rdev->use_count, rdev->open_count, rdev->bypass_count);
+
+ switch (rdev->desc->type) {
+ case REGULATOR_VOLTAGE:
+ seq_printf(s, "%5dmV ",
+ _regulator_get_voltage(rdev) / 1000);
+ break;
+ case REGULATOR_CURRENT:
+ seq_printf(s, "%5dmA ",
+ _regulator_get_current_limit(rdev) / 1000);
+ break;
+ }
+
+ c = rdev->constraints;
+ if (c) {
+ switch (rdev->desc->type) {
+ case REGULATOR_VOLTAGE:
+ seq_printf(s, "%5dmV %5dmV ",
+ c->min_uV / 1000, c->max_uV / 1000);
+ break;
+ case REGULATOR_CURRENT:
+ seq_printf(s, "%5dmA %5dmA ",
+ c->min_uA / 1000, c->max_uA / 1000);
+ break;
+ }
+ }
+
+ seq_puts(s, "\n");
+
+ list_for_each_entry(consumer, &rdev->consumer_list, list) {
+ if (consumer->dev->class == &regulator_class)
+ continue;
+
+ seq_printf(s, "%*s%-*s ",
+ (level + 1) * 3 + 1, "",
+ 30 - (level + 1) * 3, dev_name(consumer->dev));
+
+ switch (rdev->desc->type) {
+ case REGULATOR_VOLTAGE:
+ seq_printf(s, "%29dmV %5dmV",
+ consumer->min_uV / 1000,
+ consumer->max_uV / 1000);
+ break;
+ case REGULATOR_CURRENT:
+ seq_printf(s, "%37dmA",
+ regulator_get_current_limit(consumer) / 1000);
+ break;
+ }
+
+ seq_puts(s, "\n");
+ }
+
+ mutex_unlock(&rdev->mutex);
+
+ list_for_each_entry(child, list, list) {
+ /* handle only non-root regulators supplied by current rdev */
+ if (!child->supply || child->supply->rdev != rdev)
+ continue;
+
+ regulator_summary_show_subtree(s, child, level + 1);
+ }
+}
+
+static int regulator_summary_show(struct seq_file *s, void *data)
+{
+ struct list_head *list = s->private;
+ struct regulator_dev *rdev;
+
+ seq_puts(s, " regulator use open bypass value min max\n");
+ seq_puts(s, "-----------------------------------------------------------------------\n");
+
+ mutex_lock(&regulator_list_mutex);
+
+ list_for_each_entry(rdev, list, list) {
+ if (rdev->supply)
+ continue;
+
+ regulator_summary_show_subtree(s, rdev, 0);
+ }
+
+ mutex_unlock(&regulator_list_mutex);
+
+ return 0;
+}
+
+static int regulator_summary_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, regulator_summary_show, inode->i_private);
+}
+#endif
+
+static const struct file_operations regulator_summary_fops = {
+#ifdef CONFIG_DEBUG_FS
+ .open = regulator_summary_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+#endif
+};
+
static int __init regulator_init(void)
{
int ret;
@@ -3967,6 +4085,9 @@ static int __init regulator_init(void)
debugfs_create_file("supply_map", 0444, debugfs_root, NULL,
&supply_map_fops);
+ debugfs_create_file("regulator_summary", 0444, debugfs_root,
+ &regulator_list, &regulator_summary_fops);
+
regulator_dummy_init();
return ret;