Skip to content

Commit

Permalink
mfd: twl-core: Add initial DT support for twl4030/twl6030
Browse files Browse the repository at this point in the history
Add initial device-tree support for twl familly chips.
The current version is missing the regulator entries due
to the lack of DT regulator bindings for the moment.
Only the simple sub-modules that do not depend on
platform_data information can be initialized properly.

Add irqdomain support.

Add documentation for the Texas Instruments TWL Integrated Chip.

Signed-off-by: Benoit Cousson <b-cousson@ti.com>
Cc: Balaji T K <balajitk@ti.com>
Cc: Graeme Gregory <gg@slimlogic.co.uk>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Acked-by: Rob Herring <rob.herring@calxeda.com>
[grant.likely@secretlab.ca: Fix IRQ_DOMAIN dependency in kconfig]
Cc: Grant Likely <grant.likely@secretlab.ca>
  • Loading branch information
Benoit Cousson authored and Samuel Ortiz committed Jan 8, 2012
1 parent 5391b5c commit aeb5032
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 2 deletions.
47 changes: 47 additions & 0 deletions Documentation/devicetree/bindings/mfd/twl-familly.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
Texas Instruments TWL family

The TWLs are Integrated Power Management Chips.
Some version might contain much more analog function like
USB transceiver or Audio amplifier.
These chips are connected to an i2c bus.


Required properties:
- compatible : Must be "ti,twl4030";
For Integrated power-management/audio CODEC device used in OMAP3
based boards
- compatible : Must be "ti,twl6030";
For Integrated power-management used in OMAP4 based boards
- interrupts : This i2c device has an IRQ line connected to the main SoC
- interrupt-controller : Since the twl support several interrupts internally,
it is considered as an interrupt controller cascaded to the SoC one.
- #interrupt-cells = <1>;
- interrupt-parent : The parent interrupt controller.

Optional node:
- Child nodes contain in the twl. The twl family is made of several variants
that support a different number of features.
The children nodes will thus depend of the capability of the variant.


Example:
/*
* Integrated Power Management Chip
* http://www.ti.com/lit/ds/symlink/twl6030.pdf
*/
twl@48 {
compatible = "ti,twl6030";
reg = <0x48>;
interrupts = <39>; /* IRQ_SYS_1N cascaded to gic */
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&gic>;
#address-cells = <1>;
#size-cells = <0>;

twl_rtc {
compatible = "ti,twl_rtc";
interrupts = <11>;
reg = <0>;
};
};
2 changes: 1 addition & 1 deletion drivers/mfd/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ config MENELAUS

config TWL4030_CORE
bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support"
depends on I2C=y && GENERIC_HARDIRQS
depends on I2C=y && GENERIC_HARDIRQS && IRQ_DOMAIN
help
Say yes here if you have TWL4030 / TWL6030 family chip on your board.
This core driver provides register access and IRQ handling
Expand Down
51 changes: 50 additions & 1 deletion drivers/mfd/twl-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/irqdomain.h>

#include <linux/regulator/machine.h>

Expand Down Expand Up @@ -144,6 +149,9 @@

#define TWL_MODULE_LAST TWL4030_MODULE_LAST

#define TWL4030_NR_IRQS 8
#define TWL6030_NR_IRQS 20

/* Base Address defns for twl4030_map[] */

/* subchip/slave 0 - USB ID */
Expand Down Expand Up @@ -255,6 +263,7 @@ struct twl_client {

static struct twl_client twl_modules[TWL_NUM_SLAVES];

static struct irq_domain domain;

/* mapping the module id to slave id and base address */
struct twl_mapping {
Expand Down Expand Up @@ -1183,14 +1192,48 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
int status;
unsigned i;
struct twl4030_platform_data *pdata = client->dev.platform_data;
struct device_node *node = client->dev.of_node;
u8 temp;
int ret = 0;
int nr_irqs = TWL4030_NR_IRQS;

if ((id->driver_data) & TWL6030_CLASS)
nr_irqs = TWL6030_NR_IRQS;

if (node && !pdata) {
/*
* XXX: Temporary pdata until the information is correctly
* retrieved by every TWL modules from DT.
*/
pdata = devm_kzalloc(&client->dev,
sizeof(struct twl4030_platform_data),
GFP_KERNEL);
if (!pdata)
return -ENOMEM;
}

if (!pdata) {
dev_dbg(&client->dev, "no platform data?\n");
return -EINVAL;
}

status = irq_alloc_descs(-1, pdata->irq_base, nr_irqs, 0);
if (IS_ERR_VALUE(status)) {
dev_err(&client->dev, "Fail to allocate IRQ descs\n");
return status;
}

pdata->irq_base = status;
pdata->irq_end = pdata->irq_base + nr_irqs;

domain.irq_base = pdata->irq_base;
domain.nr_irq = nr_irqs;
#ifdef CONFIG_OF_IRQ
domain.of_node = of_node_get(node);
domain.ops = &irq_domain_simple_ops;
#endif
irq_domain_add(&domain);

if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
dev_dbg(&client->dev, "can't talk I2C?\n");
return -EIO;
Expand Down Expand Up @@ -1270,7 +1313,13 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
}

status = add_children(pdata, id->driver_data);
#ifdef CONFIG_OF_DEVICE
if (node)
status = of_platform_populate(node, NULL, NULL, &client->dev);
else
#endif
status = add_children(pdata, id->driver_data);

fail:
if (status < 0)
twl_remove(client);
Expand Down

0 comments on commit aeb5032

Please sign in to comment.