aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib.c
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2014-03-28 15:42:01 -0400
committerLinus Walleij <linus.walleij@linaro.org>2014-03-28 15:42:01 -0400
commitc3626fdea044cc97bfc035ebb048f7619acb6736 (patch)
tree4616758a56f3b3cef5303e511d2087d2e5eadfec /drivers/gpio/gpiolib.c
parent2ddf6cd67cc561e40454d60126a8a7cb32f3328f (diff)
gpio: unmap gpio irqs properly
When using the irqchip helper inside the gpiolib, make sure the IRQs are unmapped/disposed before the irqdomain is removed as part of removing the gpiochip. Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r--drivers/gpio/gpiolib.c33
1 files changed, 29 insertions, 4 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f41cb4f3d715..761013f8b82f 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1399,8 +1399,18 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
1399 return 0; 1399 return 0;
1400} 1400}
1401 1401
1402static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
1403{
1404#ifdef CONFIG_ARM
1405 set_irq_flags(irq, 0);
1406#endif
1407 irq_set_chip_and_handler(irq, NULL, NULL);
1408 irq_set_chip_data(irq, NULL);
1409}
1410
1402static const struct irq_domain_ops gpiochip_domain_ops = { 1411static const struct irq_domain_ops gpiochip_domain_ops = {
1403 .map = gpiochip_irq_map, 1412 .map = gpiochip_irq_map,
1413 .unmap = gpiochip_irq_unmap,
1404 /* Virtually all GPIO irqchips are twocell:ed */ 1414 /* Virtually all GPIO irqchips are twocell:ed */
1405 .xlate = irq_domain_xlate_twocell, 1415 .xlate = irq_domain_xlate_twocell,
1406}; 1416};
@@ -1438,8 +1448,14 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
1438 */ 1448 */
1439static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) 1449static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
1440{ 1450{
1441 if (gpiochip->irqdomain) 1451 unsigned int offset;
1452
1453 /* Remove all IRQ mappings and delete the domain */
1454 if (gpiochip->irqdomain) {
1455 for (offset = 0; offset < gpiochip->ngpio; offset++)
1456 irq_dispose_mapping(gpiochip->irq_base + offset);
1442 irq_domain_remove(gpiochip->irqdomain); 1457 irq_domain_remove(gpiochip->irqdomain);
1458 }
1443 1459
1444 if (gpiochip->irqchip) { 1460 if (gpiochip->irqchip) {
1445 gpiochip->irqchip->irq_request_resources = NULL; 1461 gpiochip->irqchip->irq_request_resources = NULL;
@@ -1467,7 +1483,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
1467 * translation. The gpiochip will need to be initialized and registered 1483 * translation. The gpiochip will need to be initialized and registered
1468 * before calling this function. 1484 * before calling this function.
1469 * 1485 *
1470 * This function will handle two cell:ed simple IRQs. Everything else 1486 * This function will handle two cell:ed simple IRQs and assumes all
1487 * the pins on the gpiochip can generate a unique IRQ. Everything else
1471 * need to be open coded. 1488 * need to be open coded.
1472 */ 1489 */
1473int gpiochip_irqchip_add(struct gpio_chip *gpiochip, 1490int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
@@ -1478,6 +1495,7 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
1478{ 1495{
1479 struct device_node *of_node; 1496 struct device_node *of_node;
1480 unsigned int offset; 1497 unsigned int offset;
1498 unsigned irq_base = 0;
1481 1499
1482 if (!gpiochip || !irqchip) 1500 if (!gpiochip || !irqchip)
1483 return -EINVAL; 1501 return -EINVAL;
@@ -1514,8 +1532,15 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
1514 * any gpiochip calls. If the first_irq was zero, this is 1532 * any gpiochip calls. If the first_irq was zero, this is
1515 * necessary to allocate descriptors for all IRQs. 1533 * necessary to allocate descriptors for all IRQs.
1516 */ 1534 */
1517 for (offset = 0; offset < gpiochip->ngpio; offset++) 1535 for (offset = 0; offset < gpiochip->ngpio; offset++) {
1518 irq_create_mapping(gpiochip->irqdomain, offset); 1536 irq_base = irq_create_mapping(gpiochip->irqdomain, offset);
1537 if (offset == 0)
1538 /*
1539 * Store the base into the gpiochip to be used when
1540 * unmapping the irqs.
1541 */
1542 gpiochip->irq_base = irq_base;
1543 }
1519 1544
1520 return 0; 1545 return 0;
1521} 1546}