summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/mfd/palmas.txt52
-rw-r--r--drivers/mfd/palmas.c133
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",