diff options
Diffstat (limited to 'drivers/mfd/ab8500-core.c')
-rw-r--r-- | drivers/mfd/ab8500-core.c | 130 |
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) | |||
361 | static void ab8500_irq_mask(struct irq_data *data) | 362 | static 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) | |||
371 | static void ab8500_irq_unmask(struct irq_data *data) | 372 | static 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 | ||
513 | static 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 | */ | ||
522 | int 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)) | 529 | EXPORT_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++) { | 531 | static 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 | ||
541 | static void ab8500_irq_remove(struct ab8500 *ab8500) | 552 | static struct irq_domain_ops ab8500_irq_ops = { |
553 | .map = ab8500_irq_map, | ||
554 | .xlate = irq_domain_xlate_twocell, | ||
555 | }; | ||
556 | |||
557 | static 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 | ||
563 | int ab8500_suspend(struct ab8500 *ab8500) | 586 | int 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 | ||
1423 | out_freeirq: | 1438 | out_freeirq: |
1424 | if (ab8500->irq_base) | 1439 | free_irq(ab8500->irq, ab8500); |
1425 | free_irq(ab8500->irq, ab8500); | ||
1426 | out_removeirq: | ||
1427 | if (ab8500->irq_base) | ||
1428 | ab8500_irq_remove(ab8500); | ||
1429 | out_freeoldmask: | 1440 | out_freeoldmask: |
1430 | kfree(ab8500->oldmask); | 1441 | kfree(ab8500->oldmask); |
1431 | out_freemask: | 1442 | out_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); |