2012-05-16 11:12:10

by Peter Ujfalusi

[permalink] [raw]
Subject: [PATCH v3 0/4] MFD: twl6040: Device tree support

Hello,

Changes since v2:
- Child devices are no longer described in dts, they are created with
mfd_add_devices()
- ASoC codec device is created unconditionally (main function of twl6040)

Changes since v1:
- Commit message for patch 2 (Allocate IRQ numbers dynamically) has been updated
to describe that the twl6040 can not be used as IRQ extender type of device.

Commit message from v1:

The following series adds device tree support for the twl6040 MFD core driver.
Support for the child drivers (vibra, ASoC codec) will be submitted via the
corresponding subsystem since there is no compile time dependency between them.

The first patch is a minor clean up patch to remove wrapped lines in the
twl6040-irq.c. The resulting code is more natural to read to me.

The series depends on the regulator support patch for the twl6040:
http://marc.info/?l=linux-kernel&m=133596703610515&w=2

Regards,
Peter
---
Peter Ujfalusi (4):
MFD: twl6040: Code cleanup in interrupt initialization part
MFD: twl6040: Allocate IRQ numbers dynamically
MFD: twl6040: Register the child for the ASoC codec unconditionally
MFD: twl6040: Add support for Device Tree

Documentation/devicetree/bindings/mfd/twl6040.txt | 62 ++++++++++++++++++
drivers/mfd/twl6040-core.c | 69 ++++++++++++---------
drivers/mfd/twl6040-irq.c | 32 +++++++---
3 files changed, 124 insertions(+), 39 deletions(-)
create mode 100644 Documentation/devicetree/bindings/mfd/twl6040.txt

--
1.7.8.6


2012-05-16 11:12:12

by Peter Ujfalusi

[permalink] [raw]
Subject: [PATCH v3 1/4] MFD: twl6040: Code cleanup in interrupt initialization part

No functional change, just to make the code a bit more uniform and
remove wrapped lines.

Signed-off-by: Peter Ujfalusi <[email protected]>
---
drivers/mfd/twl6040-irq.c | 17 ++++++++---------
1 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/mfd/twl6040-irq.c b/drivers/mfd/twl6040-irq.c
index b3f8dda..008022c 100644
--- a/drivers/mfd/twl6040-irq.c
+++ b/drivers/mfd/twl6040-irq.c
@@ -138,7 +138,7 @@ static irqreturn_t twl6040_irq_thread(int irq, void *data)

int twl6040_irq_init(struct twl6040 *twl6040)
{
- int cur_irq, ret;
+ int i, nr_irqs, ret;
u8 val;

mutex_init(&twl6040->irq_mutex);
@@ -148,21 +148,20 @@ int twl6040_irq_init(struct twl6040 *twl6040)
twl6040->irq_masks_cache = TWL6040_ALLINT_MSK;
twl6040_reg_write(twl6040, TWL6040_REG_INTMR, TWL6040_ALLINT_MSK);

+ nr_irqs = ARRAY_SIZE(twl6040_irqs);
/* Register them with genirq */
- for (cur_irq = twl6040->irq_base;
- cur_irq < twl6040->irq_base + ARRAY_SIZE(twl6040_irqs);
- cur_irq++) {
- irq_set_chip_data(cur_irq, twl6040);
- irq_set_chip_and_handler(cur_irq, &twl6040_irq_chip,
+ for (i = twl6040->irq_base; i < twl6040->irq_base + nr_irqs; i++) {
+ irq_set_chip_data(i, twl6040);
+ irq_set_chip_and_handler(i, &twl6040_irq_chip,
handle_level_irq);
- irq_set_nested_thread(cur_irq, 1);
+ irq_set_nested_thread(i, 1);

/* ARM needs us to explicitly flag the IRQ as valid
* and will set them noprobe when we do so. */
#ifdef CONFIG_ARM
- set_irq_flags(cur_irq, IRQF_VALID);
+ set_irq_flags(i, IRQF_VALID);
#else
- irq_set_noprobe(cur_irq);
+ irq_set_noprobe(i);
#endif
}

--
1.7.8.6

2012-05-16 11:12:59

by Peter Ujfalusi

[permalink] [raw]
Subject: [PATCH v3 3/4] MFD: twl6040: Register the child for the ASoC codec unconditionally

The main function of the twl6040 is to provide audio on OMAP4+ platforms.
Since the ASoC codec driver can work without the pdata we can register the
child to load the codec driver whenever the twl6040 MFD driver is loaded.

Signed-off-by: Peter Ujfalusi <[email protected]>
---
drivers/mfd/twl6040-core.c | 39 +++++++++++++++++++--------------------
1 files changed, 19 insertions(+), 20 deletions(-)

diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c
index c50fba7..9765dc2 100644
--- a/drivers/mfd/twl6040-core.c
+++ b/drivers/mfd/twl6040-core.c
@@ -507,7 +507,7 @@ static int __devinit twl6040_probe(struct i2c_client *client,
struct twl6040_platform_data *pdata = client->dev.platform_data;
struct twl6040 *twl6040;
struct mfd_cell *cell = NULL;
- int ret, children = 0;
+ int irq, ret, children = 0;

if (!pdata) {
dev_err(&client->dev, "Platform data is missing\n");
@@ -589,22 +589,27 @@ static int __devinit twl6040_probe(struct i2c_client *client,
/* dual-access registers controlled by I2C only */
twl6040_set_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_I2CSEL);

+ /*
+ * The main functionality of twl6040 to provide audio on OMAP4+ systems.
+ * We can add the ASoC codec child whenever this driver has been loaded.
+ * The ASoC codec can work without pdata, pass the platform_data only if
+ * it has been provided.
+ */
+ irq = twl6040->irq_base + TWL6040_IRQ_PLUG;
+ cell = &twl6040->cells[children];
+ cell->name = "twl6040-codec";
+ twl6040_codec_rsrc[0].start = irq;
+ twl6040_codec_rsrc[0].end = irq;
+ cell->resources = twl6040_codec_rsrc;
+ cell->num_resources = ARRAY_SIZE(twl6040_codec_rsrc);
if (pdata->codec) {
- int irq = twl6040->irq_base + TWL6040_IRQ_PLUG;
-
- cell = &twl6040->cells[children];
- cell->name = "twl6040-codec";
- twl6040_codec_rsrc[0].start = irq;
- twl6040_codec_rsrc[0].end = irq;
- cell->resources = twl6040_codec_rsrc;
- cell->num_resources = ARRAY_SIZE(twl6040_codec_rsrc);
cell->platform_data = pdata->codec;
cell->pdata_size = sizeof(*pdata->codec);
- children++;
}
+ children++;

if (pdata->vibra) {
- int irq = twl6040->irq_base + TWL6040_IRQ_VIB;
+ irq = twl6040->irq_base + TWL6040_IRQ_VIB;

cell = &twl6040->cells[children];
cell->name = "twl6040-vibra";
@@ -618,16 +623,10 @@ static int __devinit twl6040_probe(struct i2c_client *client,
children++;
}

- if (children) {
- ret = mfd_add_devices(&client->dev, -1, twl6040->cells,
- children, NULL, 0);
- if (ret)
- goto mfd_err;
- } else {
- dev_err(&client->dev, "No platform data found for children\n");
- ret = -ENODEV;
+ ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children,
+ NULL, 0);
+ if (ret)
goto mfd_err;
- }

return 0;

--
1.7.8.6

2012-05-16 11:13:03

by Peter Ujfalusi

[permalink] [raw]
Subject: [PATCH v3 2/4] MFD: twl6040: Allocate IRQ numbers dynamically

Use irq_alloc_descs() to get the IRQ number range dynamically instead of
the hardwired use if pdata->irq_base.
The twl6040 only provides interrupts for it's internal components which
means that it is not working as an IRQ expander type of device.
The client drivers will receive their interrupt numbers as resource which
is configured based on the received IRQ range we got from irq_alloc_descs()

Signed-off-by: Peter Ujfalusi <[email protected]>
---
drivers/mfd/twl6040-core.c | 3 +--
drivers/mfd/twl6040-irq.c | 13 +++++++++++--
2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c
index 7a92d95..c50fba7 100644
--- a/drivers/mfd/twl6040-core.c
+++ b/drivers/mfd/twl6040-core.c
@@ -515,7 +515,7 @@ static int __devinit twl6040_probe(struct i2c_client *client,
}

/* In order to operate correctly we need valid interrupt config */
- if (!client->irq || !pdata->irq_base) {
+ if (!client->irq) {
dev_err(&client->dev, "Invalid IRQ configuration\n");
return -EINVAL;
}
@@ -552,7 +552,6 @@ static int __devinit twl6040_probe(struct i2c_client *client,

twl6040->dev = &client->dev;
twl6040->irq = client->irq;
- twl6040->irq_base = pdata->irq_base;

mutex_init(&twl6040->mutex);
mutex_init(&twl6040->io_mutex);
diff --git a/drivers/mfd/twl6040-irq.c b/drivers/mfd/twl6040-irq.c
index 008022c..914978e 100644
--- a/drivers/mfd/twl6040-irq.c
+++ b/drivers/mfd/twl6040-irq.c
@@ -23,6 +23,7 @@

#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/err.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/mfd/core.h>
@@ -138,7 +139,7 @@ static irqreturn_t twl6040_irq_thread(int irq, void *data)

int twl6040_irq_init(struct twl6040 *twl6040)
{
- int i, nr_irqs, ret;
+ int i, nr_irqs, irq_base, ret;
u8 val;

mutex_init(&twl6040->irq_mutex);
@@ -149,8 +150,16 @@ int twl6040_irq_init(struct twl6040 *twl6040)
twl6040_reg_write(twl6040, TWL6040_REG_INTMR, TWL6040_ALLINT_MSK);

nr_irqs = ARRAY_SIZE(twl6040_irqs);
+
+ irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+ if (IS_ERR_VALUE(irq_base)) {
+ dev_err(twl6040->dev, "Fail to allocate IRQ descs\n");
+ return irq_base;
+ }
+ twl6040->irq_base = irq_base;
+
/* Register them with genirq */
- for (i = twl6040->irq_base; i < twl6040->irq_base + nr_irqs; i++) {
+ for (i = irq_base; i < irq_base + nr_irqs; i++) {
irq_set_chip_data(i, twl6040);
irq_set_chip_and_handler(i, &twl6040_irq_chip,
handle_level_irq);
--
1.7.8.6

2012-05-16 11:18:57

by Peter Ujfalusi

[permalink] [raw]
Subject: [PATCH v3 4/4] MFD: twl6040: Add support for Device Tree

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: Peter Ujfalusi <[email protected]>
---
Documentation/devicetree/bindings/mfd/twl6040.txt | 62 +++++++++++++++++++++
drivers/mfd/twl6040-core.c | 27 ++++++---
drivers/mfd/twl6040-irq.c | 6 ++
3 files changed, 87 insertions(+), 8 deletions(-)
create mode 100644 Documentation/devicetree/bindings/mfd/twl6040.txt

diff --git a/Documentation/devicetree/bindings/mfd/twl6040.txt b/Documentation/devicetree/bindings/mfd/twl6040.txt
new file mode 100644
index 0000000..bc67c6f
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/twl6040.txt
@@ -0,0 +1,62 @@
+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>;
+ };
+ };
+};
diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c
index 9765dc2..450a28f 100644
--- a/drivers/mfd/twl6040-core.c
+++ b/drivers/mfd/twl6040-core.c
@@ -29,6 +29,10 @@
#include <linux/kernel.h>
#include <linux/err.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/delay.h>
#include <linux/i2c.h>
@@ -505,11 +509,12 @@ static int __devinit twl6040_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct twl6040_platform_data *pdata = client->dev.platform_data;
+ struct device_node *node = client->dev.of_node;
struct twl6040 *twl6040;
struct mfd_cell *cell = NULL;
int irq, ret, children = 0;

- if (!pdata) {
+ if (!pdata && !node) {
dev_err(&client->dev, "Platform data is missing\n");
return -EINVAL;
}
@@ -560,9 +565,13 @@ static int __devinit twl6040_probe(struct i2c_client *client,
twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV);

/* ERRATA: Automatic power-up is not possible in ES1.0 */
- if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0)
- twl6040->audpwron = pdata->audpwron_gpio;
- else
+ if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0) {
+ if (pdata)
+ twl6040->audpwron = pdata->audpwron_gpio;
+ else
+ twl6040->audpwron = of_get_named_gpio(node,
+ "ti,audpwron-gpio", 0);
+ } else
twl6040->audpwron = -EINVAL;

if (gpio_is_valid(twl6040->audpwron)) {
@@ -602,13 +611,13 @@ static int __devinit twl6040_probe(struct i2c_client *client,
twl6040_codec_rsrc[0].end = irq;
cell->resources = twl6040_codec_rsrc;
cell->num_resources = ARRAY_SIZE(twl6040_codec_rsrc);
- if (pdata->codec) {
+ if (pdata && pdata->codec) {
cell->platform_data = pdata->codec;
cell->pdata_size = sizeof(*pdata->codec);
}
children++;

- if (pdata->vibra) {
+ if ((pdata && pdata->vibra) || of_find_node_by_name(node, "vibra")) {
irq = twl6040->irq_base + TWL6040_IRQ_VIB;

cell = &twl6040->cells[children];
@@ -618,8 +627,10 @@ static int __devinit twl6040_probe(struct i2c_client *client,
cell->resources = twl6040_vibra_rsrc;
cell->num_resources = ARRAY_SIZE(twl6040_vibra_rsrc);

- cell->platform_data = pdata->vibra;
- cell->pdata_size = sizeof(*pdata->vibra);
+ if (pdata && pdata->vibra) {
+ cell->platform_data = pdata->vibra;
+ cell->pdata_size = sizeof(*pdata->vibra);
+ }
children++;
}

diff --git a/drivers/mfd/twl6040-irq.c b/drivers/mfd/twl6040-irq.c
index 914978e..4b42543 100644
--- a/drivers/mfd/twl6040-irq.c
+++ b/drivers/mfd/twl6040-irq.c
@@ -25,6 +25,8 @@
#include <linux/module.h>
#include <linux/err.h>
#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/mfd/core.h>
#include <linux/mfd/twl6040.h>
@@ -139,6 +141,7 @@ static irqreturn_t twl6040_irq_thread(int irq, void *data)

int twl6040_irq_init(struct twl6040 *twl6040)
{
+ struct device_node *node = twl6040->dev->of_node;
int i, nr_irqs, irq_base, ret;
u8 val;

@@ -158,6 +161,9 @@ int twl6040_irq_init(struct twl6040 *twl6040)
}
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 */
for (i = irq_base; i < irq_base + nr_irqs; i++) {
irq_set_chip_data(i, twl6040);
--
1.7.8.6

2012-05-19 15:22:43

by Samuel Ortiz

[permalink] [raw]
Subject: Re: [PATCH v3 0/4] MFD: twl6040: Device tree support

Hi Peter,

On Wed, May 16, 2012 at 02:11:54PM +0300, Peter Ujfalusi wrote:
> Hello,
>
> Changes since v2:
> - Child devices are no longer described in dts, they are created with
> mfd_add_devices()
> - ASoC codec device is created unconditionally (main function of twl6040)
>
> Changes since v1:
> - Commit message for patch 2 (Allocate IRQ numbers dynamically) has been updated
> to describe that the twl6040 can not be used as IRQ extender type of device.
>
> Commit message from v1:
>
> The following series adds device tree support for the twl6040 MFD core driver.
> Support for the child drivers (vibra, ASoC codec) will be submitted via the
> corresponding subsystem since there is no compile time dependency between them.
>
> The first patch is a minor clean up patch to remove wrapped lines in the
> twl6040-irq.c. The resulting code is more natural to read to me.
>
> The series depends on the regulator support patch for the twl6040:
> http://marc.info/?l=linux-kernel&m=133596703610515&w=2
All 4 patches applied, thanks.

Cheers,
Samuel.

--
Intel Open Source Technology Centre
http://oss.intel.com/