[PATCH] of: add devicetree API for regulator
Haojian Zhuang
haojian.zhuang at marvell.com
Fri Jul 8 06:20:24 EDT 2011
Signed-off-by: Haojian Zhuang <haojian.zhuang at marvell.com>
---
drivers/of/Kconfig | 4 +
drivers/of/Makefile | 1 +
drivers/of/of_regulator.c | 166 ++++++++++++++++++++++++++++++++++++++++++
include/linux/of_regulator.h | 34 +++++++++
4 files changed, 205 insertions(+), 0 deletions(-)
create mode 100644 drivers/of/of_regulator.c
create mode 100644 include/linux/of_regulator.h
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index d06a637..edb6601 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -75,4 +75,8 @@ config OF_PCI
help
OpenFirmware PCI bus accessors
+config OF_REGULATOR
+ def_tristate REGULATOR
+ depends on REGULATOR
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index f7861ed..83ca06f 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_OF_NET) += of_net.o
obj-$(CONFIG_OF_SPI) += of_spi.o
obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_OF_PCI) += of_pci.o
+obj-$(CONFIG_OF_REGULATOR) += of_regulator.o
diff --git a/drivers/of/of_regulator.c b/drivers/of/of_regulator.c
new file mode 100644
index 0000000..d523302
--- /dev/null
+++ b/drivers/of/of_regulator.c
@@ -0,0 +1,166 @@
+/*
+ * OF helpers for the Regulator API
+ *
+ * Copyright (c) 2011 Haojian Zhuang <haojian.zhuang at marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/regulator/machine.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/suspend.h>
+
+static int of_regulator_init_constraints(struct device_node *of_dev,
+ struct regulation_constraints *constraints)
+{
+ const __be32 *p;
+ const char *cp;
+ const char *ops[] = {"voltage", "current", "mode", "status",
+ "drms"};
+ int i, size, len = 0, tmp = 0;
+
+ memset(constraints, 0, sizeof(struct regulation_constraints));
+
+ p = of_get_property(of_dev, "voltages", &size);
+ if (p && size / sizeof(int) == 2) {
+ constraints->min_uV = be32_to_cpu(*p++);
+ constraints->max_uV = be32_to_cpu(*p);
+ }
+ p = of_get_property(of_dev, "currents", &size);
+ if (p && size / sizeof(int) == 2) {
+ constraints->min_uA = be32_to_cpu(*p++);
+ constraints->max_uA = be32_to_cpu(*p);
+ }
+ p = of_get_property(of_dev, "modes-mask", NULL);
+ if (p)
+ constraints->valid_modes_mask = be32_to_cpu(*p);
+ cp = of_get_property(of_dev, "ops-mask", &size);
+ tmp = 0;
+ if (cp && size > 0) {
+ i = 0;
+ do {
+ len = strlen(ops[i]);
+ if (!strncmp(cp, ops[i], len)) {
+ constraints->valid_ops_mask |= 1 << i;
+ /* need to handle '\0' */
+ cp += len + 1;
+ size = size - len - 1;
+ i = 0;
+ } else
+ i++;
+ } while (i < ARRAY_SIZE(ops));
+ if (size > 0)
+ printk(KERN_WARNING "Invalid string:%s\n", cp);
+ }
+ p = of_get_property(of_dev, "input-uV", NULL);
+ if (p)
+ constraints->input_uV = be32_to_cpu(*p);
+ p = of_get_property(of_dev, "state-pm-disk", &size);
+ if (p && size / sizeof(int) == 3) {
+ constraints->state_disk.uV = be32_to_cpu(*p++);
+ constraints->state_disk.mode = be32_to_cpu(*p++);
+ tmp = be32_to_cpu(*p);
+ constraints->state_disk.enabled = (tmp) ? 1 : 0;
+ constraints->state_disk.disabled = (tmp) ? 0 : 1;
+ }
+ p = of_get_property(of_dev, "state-pm-mem", &size);
+ if (p && size / sizeof(int) == 3) {
+ constraints->state_mem.uV = be32_to_cpu(*p++);
+ constraints->state_mem.mode = be32_to_cpu(*p++);
+ tmp = be32_to_cpu(*p);
+ constraints->state_mem.enabled = (tmp) ? 1 : 0;
+ constraints->state_mem.disabled = (tmp) ? 0 : 1;
+ }
+ p = of_get_property(of_dev, "state-pm-standby", &size);
+ if (p && size / sizeof(int) == 3) {
+ constraints->state_standby.uV = be32_to_cpu(*p++);
+ constraints->state_standby.mode = be32_to_cpu(*p++);
+ tmp = be32_to_cpu(*p);
+ constraints->state_standby.enabled = (tmp) ? 1 : 0;
+ constraints->state_standby.disabled = (tmp) ? 0 : 1;
+ }
+ cp = of_get_property(of_dev, "initial-state", &size);
+ if (cp) {
+ if (!strncmp(cp, "pm-suspend-on", size))
+ constraints->initial_state = PM_SUSPEND_ON;
+ if (!strncmp(cp, "pm-suspend-mem", size))
+ constraints->initial_state = PM_SUSPEND_MEM;
+ if (!strncmp(cp, "pm-suspend-standby", size))
+ constraints->initial_state = PM_SUSPEND_STANDBY;
+ }
+ p = of_get_property(of_dev, "initial_mode", NULL);
+ if (p)
+ constraints->initial_mode = be32_to_cpu(*p);
+ p = of_get_property(of_dev, "always-on", NULL);
+ if (p)
+ constraints->always_on = 1;
+ p = of_get_property(of_dev, "boot-on", NULL);
+ if (p)
+ constraints->boot_on = 1;
+ p = of_get_property(of_dev, "apply-uV", NULL);
+ if (p)
+ constraints->apply_uV = 1;
+ return 0;
+}
+
+int of_regulator_init_data(struct device_node *of_dev,
+ struct regulator_init_data *data)
+{
+ struct regulator_consumer_supply *supply;
+ const char *p, *str;
+ int ret, i, size, calc_size, len, count = 0;
+
+ if (of_dev == NULL || data == NULL)
+ return -EINVAL;
+
+ p = of_get_property(of_dev, "device_type", &size);
+ if (p == NULL || strncmp(p, "regulator", size))
+ return -EINVAL;
+
+ ret = of_regulator_init_constraints(of_dev, &data->constraints);
+ if (ret)
+ return ret;
+ p = of_get_property(of_dev, "supply-name", &size);
+ str = p;
+ calc_size = size;
+ while (str && calc_size > 0) {
+ len = strlen(str);
+ if (len == 0)
+ break;
+ calc_size = calc_size - len - 1;
+ str += len + 1;
+ count++;
+ }
+ if (count == 0)
+ return -EINVAL;
+
+ supply = kzalloc(sizeof(struct regulator_consumer_supply) * count,
+ GFP_KERNEL);
+ if (supply == NULL)
+ return -EINVAL;
+ str = p;
+ calc_size = size;
+ i = 0;
+ while (str && calc_size > 0 && i < count) {
+ len = strlen(str);
+ if (len == 0)
+ break;
+ supply[i++].supply = str;
+ calc_size = calc_size - len - 1;
+ str += len + 1;
+ }
+ data->consumer_supplies = supply;
+ data->num_consumer_supplies = count;
+ return 0;
+}
+
+void of_regulator_deinit_data(struct regulator_init_data *data)
+{
+ if (data && data->consumer_supplies)
+ kfree(data->consumer_supplies);
+}
diff --git a/include/linux/of_regulator.h b/include/linux/of_regulator.h
new file mode 100644
index 0000000..0155bd8
--- /dev/null
+++ b/include/linux/of_regulator.h
@@ -0,0 +1,34 @@
+/*
+ * Generic Regulator API implementation
+ *
+ * Copyright (c) 2011 Haojian Zhuang <haojian.zhuang at marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_OF_REGULATOR_H
+#define __LINUX_OF_REGULATOR_H
+
+#if defined(CONFIG_OF_REGULATOR) || defined(CONFIG_OF_REGULATOR_MODULE)
+#include <linux/regulator/machine.h>
+
+extern int of_regulator_init_data(struct device_node *of_node,
+ struct regulator_init_data *data);
+extern void of_regulator_deinit_data(struct regulator_init_data *data);
+
+#else
+static inline int of_regulator_init_data(struct device_node *of_node,
+ struct regulator_init_data *data)
+{
+ return 0;
+}
+
+static inline void of_regulator_deinit_data(struct regulator_init_data *data)
+{
+}
+#endif /* CONFIG_OF_REGULATOR */
+
+#endif /* __LINUX_OF_REGULATOR_H */
--
1.5.6.5
More information about the linux-arm-kernel
mailing list