aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-05-14 17:14:24 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2012-05-20 11:27:07 -0400
commitcd99758ba3bde64347a8ece381cbae2fb5c745b2 (patch)
treece74c5150978f1cd29861e33e8847bc5dd667ed7 /drivers/mfd
parent4492c4c3ff7bbb5fd400f021532643a3493f0723 (diff)
mfd: Convert wm831x to irq_domain
The modern idiom is to use irq_domain to allocate interrupts. This is useful partly to allow further infrastructure to be based on the domains and partly because it makes it much easier to allocate virtual interrupts to devices as we don't need to allocate a contiguous range of interrupt numbers. Convert the wm831x driver over to this infrastructure, using a legacy IRQ mapping if an irq_base is specified in platform data and otherwise using a linear mapping, always registering the interrupts even if they won't ever be used. Only boards which need to use the GPIOs as interrupts should need to use an irq_base. This means that we can't use the MFD irq_base management since the unless we're using an explicit irq_base from platform data we can't rely on a linear mapping of interrupts. Instead we need to map things via the irq_domain - provide a conveniencem function wm831x_irq() to save a small amount of typing when doing so. Looking at this I couldn't clearly see anything the MFD core could do to make this nicer. Since we're not supporting device tree yet there's no meaningful advantage if we don't do this conversion in one, the fact that the interrupt resources are used for repeated IP blocks makes accessor functions for the irq_domain more trouble to do than they're worth. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig2
-rw-r--r--drivers/mfd/wm831x-auxadc.c6
-rw-r--r--drivers/mfd/wm831x-core.c19
-rw-r--r--drivers/mfd/wm831x-irq.c101
4 files changed, 78 insertions, 50 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index a0e1b834af61..8325c44c04c6 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -496,6 +496,7 @@ config MFD_WM831X_I2C
496 select MFD_CORE 496 select MFD_CORE
497 select MFD_WM831X 497 select MFD_WM831X
498 select REGMAP_I2C 498 select REGMAP_I2C
499 select IRQ_DOMAIN
499 depends on I2C=y && GENERIC_HARDIRQS 500 depends on I2C=y && GENERIC_HARDIRQS
500 help 501 help
501 Support for the Wolfson Microelecronics WM831x and WM832x PMICs 502 Support for the Wolfson Microelecronics WM831x and WM832x PMICs
@@ -508,6 +509,7 @@ config MFD_WM831X_SPI
508 select MFD_CORE 509 select MFD_CORE
509 select MFD_WM831X 510 select MFD_WM831X
510 select REGMAP_SPI 511 select REGMAP_SPI
512 select IRQ_DOMAIN
511 depends on SPI_MASTER && GENERIC_HARDIRQS 513 depends on SPI_MASTER && GENERIC_HARDIRQS
512 help 514 help
513 Support for the Wolfson Microelecronics WM831x and WM832x PMICs 515 Support for the Wolfson Microelecronics WM831x and WM832x PMICs
diff --git a/drivers/mfd/wm831x-auxadc.c b/drivers/mfd/wm831x-auxadc.c
index 87210954a066..6ee3018d8653 100644
--- a/drivers/mfd/wm831x-auxadc.c
+++ b/drivers/mfd/wm831x-auxadc.c
@@ -280,11 +280,11 @@ void wm831x_auxadc_init(struct wm831x *wm831x)
280 mutex_init(&wm831x->auxadc_lock); 280 mutex_init(&wm831x->auxadc_lock);
281 INIT_LIST_HEAD(&wm831x->auxadc_pending); 281 INIT_LIST_HEAD(&wm831x->auxadc_pending);
282 282
283 if (wm831x->irq && wm831x->irq_base) { 283 if (wm831x->irq) {
284 wm831x->auxadc_read = wm831x_auxadc_read_irq; 284 wm831x->auxadc_read = wm831x_auxadc_read_irq;
285 285
286 ret = request_threaded_irq(wm831x->irq_base + 286 ret = request_threaded_irq(wm831x_irq(wm831x,
287 WM831X_IRQ_AUXADC_DATA, 287 WM831X_IRQ_AUXADC_DATA),
288 NULL, wm831x_auxadc_irq, 0, 288 NULL, wm831x_auxadc_irq, 0,
289 "auxadc", wm831x); 289 "auxadc", wm831x);
290 if (ret < 0) { 290 if (ret < 0) {
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 476e4d31a823..946698fd2dc6 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -1813,27 +1813,27 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
1813 case WM8310: 1813 case WM8310:
1814 ret = mfd_add_devices(wm831x->dev, wm831x_num, 1814 ret = mfd_add_devices(wm831x->dev, wm831x_num,
1815 wm8310_devs, ARRAY_SIZE(wm8310_devs), 1815 wm8310_devs, ARRAY_SIZE(wm8310_devs),
1816 NULL, wm831x->irq_base); 1816 NULL, 0);
1817 break; 1817 break;
1818 1818
1819 case WM8311: 1819 case WM8311:
1820 ret = mfd_add_devices(wm831x->dev, wm831x_num, 1820 ret = mfd_add_devices(wm831x->dev, wm831x_num,
1821 wm8311_devs, ARRAY_SIZE(wm8311_devs), 1821 wm8311_devs, ARRAY_SIZE(wm8311_devs),
1822 NULL, wm831x->irq_base); 1822 NULL, 0);
1823 if (!pdata || !pdata->disable_touch) 1823 if (!pdata || !pdata->disable_touch)
1824 mfd_add_devices(wm831x->dev, wm831x_num, 1824 mfd_add_devices(wm831x->dev, wm831x_num,
1825 touch_devs, ARRAY_SIZE(touch_devs), 1825 touch_devs, ARRAY_SIZE(touch_devs),
1826 NULL, wm831x->irq_base); 1826 NULL, 0);
1827 break; 1827 break;
1828 1828
1829 case WM8312: 1829 case WM8312:
1830 ret = mfd_add_devices(wm831x->dev, wm831x_num, 1830 ret = mfd_add_devices(wm831x->dev, wm831x_num,
1831 wm8312_devs, ARRAY_SIZE(wm8312_devs), 1831 wm8312_devs, ARRAY_SIZE(wm8312_devs),
1832 NULL, wm831x->irq_base); 1832 NULL, 0);
1833 if (!pdata || !pdata->disable_touch) 1833 if (!pdata || !pdata->disable_touch)
1834 mfd_add_devices(wm831x->dev, wm831x_num, 1834 mfd_add_devices(wm831x->dev, wm831x_num,
1835 touch_devs, ARRAY_SIZE(touch_devs), 1835 touch_devs, ARRAY_SIZE(touch_devs),
1836 NULL, wm831x->irq_base); 1836 NULL, 0);
1837 break; 1837 break;
1838 1838
1839 case WM8320: 1839 case WM8320:
@@ -1842,7 +1842,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
1842 case WM8326: 1842 case WM8326:
1843 ret = mfd_add_devices(wm831x->dev, wm831x_num, 1843 ret = mfd_add_devices(wm831x->dev, wm831x_num,
1844 wm8320_devs, ARRAY_SIZE(wm8320_devs), 1844 wm8320_devs, ARRAY_SIZE(wm8320_devs),
1845 NULL, wm831x->irq_base); 1845 NULL, 0);
1846 break; 1846 break;
1847 1847
1848 default: 1848 default:
@@ -1867,7 +1867,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
1867 if (ret & WM831X_XTAL_ENA) { 1867 if (ret & WM831X_XTAL_ENA) {
1868 ret = mfd_add_devices(wm831x->dev, wm831x_num, 1868 ret = mfd_add_devices(wm831x->dev, wm831x_num,
1869 rtc_devs, ARRAY_SIZE(rtc_devs), 1869 rtc_devs, ARRAY_SIZE(rtc_devs),
1870 NULL, wm831x->irq_base); 1870 NULL, 0);
1871 if (ret != 0) { 1871 if (ret != 0) {
1872 dev_err(wm831x->dev, "Failed to add RTC: %d\n", ret); 1872 dev_err(wm831x->dev, "Failed to add RTC: %d\n", ret);
1873 goto err_irq; 1873 goto err_irq;
@@ -1880,7 +1880,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
1880 /* Treat errors as non-critical */ 1880 /* Treat errors as non-critical */
1881 ret = mfd_add_devices(wm831x->dev, wm831x_num, backlight_devs, 1881 ret = mfd_add_devices(wm831x->dev, wm831x_num, backlight_devs,
1882 ARRAY_SIZE(backlight_devs), NULL, 1882 ARRAY_SIZE(backlight_devs), NULL,
1883 wm831x->irq_base); 1883 0);
1884 if (ret < 0) 1884 if (ret < 0)
1885 dev_err(wm831x->dev, "Failed to add backlight: %d\n", 1885 dev_err(wm831x->dev, "Failed to add backlight: %d\n",
1886 ret); 1886 ret);
@@ -1909,8 +1909,7 @@ void wm831x_device_exit(struct wm831x *wm831x)
1909{ 1909{
1910 wm831x_otp_exit(wm831x); 1910 wm831x_otp_exit(wm831x);
1911 mfd_remove_devices(wm831x->dev); 1911 mfd_remove_devices(wm831x->dev);
1912 if (wm831x->irq_base) 1912 free_irq(wm831x_irq(wm831x, WM831X_IRQ_AUXADC_DATA), wm831x);
1913 free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x);
1914 wm831x_irq_exit(wm831x); 1913 wm831x_irq_exit(wm831x);
1915} 1914}
1916 1915
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c
index 2be9628074bd..ecc9d6d62fad 100644
--- a/drivers/mfd/wm831x-irq.c
+++ b/drivers/mfd/wm831x-irq.c
@@ -18,6 +18,7 @@
18#include <linux/irq.h> 18#include <linux/irq.h>
19#include <linux/mfd/core.h> 19#include <linux/mfd/core.h>
20#include <linux/interrupt.h> 20#include <linux/interrupt.h>
21#include <linux/irqdomain.h>
21 22
22#include <linux/mfd/wm831x/core.h> 23#include <linux/mfd/wm831x/core.h>
23#include <linux/mfd/wm831x/pdata.h> 24#include <linux/mfd/wm831x/pdata.h>
@@ -328,7 +329,7 @@ static inline int irq_data_to_status_reg(struct wm831x_irq_data *irq_data)
328static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x, 329static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x,
329 int irq) 330 int irq)
330{ 331{
331 return &wm831x_irqs[irq - wm831x->irq_base]; 332 return &wm831x_irqs[irq];
332} 333}
333 334
334static void wm831x_irq_lock(struct irq_data *data) 335static void wm831x_irq_lock(struct irq_data *data)
@@ -374,7 +375,7 @@ static void wm831x_irq_enable(struct irq_data *data)
374{ 375{
375 struct wm831x *wm831x = irq_data_get_irq_chip_data(data); 376 struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
376 struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, 377 struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
377 data->irq); 378 data->hwirq);
378 379
379 wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; 380 wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
380} 381}
@@ -383,7 +384,7 @@ static void wm831x_irq_disable(struct irq_data *data)
383{ 384{
384 struct wm831x *wm831x = irq_data_get_irq_chip_data(data); 385 struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
385 struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, 386 struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
386 data->irq); 387 data->hwirq);
387 388
388 wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; 389 wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
389} 390}
@@ -393,7 +394,7 @@ static int wm831x_irq_set_type(struct irq_data *data, unsigned int type)
393 struct wm831x *wm831x = irq_data_get_irq_chip_data(data); 394 struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
394 int irq; 395 int irq;
395 396
396 irq = data->irq - wm831x->irq_base; 397 irq = data->hwirq;
397 398
398 if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) { 399 if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) {
399 /* Ignore internal-only IRQs */ 400 /* Ignore internal-only IRQs */
@@ -469,9 +470,11 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
469 * descriptors. 470 * descriptors.
470 */ 471 */
471 if (primary & WM831X_TCHPD_INT) 472 if (primary & WM831X_TCHPD_INT)
472 handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHPD); 473 handle_nested_irq(irq_find_mapping(wm831x->irq_domain,
474 WM831X_IRQ_TCHPD));
473 if (primary & WM831X_TCHDATA_INT) 475 if (primary & WM831X_TCHDATA_INT)
474 handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHDATA); 476 handle_nested_irq(irq_find_mapping(wm831x->irq_domain,
477 WM831X_IRQ_TCHDATA));
475 primary &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT); 478 primary &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT);
476 479
477 for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { 480 for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) {
@@ -507,7 +510,8 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
507 } 510 }
508 511
509 if (*status & wm831x_irqs[i].mask) 512 if (*status & wm831x_irqs[i].mask)
510 handle_nested_irq(wm831x->irq_base + i); 513 handle_nested_irq(irq_find_mapping(wm831x->irq_domain,
514 i));
511 515
512 /* Simulate an edge triggered IRQ by polling the input 516 /* Simulate an edge triggered IRQ by polling the input
513 * status. This is sucky but improves interoperability. 517 * status. This is sucky but improves interoperability.
@@ -516,7 +520,8 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
516 wm831x->gpio_level[i - WM831X_IRQ_GPIO_1]) { 520 wm831x->gpio_level[i - WM831X_IRQ_GPIO_1]) {
517 ret = wm831x_reg_read(wm831x, WM831X_GPIO_LEVEL); 521 ret = wm831x_reg_read(wm831x, WM831X_GPIO_LEVEL);
518 while (ret & 1 << (i - WM831X_IRQ_GPIO_1)) { 522 while (ret & 1 << (i - WM831X_IRQ_GPIO_1)) {
519 handle_nested_irq(wm831x->irq_base + i); 523 handle_nested_irq(irq_find_mapping(wm831x->irq_domain,
524 i));
520 ret = wm831x_reg_read(wm831x, 525 ret = wm831x_reg_read(wm831x,
521 WM831X_GPIO_LEVEL); 526 WM831X_GPIO_LEVEL);
522 } 527 }
@@ -527,10 +532,34 @@ out:
527 return IRQ_HANDLED; 532 return IRQ_HANDLED;
528} 533}
529 534
535static int wm831x_irq_map(struct irq_domain *h, unsigned int virq,
536 irq_hw_number_t hw)
537{
538 irq_set_chip_data(virq, h->host_data);
539 irq_set_chip_and_handler(virq, &wm831x_irq_chip, handle_edge_irq);
540 irq_set_nested_thread(virq, 1);
541
542 /* ARM needs us to explicitly flag the IRQ as valid
543 * and will set them noprobe when we do so. */
544#ifdef CONFIG_ARM
545 set_irq_flags(virq, IRQF_VALID);
546#else
547 irq_set_noprobe(virq);
548#endif
549
550 return 0;
551}
552
553static struct irq_domain_ops wm831x_irq_domain_ops = {
554 .map = wm831x_irq_map,
555 .xlate = irq_domain_xlate_twocell,
556};
557
530int wm831x_irq_init(struct wm831x *wm831x, int irq) 558int wm831x_irq_init(struct wm831x *wm831x, int irq)
531{ 559{
532 struct wm831x_pdata *pdata = wm831x->dev->platform_data; 560 struct wm831x_pdata *pdata = wm831x->dev->platform_data;
533 int i, cur_irq, ret; 561 struct irq_domain *domain;
562 int i, ret, irq_base;
534 563
535 mutex_init(&wm831x->irq_lock); 564 mutex_init(&wm831x->irq_lock);
536 565
@@ -543,18 +572,33 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
543 } 572 }
544 573
545 /* Try to dynamically allocate IRQs if no base is specified */ 574 /* Try to dynamically allocate IRQs if no base is specified */
546 if (!pdata || !pdata->irq_base) 575 if (pdata && pdata->irq_base) {
547 wm831x->irq_base = -1; 576 irq_base = irq_alloc_descs(pdata->irq_base, 0,
577 WM831X_NUM_IRQS, 0);
578 if (irq_base < 0) {
579 dev_warn(wm831x->dev, "Failed to allocate IRQs: %d\n",
580 irq_base);
581 irq_base = 0;
582 }
583 } else {
584 irq_base = 0;
585 }
586
587 if (irq_base)
588 domain = irq_domain_add_legacy(wm831x->dev->of_node,
589 ARRAY_SIZE(wm831x_irqs),
590 irq_base, 0,
591 &wm831x_irq_domain_ops,
592 wm831x);
548 else 593 else
549 wm831x->irq_base = pdata->irq_base; 594 domain = irq_domain_add_linear(wm831x->dev->of_node,
595 ARRAY_SIZE(wm831x_irqs),
596 &wm831x_irq_domain_ops,
597 wm831x);
550 598
551 wm831x->irq_base = irq_alloc_descs(wm831x->irq_base, 0, 599 if (!domain) {
552 WM831X_NUM_IRQS, 0); 600 dev_warn(wm831x->dev, "Failed to allocate IRQ domain\n");
553 if (wm831x->irq_base < 0) { 601 return -EINVAL;
554 dev_warn(wm831x->dev, "Failed to allocate IRQs: %d\n",
555 wm831x->irq_base);
556 wm831x->irq_base = 0;
557 return 0;
558 } 602 }
559 603
560 if (pdata && pdata->irq_cmos) 604 if (pdata && pdata->irq_cmos)
@@ -566,24 +610,7 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
566 WM831X_IRQ_OD, i); 610 WM831X_IRQ_OD, i);
567 611
568 wm831x->irq = irq; 612 wm831x->irq = irq;
569 613 wm831x->irq_domain = domain;
570 /* Register them with genirq */
571 for (cur_irq = wm831x->irq_base;
572 cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base;
573 cur_irq++) {
574 irq_set_chip_data(cur_irq, wm831x);
575 irq_set_chip_and_handler(cur_irq, &wm831x_irq_chip,
576 handle_edge_irq);
577 irq_set_nested_thread(cur_irq, 1);
578
579 /* ARM needs us to explicitly flag the IRQ as valid
580 * and will set them noprobe when we do so. */
581#ifdef CONFIG_ARM
582 set_irq_flags(cur_irq, IRQF_VALID);
583#else
584 irq_set_noprobe(cur_irq);
585#endif
586 }
587 614
588 if (irq) { 615 if (irq) {
589 /* Try to flag /IRQ as a wake source; there are a number of 616 /* Try to flag /IRQ as a wake source; there are a number of