diff options
-rw-r--r-- | Documentation/devicetree/bindings/mfd/palmas.txt | 52 | ||||
-rw-r--r-- | drivers/mfd/palmas.c | 133 |
2 files changed, 146 insertions, 39 deletions
diff --git a/Documentation/devicetree/bindings/mfd/palmas.txt b/Documentation/devicetree/bindings/mfd/palmas.txt new file mode 100644 index 000000000000..c9f157f9f67a --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/palmas.txt @@ -0,0 +1,52 @@ +* palmas device tree bindings + +The TI palmas family current members :- +twl6035 (palmas) +twl6037 (palmas) +tps65913 (palmas) +tps65914 (palmas) +tps659038 +tps80036 + +Required properties: +- compatible : Should be from the list + ti,twl6035 + ti,twl6036 + ti,twl6037 + ti,tps65913 + ti,tps65914 + ti,tps80036 + ti,tps659038 +and also the generic series names + ti,palmas +- interrupt-controller : palmas has its own internal IRQs +- #interrupt-cells : should be set to 2 for IRQ number and flags + The first cell is the IRQ number. + The second cell is the flags, encoded as the trigger masks from + Documentation/devicetree/bindings/interrupts.txt +- interrupt-parent : The parent interrupt controller. + +Optional properties: + ti,mux-padX : set the pad register X (1-2) to the correct muxing for the + hardware, if not set will use muxing in OTP. + +Example: + +palmas { + compatible = "ti,twl6035", "ti,palmas"; + reg = <0x48> + interrupt-parent = <&intc>; + interrupt-controller; + #interrupt-cells = <2>; + + ti,mux-pad1 = <0>; + ti,mux-pad2 = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + pmic { + compatible = "ti,twl6035-pmic", "ti,palmas-pmic"; + .... + }; +} diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index 342098a7ed0e..ab235c8360e5 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -25,6 +25,8 @@ #include <linux/err.h> #include <linux/mfd/core.h> #include <linux/mfd/palmas.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/of_platform.h> #define EXT_PWR_REQ (PALMAS_EXT_CONTROL_ENABLE1 | \ @@ -1038,6 +1040,37 @@ static int palmas_read_version_information(struct palmas *palmas) return 0; } +static int palmas_set_pdata_irq_flag(struct i2c_client *i2c, + struct palmas_platform_data *pdata) +{ + struct irq_data *irq_data = irq_get_irq_data(i2c->irq); + if (!irq_data) { + dev_err(&i2c->dev, "Invalid IRQ: %d\n", i2c->irq); + return -EINVAL; + } + + pdata->irq_type = irqd_get_trigger_type(irq_data); + dev_info(&i2c->dev, "Irq flag is 0x%08x\n", pdata->irq_type); + return 0; +} + +static void palmas_dt_to_pdata(struct i2c_client *i2c, + struct palmas_platform_data *pdata) +{ + if (i2c->irq) + palmas_set_pdata_irq_flag(i2c, pdata); +} + +static const struct of_device_id of_palmas_match_tbl[] = { + { .compatible = "ti,palmas", .data = (void *)PALMAS, }, + { .compatible = "ti,tps80036", .data = (void *)TPS80036, }, + { .compatible = "ti,twl6035", .data = (void *)TWL6035, }, + { .compatible = "ti,twl6037", .data = (void *)TWL6037, }, + { .compatible = "ti,tps65913", .data = (void *)TPS65913, }, + { }, +}; +MODULE_DEVICE_TABLE(of, of_palmas_match_tbl); + static int palmas_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1049,6 +1082,7 @@ static int palmas_i2c_probe(struct i2c_client *i2c, int slave; struct mfd_cell *children; int child_count; + const struct of_device_id *match; pdata = dev_get_platdata(&i2c->dev); @@ -1070,10 +1104,20 @@ static int palmas_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, palmas); palmas->dev = &i2c->dev; - palmas->id = id->driver_data; - palmas->submodule_lists = submodule_lists[palmas->id]; palmas->irq = i2c->irq; + if (node) { + match = of_match_device(of_match_ptr(of_palmas_match_tbl), + &i2c->dev); + if (!match) + return -ENODATA; + palmas->id = (unsigned int)match->data; + } else { + palmas->id = id->driver_data; + } + + palmas->submodule_lists = submodule_lists[palmas->id]; + for (i = 0; i < PALMAS_NUM_CLIENTS; i++) { if (i == 0) palmas->i2c_clients[i] = i2c; @@ -1087,7 +1131,8 @@ static int palmas_i2c_probe(struct i2c_client *i2c, ret = -ENOMEM; goto free_i2c_client; } - palmas->i2c_clients[i]->dev.of_node = of_node_get(node); + if (node) + palmas->i2c_clients[i]->dev.of_node = of_node_get(node); } palmas->regmap[i] = devm_regmap_init_i2c(palmas->i2c_clients[i], &palmas_regmap_config[i]); @@ -1179,50 +1224,63 @@ static int palmas_i2c_probe(struct i2c_client *i2c, palmas_clk32k_init(palmas, pdata); - children = kzalloc(sizeof(*children) * ARRAY_SIZE(palmas_children), - GFP_KERNEL); - if (!children) { - ret = -ENOMEM; - goto free_irq; - } + /* + * If we are probing with DT do this the DT way and return here + * otherwise continue and add devices using mfd helpers. + */ + if (node) { + ret = of_platform_populate(node, NULL, NULL, &i2c->dev); + if (ret < 0) { + dev_err(palmas->dev, + "Couldn't populate Palmas devices, %d\n", ret); + goto free_irq; + } + } else { + children = kzalloc(sizeof(*children) * ARRAY_SIZE(palmas_children), + GFP_KERNEL); + if (!children) { + ret = -ENOMEM; + goto free_irq; + } - child_count = 0; - for (i = 0; i< ARRAY_SIZE(palmas_children); ++i) { - if (palmas->submodule_lists & BIT(palmas_children[i].id)) - children[child_count++] = palmas_children[i]; - } + child_count = 0; + for (i = 0; i< ARRAY_SIZE(palmas_children); ++i) { + if (palmas->submodule_lists & BIT(palmas_children[i].id)) + children[child_count++] = palmas_children[i]; + } - children[PALMAS_PMIC_ID].platform_data = pdata->pmic_pdata; - children[PALMAS_PMIC_ID].pdata_size = sizeof(*pdata->pmic_pdata); + children[PALMAS_PMIC_ID].platform_data = pdata->pmic_pdata; + children[PALMAS_PMIC_ID].pdata_size = sizeof(*pdata->pmic_pdata); - children[PALMAS_GPADC_ID].platform_data = pdata->gpadc_pdata; - children[PALMAS_GPADC_ID].pdata_size = sizeof(*pdata->gpadc_pdata); + children[PALMAS_GPADC_ID].platform_data = pdata->gpadc_pdata; + children[PALMAS_GPADC_ID].pdata_size = sizeof(*pdata->gpadc_pdata); - children[PALMAS_RESOURCE_ID].platform_data = pdata->resource_pdata; - children[PALMAS_RESOURCE_ID].pdata_size = - sizeof(*pdata->resource_pdata); + children[PALMAS_RESOURCE_ID].platform_data = pdata->resource_pdata; + children[PALMAS_RESOURCE_ID].pdata_size = + sizeof(*pdata->resource_pdata); - children[PALMAS_USB_ID].platform_data = pdata->usb_pdata; - children[PALMAS_USB_ID].pdata_size = sizeof(*pdata->usb_pdata); + children[PALMAS_USB_ID].platform_data = pdata->usb_pdata; + children[PALMAS_USB_ID].pdata_size = sizeof(*pdata->usb_pdata); - children[PALMAS_CLK_ID].platform_data = pdata->clk_pdata; - children[PALMAS_CLK_ID].pdata_size = sizeof(*pdata->clk_pdata); + children[PALMAS_CLK_ID].platform_data = pdata->clk_pdata; + children[PALMAS_CLK_ID].pdata_size = sizeof(*pdata->clk_pdata); - ret = mfd_add_devices(palmas->dev, -1, - children, child_count, - NULL, palmas->irq_chip_data->irq_base, - NULL); - kfree(children); + ret = mfd_add_devices(palmas->dev, -1, + children, child_count, + NULL, palmas->irq_chip_data->irq_base, + palmas->irq_chip_data->domain); + kfree(children); - if (ret < 0) - goto free_irq; + if (ret < 0) + goto free_irq; + } if (pdata->auto_ldousb_en) /* VBUS detection enables the LDOUSB */ palmas_control_update(palmas, PALMAS_EXT_CHRG_CTRL, 1, PALMAS_EXT_CHRG_CTRL_AUTO_LDOUSB_EN); - return ret; + return 0; free_irq: palmas_del_irq_chip(palmas->irq, palmas->irq_chip_data); @@ -1239,7 +1297,9 @@ static int palmas_i2c_remove(struct i2c_client *i2c) struct palmas *palmas = i2c_get_clientdata(i2c); int i; - mfd_remove_devices(palmas->dev); + if (!i2c->dev.of_node) + mfd_remove_devices(palmas->dev); + palmas_del_irq_chip(palmas->irq, palmas->irq_chip_data); for (i = 1; i < PALMAS_NUM_CLIENTS; i++) { @@ -1260,11 +1320,6 @@ static const struct i2c_device_id palmas_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, palmas_i2c_id); -static struct of_device_id of_palmas_match_tbl[] = { - { .compatible = "ti,palmas", }, - { /* end */ } -}; - static struct i2c_driver palmas_i2c_driver = { .driver = { .name = "palmas", |