Commit 37e13cec authored by Peter Ujfalusi's avatar Peter Ujfalusi Committed by Samuel Ortiz

mfd: Add support for Device Tree to twl6040

Device tree based probing support for the core twl6040 driver. Child
devices will be created as MFD devices:
- ASoC codec is always created
- Vibra child is only created if the vibra section present in the DT blob.
Signed-off-by: default avatarPeter Ujfalusi <peter.ujfalusi@ti.com>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent 1f01d60e
Texas Instruments TWL6040 family
The TWL6040s are 8-channel high quality low-power audio codecs providing audio
and vibra functionality on OMAP4+ platforms.
They are connected ot the host processor via i2c for commands, McPDM for audio
data and commands.
Required properties:
- compatible : Must be "ti,twl6040";
- reg: must be 0x4b for i2c address
- interrupts: twl6040 has one interrupt line connecteded to the main SoC
- interrupt-parent: The parent interrupt controller
- twl6040,audpwron-gpio: Power on GPIO line for the twl6040
- vio-supply: Regulator for the twl6040 VIO supply
- v2v1-supply: Regulator for the twl6040 V2V1 supply
Optional properties, nodes:
- enable-active-high: To power on the twl6040 during boot.
Vibra functionality
Required properties:
- vddvibl-supply: Regulator for the left vibra motor
- vddvibr-supply: Regulator for the right vibra motor
- vibra { }: Configuration section for vibra parameters containing the following
properties:
- ti,vibldrv-res: Resistance parameter for left driver
- ti,vibrdrv-res: Resistance parameter for right driver
- ti,viblmotor-res: Resistance parameter for left motor
- ti,viblmotor-res: Resistance parameter for right motor
Optional properties within vibra { } section:
- vddvibl_uV: If the vddvibl default voltage need to be changed
- vddvibr_uV: If the vddvibr default voltage need to be changed
Example:
&i2c1 {
twl6040: twl@4b {
compatible = "ti,twl6040";
reg = <0x4b>;
interrupts = <0 119 4>;
interrupt-parent = <&gic>;
twl6040,audpwron-gpio = <&gpio4 31 0>;
vio-supply = <&v1v8>;
v2v1-supply = <&v2v1>;
enable-active-high;
/* regulators for vibra motor */
vddvibl-supply = <&vbat>;
vddvibr-supply = <&vbat>;
vibra {
/* Vibra driver, motor resistance parameters */
ti,vibldrv-res = <8>;
ti,vibrdrv-res = <3>;
ti,viblmotor-res = <10>;
ti,vibrmotor-res = <10>;
};
};
};
...@@ -29,6 +29,10 @@ ...@@ -29,6 +29,10 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/i2c.h> #include <linux/i2c.h>
...@@ -505,11 +509,12 @@ static int __devinit twl6040_probe(struct i2c_client *client, ...@@ -505,11 +509,12 @@ static int __devinit twl6040_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct twl6040_platform_data *pdata = client->dev.platform_data; struct twl6040_platform_data *pdata = client->dev.platform_data;
struct device_node *node = client->dev.of_node;
struct twl6040 *twl6040; struct twl6040 *twl6040;
struct mfd_cell *cell = NULL; struct mfd_cell *cell = NULL;
int irq, ret, children = 0; int irq, ret, children = 0;
if (!pdata) { if (!pdata && !node) {
dev_err(&client->dev, "Platform data is missing\n"); dev_err(&client->dev, "Platform data is missing\n");
return -EINVAL; return -EINVAL;
} }
...@@ -560,9 +565,13 @@ static int __devinit twl6040_probe(struct i2c_client *client, ...@@ -560,9 +565,13 @@ static int __devinit twl6040_probe(struct i2c_client *client,
twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV); twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV);
/* ERRATA: Automatic power-up is not possible in ES1.0 */ /* ERRATA: Automatic power-up is not possible in ES1.0 */
if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0) if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0) {
twl6040->audpwron = pdata->audpwron_gpio; if (pdata)
else twl6040->audpwron = pdata->audpwron_gpio;
else
twl6040->audpwron = of_get_named_gpio(node,
"ti,audpwron-gpio", 0);
} else
twl6040->audpwron = -EINVAL; twl6040->audpwron = -EINVAL;
if (gpio_is_valid(twl6040->audpwron)) { if (gpio_is_valid(twl6040->audpwron)) {
...@@ -602,13 +611,13 @@ static int __devinit twl6040_probe(struct i2c_client *client, ...@@ -602,13 +611,13 @@ static int __devinit twl6040_probe(struct i2c_client *client,
twl6040_codec_rsrc[0].end = irq; twl6040_codec_rsrc[0].end = irq;
cell->resources = twl6040_codec_rsrc; cell->resources = twl6040_codec_rsrc;
cell->num_resources = ARRAY_SIZE(twl6040_codec_rsrc); cell->num_resources = ARRAY_SIZE(twl6040_codec_rsrc);
if (pdata->codec) { if (pdata && pdata->codec) {
cell->platform_data = pdata->codec; cell->platform_data = pdata->codec;
cell->pdata_size = sizeof(*pdata->codec); cell->pdata_size = sizeof(*pdata->codec);
} }
children++; children++;
if (pdata->vibra) { if ((pdata && pdata->vibra) || of_find_node_by_name(node, "vibra")) {
irq = twl6040->irq_base + TWL6040_IRQ_VIB; irq = twl6040->irq_base + TWL6040_IRQ_VIB;
cell = &twl6040->cells[children]; cell = &twl6040->cells[children];
...@@ -618,8 +627,10 @@ static int __devinit twl6040_probe(struct i2c_client *client, ...@@ -618,8 +627,10 @@ static int __devinit twl6040_probe(struct i2c_client *client,
cell->resources = twl6040_vibra_rsrc; cell->resources = twl6040_vibra_rsrc;
cell->num_resources = ARRAY_SIZE(twl6040_vibra_rsrc); cell->num_resources = ARRAY_SIZE(twl6040_vibra_rsrc);
cell->platform_data = pdata->vibra; if (pdata && pdata->vibra) {
cell->pdata_size = sizeof(*pdata->vibra); cell->platform_data = pdata->vibra;
cell->pdata_size = sizeof(*pdata->vibra);
}
children++; children++;
} }
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/of.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
#include <linux/mfd/twl6040.h> #include <linux/mfd/twl6040.h>
...@@ -139,6 +141,7 @@ static irqreturn_t twl6040_irq_thread(int irq, void *data) ...@@ -139,6 +141,7 @@ static irqreturn_t twl6040_irq_thread(int irq, void *data)
int twl6040_irq_init(struct twl6040 *twl6040) int twl6040_irq_init(struct twl6040 *twl6040)
{ {
struct device_node *node = twl6040->dev->of_node;
int i, nr_irqs, irq_base, ret; int i, nr_irqs, irq_base, ret;
u8 val; u8 val;
...@@ -158,6 +161,9 @@ int twl6040_irq_init(struct twl6040 *twl6040) ...@@ -158,6 +161,9 @@ int twl6040_irq_init(struct twl6040 *twl6040)
} }
twl6040->irq_base = irq_base; twl6040->irq_base = irq_base;
irq_domain_add_legacy(node, ARRAY_SIZE(twl6040_irqs), irq_base, 0,
&irq_domain_simple_ops, NULL);
/* Register them with genirq */ /* Register them with genirq */
for (i = irq_base; i < irq_base + nr_irqs; i++) { for (i = irq_base; i < irq_base + nr_irqs; i++) {
irq_set_chip_data(i, twl6040); irq_set_chip_data(i, twl6040);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment