aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/ab8500-core.c
diff options
context:
space:
mode:
authorLee Jones <lee.jones@linaro.org>2012-06-20 08:56:37 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2012-07-08 18:16:08 -0400
commit06e589efa5b75e6a38a8e8b9c6cd774b5f679cdc (patch)
tree01845abcf4b91b726c9f8919f7186997c04f7dc9 /drivers/mfd/ab8500-core.c
parent3c1447620401294b81e34bec7195f803c749bb91 (diff)
mfd: Add IRQ domain support for the AB8500
As the AB8500 is an IRQ controller in its own right, here we provide the AB8500 driver with IRQ domain support. This is required if we wish to reference any of its IRQs from a platform's Device Tree. Cc: Naga Radheshy <naga.radheshy@stericsson.com> Cc: Mattias Wallin <mattias.wallin@stericsson.com> Cc: Daniel Willerud <daniel.willerud@stericsson.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/ab8500-core.c')
-rw-r--r--drivers/mfd/ab8500-core.c130
1 files changed, 70 insertions, 60 deletions
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index dac0e2998603..f3af34596439 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -11,6 +11,7 @@
11#include <linux/slab.h> 11#include <linux/slab.h>
12#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/irq.h> 13#include <linux/irq.h>
14#include <linux/irqdomain.h>
14#include <linux/delay.h> 15#include <linux/delay.h>
15#include <linux/interrupt.h> 16#include <linux/interrupt.h>
16#include <linux/module.h> 17#include <linux/module.h>
@@ -361,7 +362,7 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
361static void ab8500_irq_mask(struct irq_data *data) 362static void ab8500_irq_mask(struct irq_data *data)
362{ 363{
363 struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 364 struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
364 int offset = data->irq - ab8500->irq_base; 365 int offset = data->hwirq;
365 int index = offset / 8; 366 int index = offset / 8;
366 int mask = 1 << (offset % 8); 367 int mask = 1 << (offset % 8);
367 368
@@ -371,7 +372,7 @@ static void ab8500_irq_mask(struct irq_data *data)
371static void ab8500_irq_unmask(struct irq_data *data) 372static void ab8500_irq_unmask(struct irq_data *data)
372{ 373{
373 struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); 374 struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
374 int offset = data->irq - ab8500->irq_base; 375 int offset = data->hwirq;
375 int index = offset / 8; 376 int index = offset / 8;
376 int mask = 1 << (offset % 8); 377 int mask = 1 << (offset % 8);
377 378
@@ -510,38 +511,51 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
510 return IRQ_HANDLED; 511 return IRQ_HANDLED;
511} 512}
512 513
513static int ab8500_irq_init(struct ab8500 *ab8500) 514/**
515 * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
516 *
517 * @ab8500: ab8500_irq controller to operate on.
518 * @irq: index of the interrupt requested in the chip IRQs
519 *
520 * Useful for drivers to request their own IRQs.
521 */
522int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq)
514{ 523{
515 int base = ab8500->irq_base; 524 if (!ab8500)
516 int irq; 525 return -EINVAL;
517 int num_irqs;
518 526
519 if (is_ab9540(ab8500)) 527 return irq_create_mapping(ab8500->domain, irq);
520 num_irqs = AB9540_NR_IRQS; 528}
521 else if (is_ab8505(ab8500)) 529EXPORT_SYMBOL_GPL(ab8500_irq_get_virq);
522 num_irqs = AB8505_NR_IRQS;
523 else
524 num_irqs = AB8500_NR_IRQS;
525 530
526 for (irq = base; irq < base + num_irqs; irq++) { 531static int ab8500_irq_map(struct irq_domain *d, unsigned int virq,
527 irq_set_chip_data(irq, ab8500); 532 irq_hw_number_t hwirq)
528 irq_set_chip_and_handler(irq, &ab8500_irq_chip, 533{
529 handle_simple_irq); 534 struct ab8500 *ab8500 = d->host_data;
530 irq_set_nested_thread(irq, 1); 535
536 if (!ab8500)
537 return -EINVAL;
538
539 irq_set_chip_data(virq, ab8500);
540 irq_set_chip_and_handler(virq, &ab8500_irq_chip,
541 handle_simple_irq);
542 irq_set_nested_thread(virq, 1);
531#ifdef CONFIG_ARM 543#ifdef CONFIG_ARM
532 set_irq_flags(irq, IRQF_VALID); 544 set_irq_flags(virq, IRQF_VALID);
533#else 545#else
534 irq_set_noprobe(irq); 546 irq_set_noprobe(virq);
535#endif 547#endif
536 }
537 548
538 return 0; 549 return 0;
539} 550}
540 551
541static void ab8500_irq_remove(struct ab8500 *ab8500) 552static struct irq_domain_ops ab8500_irq_ops = {
553 .map = ab8500_irq_map,
554 .xlate = irq_domain_xlate_twocell,
555};
556
557static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np)
542{ 558{
543 int base = ab8500->irq_base;
544 int irq;
545 int num_irqs; 559 int num_irqs;
546 560
547 if (is_ab9540(ab8500)) 561 if (is_ab9540(ab8500))
@@ -551,13 +565,22 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
551 else 565 else
552 num_irqs = AB8500_NR_IRQS; 566 num_irqs = AB8500_NR_IRQS;
553 567
554 for (irq = base; irq < base + num_irqs; irq++) { 568 if (ab8500->irq_base) {
555#ifdef CONFIG_ARM 569 ab8500->domain = irq_domain_add_legacy(
556 set_irq_flags(irq, 0); 570 NULL, num_irqs, ab8500->irq_base,
557#endif 571 0, &ab8500_irq_ops, ab8500);
558 irq_set_chip_and_handler(irq, NULL, NULL); 572 }
559 irq_set_chip_data(irq, NULL); 573 else {
574 ab8500->domain = irq_domain_add_linear(
575 np, num_irqs, &ab8500_irq_ops, ab8500);
560 } 576 }
577
578 if (!ab8500->domain) {
579 dev_err(ab8500->dev, "Failed to create irqdomain\n");
580 return -ENOSYS;
581 }
582
583 return 0;
561} 584}
562 585
563int ab8500_suspend(struct ab8500 *ab8500) 586int ab8500_suspend(struct ab8500 *ab8500)
@@ -1233,14 +1256,6 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
1233 1256
1234 if (plat) 1257 if (plat)
1235 ab8500->irq_base = plat->irq_base; 1258 ab8500->irq_base = plat->irq_base;
1236 else if (np)
1237 ret = of_property_read_u32(np, "stericsson,irq-base", &ab8500->irq_base);
1238
1239 if (!ab8500->irq_base) {
1240 dev_info(&pdev->dev, "couldn't find irq-base\n");
1241 ret = -EINVAL;
1242 goto out_free_ab8500;
1243 }
1244 1259
1245 ab8500->dev = &pdev->dev; 1260 ab8500->dev = &pdev->dev;
1246 1261
@@ -1323,7 +1338,7 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
1323 AB8500_SWITCH_OFF_STATUS, &value); 1338 AB8500_SWITCH_OFF_STATUS, &value);
1324 if (ret < 0) 1339 if (ret < 0)
1325 return ret; 1340 return ret;
1326 dev_info(ab8500->dev, "switch off status: %#x", value); 1341 dev_info(ab8500->dev, "switch off status: %#x\n", value);
1327 1342
1328 if (plat && plat->init) 1343 if (plat && plat->init)
1329 plat->init(ab8500); 1344 plat->init(ab8500);
@@ -1352,25 +1367,25 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
1352 for (i = 0; i < ab8500->mask_size; i++) 1367 for (i = 0; i < ab8500->mask_size; i++)
1353 ab8500->mask[i] = ab8500->oldmask[i] = 0xff; 1368 ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
1354 1369
1355 if (ab8500->irq_base) { 1370 ret = ab8500_irq_init(ab8500, np);
1356 ret = ab8500_irq_init(ab8500); 1371 if (ret)
1357 if (ret) 1372 goto out_freeoldmask;
1358 goto out_freeoldmask;
1359 1373
1360 /* Activate this feature only in ab9540 */ 1374 /* Activate this feature only in ab9540 */
1361 /* till tests are done on ab8500 1p2 or later*/ 1375 /* till tests are done on ab8500 1p2 or later*/
1362 if (is_ab9540(ab8500)) 1376 if (is_ab9540(ab8500)) {
1363 ret = request_threaded_irq(ab8500->irq, NULL, 1377 ret = request_threaded_irq(ab8500->irq, NULL,
1364 ab8500_hierarchical_irq, 1378 ab8500_hierarchical_irq,
1365 IRQF_ONESHOT | IRQF_NO_SUSPEND, 1379 IRQF_ONESHOT | IRQF_NO_SUSPEND,
1366 "ab8500", ab8500); 1380 "ab8500", ab8500);
1367 else 1381 }
1368 ret = request_threaded_irq(ab8500->irq, NULL, 1382 else {
1383 ret = request_threaded_irq(ab8500->irq, NULL,
1369 ab8500_irq, 1384 ab8500_irq,
1370 IRQF_ONESHOT | IRQF_NO_SUSPEND, 1385 IRQF_ONESHOT | IRQF_NO_SUSPEND,
1371 "ab8500", ab8500); 1386 "ab8500", ab8500);
1372 if (ret) 1387 if (ret)
1373 goto out_removeirq; 1388 goto out_freeoldmask;
1374 } 1389 }
1375 1390
1376 if (!np) { 1391 if (!np) {
@@ -1417,15 +1432,11 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
1417 &ab8500_attr_group); 1432 &ab8500_attr_group);
1418 if (ret) 1433 if (ret)
1419 dev_err(ab8500->dev, "error creating sysfs entries\n"); 1434 dev_err(ab8500->dev, "error creating sysfs entries\n");
1420 else 1435
1421 return ret; 1436 return ret;
1422 1437
1423out_freeirq: 1438out_freeirq:
1424 if (ab8500->irq_base) 1439 free_irq(ab8500->irq, ab8500);
1425 free_irq(ab8500->irq, ab8500);
1426out_removeirq:
1427 if (ab8500->irq_base)
1428 ab8500_irq_remove(ab8500);
1429out_freeoldmask: 1440out_freeoldmask:
1430 kfree(ab8500->oldmask); 1441 kfree(ab8500->oldmask);
1431out_freemask: 1442out_freemask:
@@ -1444,11 +1455,10 @@ static int __devexit ab8500_remove(struct platform_device *pdev)
1444 sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group); 1455 sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
1445 else 1456 else
1446 sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group); 1457 sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
1458
1447 mfd_remove_devices(ab8500->dev); 1459 mfd_remove_devices(ab8500->dev);
1448 if (ab8500->irq_base) { 1460 free_irq(ab8500->irq, ab8500);
1449 free_irq(ab8500->irq, ab8500); 1461
1450 ab8500_irq_remove(ab8500);
1451 }
1452 kfree(ab8500->oldmask); 1462 kfree(ab8500->oldmask);
1453 kfree(ab8500->mask); 1463 kfree(ab8500->mask);
1454 kfree(ab8500); 1464 kfree(ab8500);