Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+30 -4
+29 -4
drivers/gpio/gpiolib.c
··· 1399 1399 return 0; 1400 1400 } 1401 1401 1402 + static 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 + 1402 1411 static const struct irq_domain_ops gpiochip_domain_ops = { 1403 1412 .map = gpiochip_irq_map, 1413 + .unmap = gpiochip_irq_unmap, 1404 1414 /* Virtually all GPIO irqchips are twocell:ed */ 1405 1415 .xlate = irq_domain_xlate_twocell, 1406 1416 }; ··· 1448 1438 */ 1449 1439 static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) 1450 1440 { 1451 - if (gpiochip->irqdomain) 1441 + unsigned int offset; 1442 + 1443 + /* Remove all IRQ mappings and delete the domain */ 1444 + if (gpiochip->irqdomain) { 1445 + for (offset = 0; offset < gpiochip->ngpio; offset++) 1446 + irq_dispose_mapping(gpiochip->irq_base + offset); 1452 1447 irq_domain_remove(gpiochip->irqdomain); 1448 + } 1453 1449 1454 1450 if (gpiochip->irqchip) { 1455 1451 gpiochip->irqchip->irq_request_resources = NULL; ··· 1483 1467 * translation. The gpiochip will need to be initialized and registered 1484 1468 * before calling this function. 1485 1469 * 1486 - * This function will handle two cell:ed simple IRQs. Everything else 1470 + * This function will handle two cell:ed simple IRQs and assumes all 1471 + * the pins on the gpiochip can generate a unique IRQ. Everything else 1487 1472 * need to be open coded. 1488 1473 */ 1489 1474 int gpiochip_irqchip_add(struct gpio_chip *gpiochip, ··· 1495 1478 { 1496 1479 struct device_node *of_node; 1497 1480 unsigned int offset; 1481 + unsigned irq_base = 0; 1498 1482 1499 1483 if (!gpiochip || !irqchip) 1500 1484 return -EINVAL; ··· 1532 1514 * any gpiochip calls. If the first_irq was zero, this is 1533 1515 * necessary to allocate descriptors for all IRQs. 1534 1516 */ 1535 - for (offset = 0; offset < gpiochip->ngpio; offset++) 1536 - irq_create_mapping(gpiochip->irqdomain, offset); 1517 + for (offset = 0; offset < gpiochip->ngpio; offset++) { 1518 + irq_base = irq_create_mapping(gpiochip->irqdomain, offset); 1519 + if (offset == 0) 1520 + /* 1521 + * Store the base into the gpiochip to be used when 1522 + * unmapping the irqs. 1523 + */ 1524 + gpiochip->irq_base = irq_base; 1525 + } 1537 1526 1538 1527 return 0; 1539 1528 }
+1
include/linux/gpio/driver.h
··· 107 107 */ 108 108 struct irq_chip *irqchip; 109 109 struct irq_domain *irqdomain; 110 + unsigned int irq_base; 110 111 irq_flow_handler_t irq_handler; 111 112 unsigned int irq_default_type; 112 113 #endif