[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