diff options
author | Benoit Cousson <b-cousson@ti.com> | 2012-02-29 13:40:31 -0500 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-03-22 08:04:33 -0400 |
commit | 78518ffa08fceee42d61359303c58bdd0a82033f (patch) | |
tree | 3db4458970c145e8b82fa8a31536c700a4479aee /drivers | |
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')
-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 712e262ba99c..764c5b5d914e 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c | |||
@@ -147,9 +147,6 @@ | |||
147 | 147 | ||
148 | #define TWL_MODULE_LAST TWL4030_MODULE_LAST | 148 | #define TWL_MODULE_LAST TWL4030_MODULE_LAST |
149 | 149 | ||
150 | #define TWL4030_NR_IRQS 8 | ||
151 | #define TWL6030_NR_IRQS 20 | ||
152 | |||
153 | /* Base Address defns for twl4030_map[] */ | 150 | /* Base Address defns for twl4030_map[] */ |
154 | 151 | ||
155 | /* subchip/slave 0 - USB ID */ | 152 | /* subchip/slave 0 - USB ID */ |
@@ -1186,17 +1183,12 @@ static int __devinit | |||
1186 | twl_probe(struct i2c_client *client, const struct i2c_device_id *id) | 1183 | twl_probe(struct i2c_client *client, const struct i2c_device_id *id) |
1187 | { | 1184 | { |
1188 | int irq_base; | 1185 | int irq_base; |
1189 | int irq_end; | ||
1190 | int status; | 1186 | int status; |
1191 | unsigned i; | 1187 | unsigned i; |
1192 | struct twl4030_platform_data *pdata = client->dev.platform_data; | 1188 | struct twl4030_platform_data *pdata = client->dev.platform_data; |
1193 | struct device_node *node = client->dev.of_node; | 1189 | struct device_node *node = client->dev.of_node; |
1194 | u8 temp; | 1190 | u8 temp; |
1195 | int ret = 0; | 1191 | int ret = 0; |
1196 | int nr_irqs = TWL4030_NR_IRQS; | ||
1197 | |||
1198 | if ((id->driver_data) & TWL6030_CLASS) | ||
1199 | nr_irqs = TWL6030_NR_IRQS; | ||
1200 | 1192 | ||
1201 | if (node && !pdata) { | 1193 | if (node && !pdata) { |
1202 | /* | 1194 | /* |
@@ -1215,17 +1207,6 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
1215 | return -EINVAL; | 1207 | return -EINVAL; |
1216 | } | 1208 | } |
1217 | 1209 | ||
1218 | status = irq_alloc_descs(-1, 0, nr_irqs, 0); | ||
1219 | if (IS_ERR_VALUE(status)) { | ||
1220 | dev_err(&client->dev, "Fail to allocate IRQ descs\n"); | ||
1221 | return status; | ||
1222 | } | ||
1223 | |||
1224 | irq_base = status; | ||
1225 | irq_end = irq_base + nr_irqs; | ||
1226 | irq_domain_add_legacy(node, nr_irqs, irq_base, 0, | ||
1227 | &irq_domain_simple_ops, NULL); | ||
1228 | |||
1229 | if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) { | 1210 | if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) { |
1230 | dev_dbg(&client->dev, "can't talk I2C?\n"); | 1211 | dev_dbg(&client->dev, "can't talk I2C?\n"); |
1231 | return -EIO; | 1212 | return -EIO; |
@@ -1280,15 +1261,15 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
1280 | if (client->irq) { | 1261 | if (client->irq) { |
1281 | if (twl_class_is_4030()) { | 1262 | if (twl_class_is_4030()) { |
1282 | twl4030_init_chip_irq(id->name); | 1263 | twl4030_init_chip_irq(id->name); |
1283 | status = twl4030_init_irq(client->irq, irq_base, | 1264 | irq_base = twl4030_init_irq(&client->dev, client->irq); |
1284 | irq_end); | ||
1285 | } else { | 1265 | } else { |
1286 | status = twl6030_init_irq(client->irq, irq_base, | 1266 | irq_base = twl6030_init_irq(&client->dev, client->irq); |
1287 | irq_end); | ||
1288 | } | 1267 | } |
1289 | 1268 | ||
1290 | if (status < 0) | 1269 | if (irq_base < 0) { |
1270 | status = irq_base; | ||
1291 | goto fail; | 1271 | goto fail; |
1272 | } | ||
1292 | } | 1273 | } |
1293 | 1274 | ||
1294 | /* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface. | 1275 | /* 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 8c50a556e986..6ff99dce714f 100644 --- a/drivers/mfd/twl-core.h +++ b/drivers/mfd/twl-core.h | |||
@@ -1,9 +1,9 @@ | |||
1 | #ifndef __TWL_CORE_H__ | 1 | #ifndef __TWL_CORE_H__ |
2 | #define __TWL_CORE_H__ | 2 | #define __TWL_CORE_H__ |
3 | 3 | ||
4 | extern int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); | 4 | extern int twl6030_init_irq(struct device *dev, int irq_num); |
5 | extern int twl6030_exit_irq(void); | 5 | extern int twl6030_exit_irq(void); |
6 | extern int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end); | 6 | extern int twl4030_init_irq(struct device *dev, int irq_num); |
7 | extern int twl4030_exit_irq(void); | 7 | extern int twl4030_exit_irq(void); |
8 | extern int twl4030_init_chip_irq(const char *chip); | 8 | extern int twl4030_init_chip_irq(const char *chip); |
9 | 9 | ||
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index b31f920feb51..a3dc1d929070 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c | |||
@@ -28,10 +28,13 @@ | |||
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <linux/export.h> | ||
31 | #include <linux/interrupt.h> | 32 | #include <linux/interrupt.h> |
32 | #include <linux/irq.h> | 33 | #include <linux/irq.h> |
33 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
34 | 35 | ||
36 | #include <linux/of.h> | ||
37 | #include <linux/irqdomain.h> | ||
35 | #include <linux/i2c/twl.h> | 38 | #include <linux/i2c/twl.h> |
36 | 39 | ||
37 | #include "twl-core.h" | 40 | #include "twl-core.h" |
@@ -53,6 +56,8 @@ | |||
53 | * base + 8 .. base + 15 SIH for PWR_INT | 56 | * base + 8 .. base + 15 SIH for PWR_INT |
54 | * base + 16 .. base + 33 SIH for GPIO | 57 | * base + 16 .. base + 33 SIH for GPIO |
55 | */ | 58 | */ |
59 | #define TWL4030_CORE_NR_IRQS 8 | ||
60 | #define TWL4030_PWR_NR_IRQS 8 | ||
56 | 61 | ||
57 | /* PIH register offsets */ | 62 | /* PIH register offsets */ |
58 | #define REG_PIH_ISR_P1 0x01 | 63 | #define REG_PIH_ISR_P1 0x01 |
@@ -695,14 +700,34 @@ int twl4030_sih_setup(int module) | |||
695 | /* FIXME pass in which interrupt line we'll use ... */ | 700 | /* FIXME pass in which interrupt line we'll use ... */ |
696 | #define twl_irq_line 0 | 701 | #define twl_irq_line 0 |
697 | 702 | ||
698 | int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | 703 | int twl4030_init_irq(struct device *dev, int irq_num) |
699 | { | 704 | { |
700 | static struct irq_chip twl4030_irq_chip; | 705 | static struct irq_chip twl4030_irq_chip; |
706 | int irq_base, irq_end, nr_irqs; | ||
707 | struct device_node *node = dev->of_node; | ||
701 | 708 | ||
702 | int status; | 709 | int status; |
703 | int i; | 710 | int i; |
704 | 711 | ||
705 | /* | 712 | /* |
713 | * TWL core and pwr interrupts must be contiguous because | ||
714 | * the hwirqs numbers are defined contiguously from 1 to 15. | ||
715 | * Create only one domain for both. | ||
716 | */ | ||
717 | nr_irqs = TWL4030_PWR_NR_IRQS + TWL4030_CORE_NR_IRQS; | ||
718 | |||
719 | irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0); | ||
720 | if (IS_ERR_VALUE(irq_base)) { | ||
721 | dev_err(dev, "Fail to allocate IRQ descs\n"); | ||
722 | return irq_base; | ||
723 | } | ||
724 | |||
725 | irq_domain_add_legacy(node, nr_irqs, irq_base, 0, | ||
726 | &irq_domain_simple_ops, NULL); | ||
727 | |||
728 | irq_end = irq_base + TWL4030_CORE_NR_IRQS; | ||
729 | |||
730 | /* | ||
706 | * Mask and clear all TWL4030 interrupts since initially we do | 731 | * Mask and clear all TWL4030 interrupts since initially we do |
707 | * not have any TWL4030 module interrupt handlers present | 732 | * not have any TWL4030 module interrupt handlers present |
708 | */ | 733 | */ |
@@ -747,7 +772,7 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | |||
747 | goto fail_rqirq; | 772 | goto fail_rqirq; |
748 | } | 773 | } |
749 | 774 | ||
750 | return status; | 775 | return irq_base; |
751 | fail_rqirq: | 776 | fail_rqirq: |
752 | /* clean up twl4030_sih_setup */ | 777 | /* clean up twl4030_sih_setup */ |
753 | fail: | 778 | fail: |
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index bb3d762280f9..86c4082fa411 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c | |||
@@ -39,6 +39,8 @@ | |||
39 | #include <linux/i2c/twl.h> | 39 | #include <linux/i2c/twl.h> |
40 | #include <linux/platform_device.h> | 40 | #include <linux/platform_device.h> |
41 | #include <linux/suspend.h> | 41 | #include <linux/suspend.h> |
42 | #include <linux/of.h> | ||
43 | #include <linux/irqdomain.h> | ||
42 | 44 | ||
43 | #include "twl-core.h" | 45 | #include "twl-core.h" |
44 | 46 | ||
@@ -53,6 +55,7 @@ | |||
53 | * specifies mapping between interrupt number and the associated module. | 55 | * specifies mapping between interrupt number and the associated module. |
54 | * | 56 | * |
55 | */ | 57 | */ |
58 | #define TWL6030_NR_IRQS 20 | ||
56 | 59 | ||
57 | static int twl6030_interrupt_mapping[24] = { | 60 | static int twl6030_interrupt_mapping[24] = { |
58 | PWR_INTR_OFFSET, /* Bit 0 PWRON */ | 61 | PWR_INTR_OFFSET, /* Bit 0 PWRON */ |
@@ -246,11 +249,6 @@ static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on) | |||
246 | return 0; | 249 | return 0; |
247 | } | 250 | } |
248 | 251 | ||
249 | /*----------------------------------------------------------------------*/ | ||
250 | |||
251 | static unsigned twl6030_irq_next; | ||
252 | |||
253 | /*----------------------------------------------------------------------*/ | ||
254 | int twl6030_interrupt_unmask(u8 bit_mask, u8 offset) | 252 | int twl6030_interrupt_unmask(u8 bit_mask, u8 offset) |
255 | { | 253 | { |
256 | int ret; | 254 | int ret; |
@@ -350,8 +348,10 @@ int twl6030_mmc_card_detect(struct device *dev, int slot) | |||
350 | } | 348 | } |
351 | EXPORT_SYMBOL(twl6030_mmc_card_detect); | 349 | EXPORT_SYMBOL(twl6030_mmc_card_detect); |
352 | 350 | ||
353 | int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | 351 | int twl6030_init_irq(struct device *dev, int irq_num) |
354 | { | 352 | { |
353 | struct device_node *node = dev->of_node; | ||
354 | int nr_irqs, irq_base, irq_end; | ||
355 | 355 | ||
356 | int status = 0; | 356 | int status = 0; |
357 | int i; | 357 | int i; |
@@ -360,6 +360,20 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | |||
360 | u8 mask[4]; | 360 | u8 mask[4]; |
361 | 361 | ||
362 | static struct irq_chip twl6030_irq_chip; | 362 | static struct irq_chip twl6030_irq_chip; |
363 | |||
364 | nr_irqs = TWL6030_NR_IRQS; | ||
365 | |||
366 | irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0); | ||
367 | if (IS_ERR_VALUE(irq_base)) { | ||
368 | dev_err(dev, "Fail to allocate IRQ descs\n"); | ||
369 | return irq_base; | ||
370 | } | ||
371 | |||
372 | irq_domain_add_legacy(node, nr_irqs, irq_base, 0, | ||
373 | &irq_domain_simple_ops, NULL); | ||
374 | |||
375 | irq_end = irq_base + nr_irqs; | ||
376 | |||
363 | mask[1] = 0xFF; | 377 | mask[1] = 0xFF; |
364 | mask[2] = 0xFF; | 378 | mask[2] = 0xFF; |
365 | mask[3] = 0xFF; | 379 | mask[3] = 0xFF; |
@@ -387,9 +401,8 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | |||
387 | activate_irq(i); | 401 | activate_irq(i); |
388 | } | 402 | } |
389 | 403 | ||
390 | twl6030_irq_next = i; | ||
391 | pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH", | 404 | pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH", |
392 | irq_num, irq_base, twl6030_irq_next - 1); | 405 | irq_num, irq_base, irq_end); |
393 | 406 | ||
394 | /* install an irq handler to demultiplex the TWL6030 interrupt */ | 407 | /* install an irq handler to demultiplex the TWL6030 interrupt */ |
395 | init_completion(&irq_event); | 408 | init_completion(&irq_event); |
@@ -410,7 +423,7 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | |||
410 | 423 | ||
411 | twl_irq = irq_num; | 424 | twl_irq = irq_num; |
412 | register_pm_notifier(&twl6030_irq_pm_notifier_block); | 425 | register_pm_notifier(&twl6030_irq_pm_notifier_block); |
413 | return status; | 426 | return irq_base; |
414 | 427 | ||
415 | fail_kthread: | 428 | fail_kthread: |
416 | free_irq(irq_num, &irq_event); | 429 | free_irq(irq_num, &irq_event); |