[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