[PATCH] mfd: convert devicetree to platform data on max8925

Haojian Zhuang haojian.zhuang at marvell.com
Fri Jul 8 06:20:26 EDT 2011


Make max8925 to support both platform data and device tree. So a translation
between device tree and platform data is added.

Signed-off-by: Haojian Zhuang <haojian.zhuang at marvell.com>
---
 drivers/mfd/max8925-i2c.c |  159 ++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 157 insertions(+), 2 deletions(-)

diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c
index 0219115..fb74554 100644
--- a/drivers/mfd/max8925-i2c.c
+++ b/drivers/mfd/max8925-i2c.c
@@ -10,6 +10,9 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/of_regulator.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
 #include <linux/mfd/max8925.h>
@@ -135,6 +138,154 @@ static const struct i2c_device_id max8925_id_table[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max8925_id_table);
 
+#ifdef CONFIG_OF
+static int __devinit max8925_parse_irq(struct i2c_client *i2c,
+					struct max8925_platform_data *pdata)
+{
+	struct device_node *of_node = i2c->dev.of_node;
+
+	pdata->irq_base = irq_alloc_descs(-1, 0, MAX8925_NR_IRQS, 0);
+	irq_domain_add_simple(of_node, pdata->irq_base);
+	return 0;
+}
+
+static void __devinit max8925_parse_backlight(struct device_node *np,
+					struct max8925_platform_data *pdata)
+{
+	struct max8925_backlight_pdata *bk;
+	const __be32 *p;
+
+	bk = kzalloc(sizeof(struct max8925_backlight_pdata), GFP_KERNEL);
+	if (bk == NULL)
+		return;
+	pdata->backlight = bk;
+	p = of_get_property(np, "lxw-scl", NULL);
+	if (p)
+		bk->lxw_scl = be32_to_cpu(*p);
+	p = of_get_property(np, "lxw-freq", NULL);
+	if (p)
+		bk->lxw_freq = be32_to_cpu(*p);
+	p = of_get_property(np, "dual-string", NULL);
+	if (p)
+		bk->dual_string = be32_to_cpu(*p);
+}
+
+static void __devinit max8925_parse_touch(struct device_node *np,
+					struct max8925_platform_data *pdata)
+{
+	struct max8925_touch_pdata *touch;
+	const __be32 *p;
+
+	touch = kzalloc(sizeof(struct max8925_touch_pdata), GFP_KERNEL);
+	if (touch == NULL)
+		return;
+	pdata->touch = touch;
+	p = of_get_property(np, "flags", NULL);
+	if (p)
+		touch->flags = be32_to_cpu(*p);
+	p = of_get_property(np, "interrupts", NULL);
+	if (p)
+		pdata->tsc_irq = irq_of_parse_and_map(np, 0);
+}
+
+static void __devinit max8925_parse_power(struct device_node *np,
+					struct max8925_platform_data *pdata)
+{
+	struct max8925_power_pdata *power;
+	const __be32 *p;
+
+	power = kzalloc(sizeof(struct max8925_power_pdata), GFP_KERNEL);
+	if (power == NULL)
+		return;
+	pdata->power = power;
+	p = of_get_property(np, "battery-detect", NULL);
+	if (p)
+		power->batt_detect = be32_to_cpu(*p) ? 1 : 0;
+	p = of_get_property(np, "topoff-threshold", NULL);
+	if (p)
+		power->topoff_threshold = be32_to_cpu(*p) & 0x3;
+	p = of_get_property(np, "fast-charge", NULL);
+	if (p)
+		power->fast_charge = be32_to_cpu(*p) & 0x7;
+}
+
+static void __devinit max8925_parse_regulator(struct device_node *np,
+					struct max8925_platform_data *pdata)
+{
+	const char *name[MAX8925_MAX_REGULATOR] = {
+			"SD1", "SD2", "SD3", "LDO1", "LDO2", "LDO3", "LDO4",
+			"LDO5", "LDO6", "LDO7", "LDO8", "LDO9", "LDO10",
+			"LDO11", "LDO12", "LDO13", "LDO14", "LDO15", "LDO16",
+			"LDO17", "LDO18", "LDO19", "LDO20"};
+	const char *cp;
+	int i;
+
+	cp = of_get_property(np, "compatible", NULL);
+	if (cp == NULL)
+		return;
+	for (i = 0; i < MAX8925_MAX_REGULATOR; i++) {
+		if (strncmp(cp, name[i], strlen(name[i])))
+			continue;
+		of_regulator_init_data(np, pdata->regulator[i]);
+		break;
+	}
+}
+
+static struct max8925_platform_data __devinit
+*max8925_get_alt_pdata(struct i2c_client *client)
+{
+	struct max8925_platform_data *pdata;
+	struct device_node *of_node = client->dev.of_node;
+	struct device_node *np, *pp = NULL;
+	const char *cp;
+	int ret, i;
+
+	pdata = kzalloc(sizeof(struct max8925_platform_data), GFP_KERNEL);
+	if (pdata == NULL)
+		return NULL;
+	pdata->regulator[0] = kzalloc(sizeof(struct regulator_init_data)
+			* MAX8925_MAX_REGULATOR, GFP_KERNEL);
+	if (pdata->regulator[0] == NULL) {
+		kfree(pdata);
+		return NULL;
+	}
+	for (i = 1; i < MAX8925_MAX_REGULATOR; i++)
+		pdata->regulator[i] = pdata->regulator[i - 1] + 1;
+
+	ret = max8925_parse_irq(client, pdata);
+	if (ret < 0)
+		goto out;
+
+	for (; (np = of_get_next_child(of_node, pp)) != NULL; pp = np) {
+		cp = of_get_property(np, "compatible", NULL);
+		if (cp == NULL)
+			continue;
+		if (!strncmp(cp, "backlight", strlen("backlight")))
+			max8925_parse_backlight(np, pdata);
+		if (!strncmp(cp, "power", strlen("power")))
+			max8925_parse_power(np, pdata);
+		if (!strncmp(cp, "touch", strlen("touch")))
+			max8925_parse_touch(np, pdata);
+		cp = of_get_property(np, "device_type", NULL);
+		if (cp == NULL)
+			continue;
+		if (!strncmp(cp, "regulator", strlen("regulator")))
+			max8925_parse_regulator(np, pdata);
+	}
+	return pdata;
+out:
+	kfree(pdata->regulator[0]);
+	kfree(pdata);
+	return NULL;
+}
+#else
+static struct max8925_platform_data __devinit
+*max8925_get_alt_pdata(struct i2c_client *client)
+{
+	return NULL;
+}
+#endif
+
 static int __devinit max8925_probe(struct i2c_client *client,
 				   const struct i2c_device_id *id)
 {
@@ -142,8 +293,12 @@ static int __devinit max8925_probe(struct i2c_client *client,
 	static struct max8925_chip *chip;
 
 	if (!pdata) {
-		pr_info("%s: platform data is missing\n", __func__);
-		return -EINVAL;
+		pdata = max8925_get_alt_pdata(client);
+		if (!pdata) {
+			pr_info("%s: platform data is missing\n", __func__);
+			return -EINVAL;
+		}
+		client->dev.platform_data = pdata;
 	}
 
 	chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL);
-- 
1.5.6.5




More information about the linux-arm-kernel mailing list