diff options
author | Benoit Cousson <b-cousson@ti.com> | 2012-02-29 19:40:31 +0100 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-03-22 13:04:33 +0100 |
commit | 78518ffa08fceee42d61359303c58bdd0a82033f (patch) | |
tree | 3db4458970c145e8b82fa8a31536c700a4479aee /drivers/mfd | |
parent | 1b8f333ff49f778a1215f65754c31c02408d1d08 (diff) |
mfd: Move twl-core IRQ allocation into twl[4030|6030]-irq files
During DT adaptation, the irq_alloc_desc was added into twl-core, but
due to the rather different and weird IRQ management required by the twl4030,
it is much better to have a different approach for it.
The issue is that twl4030 uses a two level IRQ mechanism but handles all the
PWR interrupts as part of the twl-core interrupt range. It ends up with a
range of 16 interrupts total for CORE and PWR.
The other twl4030 functionalities already have a dedicated driver and thus
their IRQs and irqdomain can and should be defined localy.
twl6030 is using a single level IRQ controller and thus does not require any
trick.
Move the irq_alloc_desc and irq_domain_add_legacy in twl4030-irq and
twl6030-irq.
Allocate together CORE and PWR IRQs for twl4030-irq.
Conflicts:
drivers/mfd/twl-core.c
Signed-off-by: Benoit Cousson <b-cousson@ti.com>
Acked-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/twl-core.c | 29 | ||||
-rw-r--r-- | drivers/mfd/twl-core.h | 4 | ||||
-rw-r--r-- | drivers/mfd/twl4030-irq.c | 29 | ||||
-rw-r--r-- | drivers/mfd/twl6030-irq.c | 31 |
4 files changed, 56 insertions, 37 deletions
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 712e262ba99..764c5b5d914 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -147,9 +147,6 @@ #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 */ @@ -1186,17 +1183,12 @@ static int __devinit twl_probe(struct i2c_client *client, const struct i2c_device_id *id) { int irq_base; - int irq_end; 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) { /* @@ -1215,17 +1207,6 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) return -EINVAL; } - status = irq_alloc_descs(-1, 0, nr_irqs, 0); - if (IS_ERR_VALUE(status)) { - dev_err(&client->dev, "Fail to allocate IRQ descs\n"); - return status; - } - - irq_base = status; - irq_end = irq_base + nr_irqs; - irq_domain_add_legacy(node, nr_irqs, irq_base, 0, - &irq_domain_simple_ops, NULL); - if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) { dev_dbg(&client->dev, "can't talk I2C?\n"); return -EIO; @@ -1280,15 +1261,15 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) if (client->irq) { if (twl_class_is_4030()) { twl4030_init_chip_irq(id->name); - status = twl4030_init_irq(client->irq, irq_base, - irq_end); + irq_base = twl4030_init_irq(&client->dev, client->irq); } else { - status = twl6030_init_irq(client->irq, irq_base, - irq_end); + irq_base = twl6030_init_irq(&client->dev, client->irq); } - if (status < 0) + if (irq_base < 0) { + status = irq_base; goto fail; + } } /* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface. diff --git a/drivers/mfd/twl-core.h b/drivers/mfd/twl-core.h index 8c50a556e98..6ff99dce714 100644 --- a/drivers/mfd/twl-core.h +++ b/drivers/mfd/twl-core.h @@ -1,9 +1,9 @@ #ifndef __TWL_CORE_H__ #define __TWL_CORE_H__ -extern int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); +extern int twl6030_init_irq(struct device *dev, int irq_num); extern int twl6030_exit_irq(void); -extern int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); +extern int twl4030_init_irq(struct device *dev, int irq_num); extern int twl4030_exit_irq(void); extern int twl4030_init_chip_irq(const char *chip); diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index b31f920feb5..a3dc1d92907 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -28,10 +28,13 @@ */ #include <linux/init.h> +#include <linux/export.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/slab.h> +#include <linux/of.h> +#include <linux/irqdomain.h> #include <linux/i2c/twl.h> #include "twl-core.h" @@ -53,6 +56,8 @@ * base + 8 .. base + 15 SIH for PWR_INT * base + 16 .. base + 33 SIH for GPIO */ +#define TWL4030_CORE_NR_IRQS 8 +#define TWL4030_PWR_NR_IRQS 8 /* PIH register offsets */ #define REG_PIH_ISR_P1 0x01 @@ -695,14 +700,34 @@ int twl4030_sih_setup(int module) /* FIXME pass in which interrupt line we'll use ... */ #define twl_irq_line 0 -int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) +int twl4030_init_irq(struct device *dev, int irq_num) { static struct irq_chip twl4030_irq_chip; + int irq_base, irq_end, nr_irqs; + struct device_node *node = dev->of_node; int status; int i; /* + * TWL core and pwr interrupts must be contiguous because + * the hwirqs numbers are defined contiguously from 1 to 15. + * Create only one domain for both. + */ + nr_irqs = TWL4030_PWR_NR_IRQS + TWL4030_CORE_NR_IRQS; + + irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0); + if (IS_ERR_VALUE(irq_base)) { + dev_err(dev, "Fail to allocate IRQ descs\n"); + return irq_base; + } + + irq_domain_add_legacy(node, nr_irqs, irq_base, 0, + &irq_domain_simple_ops, NULL); + + irq_end = irq_base + TWL4030_CORE_NR_IRQS; + + /* * Mask and clear all TWL4030 interrupts since initially we do * not have any TWL4030 module interrupt handlers present */ @@ -747,7 +772,7 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) goto fail_rqirq; } - return status; + return irq_base; fail_rqirq: /* clean up twl4030_sih_setup */ fail: diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index bb3d762280f..86c4082fa41 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -39,6 +39,8 @@ #include <linux/i2c/twl.h> #include <linux/platform_device.h> #include <linux/suspend.h> +#include <linux/of.h> +#include <linux/irqdomain.h> #include "twl-core.h" @@ -53,6 +55,7 @@ * specifies mapping between interrupt number and the associated module. * */ +#define TWL6030_NR_IRQS 20 static int twl6030_interrupt_mapping[24] = { PWR_INTR_OFFSET, /* Bit 0 PWRON */ @@ -246,11 +249,6 @@ static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on) return 0; } -/*----------------------------------------------------------------------*/ - -static unsigned twl6030_irq_next; - -/*----------------------------------------------------------------------*/ int twl6030_interrupt_unmask(u8 bit_mask, u8 offset) { int ret; @@ -350,8 +348,10 @@ int twl6030_mmc_card_detect(struct device *dev, int slot) } EXPORT_SYMBOL(twl6030_mmc_card_detect); -int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) +int twl6030_init_irq(struct device *dev, int irq_num) { + struct device_node *node = dev->of_node; + int nr_irqs, irq_base, irq_end; int status = 0; int i; @@ -360,6 +360,20 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) u8 mask[4]; static struct irq_chip twl6030_irq_chip; + + nr_irqs = TWL6030_NR_IRQS; + + irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0); + if (IS_ERR_VALUE(irq_base)) { + dev_err(dev, "Fail to allocate IRQ descs\n"); + return irq_base; + } + + irq_domain_add_legacy(node, nr_irqs, irq_base, 0, + &irq_domain_simple_ops, NULL); + + irq_end = irq_base + nr_irqs; + mask[1] = 0xFF; mask[2] = 0xFF; mask[3] = 0xFF; @@ -387,9 +401,8 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) activate_irq(i); } - twl6030_irq_next = i; pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH", - irq_num, irq_base, twl6030_irq_next - 1); + irq_num, irq_base, irq_end); /* install an irq handler to demultiplex the TWL6030 interrupt */ init_completion(&irq_event); @@ -410,7 +423,7 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) twl_irq = irq_num; register_pm_notifier(&twl6030_irq_pm_notifier_block); - return status; + return irq_base; fail_kthread: free_irq(irq_num, &irq_event); |