diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2016-09-23 08:51:18 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2016-09-23 08:51:18 -0400 |
commit | 22a5db98a30ea734c29056b0d59cb4fe2a383bc2 (patch) | |
tree | d1d5b3ee914e95f00b917ebf48b59fe8331a5734 | |
parent | 9132ce450bd141cd8c5776b41e90f146cae4bc3b (diff) | |
parent | 79b804cb6af4f128b2c53f0887c02537a7eb5824 (diff) |
Merge branch 'gpio-irq-validmask' of /home/linus/linux-pinctrl into devel
-rw-r--r-- | Documentation/gpio/driver.txt | 6 | ||||
-rw-r--r-- | drivers/gpio/gpiolib.c | 66 | ||||
-rw-r--r-- | include/linux/gpio/driver.h | 6 |
3 files changed, 75 insertions, 3 deletions
diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt index 6cb35a78eff4..368d5a294d89 100644 --- a/Documentation/gpio/driver.txt +++ b/Documentation/gpio/driver.txt | |||
@@ -262,6 +262,12 @@ symbol: | |||
262 | to the container using container_of(). | 262 | to the container using container_of(). |
263 | (See Documentation/driver-model/design-patterns.txt) | 263 | (See Documentation/driver-model/design-patterns.txt) |
264 | 264 | ||
265 | If there is a need to exclude certain GPIOs from the IRQ domain, one can | ||
266 | set .irq_need_valid_mask of the gpiochip before gpiochip_add_data() is | ||
267 | called. This allocates .irq_valid_mask with as many bits set as there are | ||
268 | GPIOs in the chip. Drivers can exclude GPIOs by clearing bits from this | ||
269 | mask. The mask must be filled in before gpiochip_irqchip_add() is called. | ||
270 | |||
265 | * gpiochip_set_chained_irqchip(): sets up a chained irq handler for a | 271 | * gpiochip_set_chained_irqchip(): sets up a chained irq handler for a |
266 | gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler | 272 | gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler |
267 | data. (Notice handler data, since the irqchip data is likely used by the | 273 | data. (Notice handler data, since the irqchip data is likely used by the |
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 043128d3e831..19a665f8d455 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c | |||
@@ -71,6 +71,8 @@ LIST_HEAD(gpio_devices); | |||
71 | 71 | ||
72 | static void gpiochip_free_hogs(struct gpio_chip *chip); | 72 | static void gpiochip_free_hogs(struct gpio_chip *chip); |
73 | static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); | 73 | static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); |
74 | static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip); | ||
75 | static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip); | ||
74 | 76 | ||
75 | static bool gpiolib_initialized; | 77 | static bool gpiolib_initialized; |
76 | 78 | ||
@@ -1167,6 +1169,10 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data) | |||
1167 | if (status) | 1169 | if (status) |
1168 | goto err_remove_from_list; | 1170 | goto err_remove_from_list; |
1169 | 1171 | ||
1172 | status = gpiochip_irqchip_init_valid_mask(chip); | ||
1173 | if (status) | ||
1174 | goto err_remove_from_list; | ||
1175 | |||
1170 | status = of_gpiochip_add(chip); | 1176 | status = of_gpiochip_add(chip); |
1171 | if (status) | 1177 | if (status) |
1172 | goto err_remove_chip; | 1178 | goto err_remove_chip; |
@@ -1192,6 +1198,7 @@ err_remove_chip: | |||
1192 | acpi_gpiochip_remove(chip); | 1198 | acpi_gpiochip_remove(chip); |
1193 | gpiochip_free_hogs(chip); | 1199 | gpiochip_free_hogs(chip); |
1194 | of_gpiochip_remove(chip); | 1200 | of_gpiochip_remove(chip); |
1201 | gpiochip_irqchip_free_valid_mask(chip); | ||
1195 | err_remove_from_list: | 1202 | err_remove_from_list: |
1196 | spin_lock_irqsave(&gpio_lock, flags); | 1203 | spin_lock_irqsave(&gpio_lock, flags); |
1197 | list_del(&gdev->list); | 1204 | list_del(&gdev->list); |
@@ -1397,6 +1404,40 @@ static struct gpio_chip *find_chip_by_name(const char *name) | |||
1397 | * The following is irqchip helper code for gpiochips. | 1404 | * The following is irqchip helper code for gpiochips. |
1398 | */ | 1405 | */ |
1399 | 1406 | ||
1407 | static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip) | ||
1408 | { | ||
1409 | int i; | ||
1410 | |||
1411 | if (!gpiochip->irq_need_valid_mask) | ||
1412 | return 0; | ||
1413 | |||
1414 | gpiochip->irq_valid_mask = kcalloc(BITS_TO_LONGS(gpiochip->ngpio), | ||
1415 | sizeof(long), GFP_KERNEL); | ||
1416 | if (!gpiochip->irq_valid_mask) | ||
1417 | return -ENOMEM; | ||
1418 | |||
1419 | /* Assume by default all GPIOs are valid */ | ||
1420 | for (i = 0; i < gpiochip->ngpio; i++) | ||
1421 | set_bit(i, gpiochip->irq_valid_mask); | ||
1422 | |||
1423 | return 0; | ||
1424 | } | ||
1425 | |||
1426 | static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip) | ||
1427 | { | ||
1428 | kfree(gpiochip->irq_valid_mask); | ||
1429 | gpiochip->irq_valid_mask = NULL; | ||
1430 | } | ||
1431 | |||
1432 | static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, | ||
1433 | unsigned int offset) | ||
1434 | { | ||
1435 | /* No mask means all valid */ | ||
1436 | if (likely(!gpiochip->irq_valid_mask)) | ||
1437 | return true; | ||
1438 | return test_bit(offset, gpiochip->irq_valid_mask); | ||
1439 | } | ||
1440 | |||
1400 | /** | 1441 | /** |
1401 | * gpiochip_set_chained_irqchip() - sets a chained irqchip to a gpiochip | 1442 | * gpiochip_set_chained_irqchip() - sets a chained irqchip to a gpiochip |
1402 | * @gpiochip: the gpiochip to set the irqchip chain to | 1443 | * @gpiochip: the gpiochip to set the irqchip chain to |
@@ -1438,9 +1479,12 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, | |||
1438 | } | 1479 | } |
1439 | 1480 | ||
1440 | /* Set the parent IRQ for all affected IRQs */ | 1481 | /* Set the parent IRQ for all affected IRQs */ |
1441 | for (offset = 0; offset < gpiochip->ngpio; offset++) | 1482 | for (offset = 0; offset < gpiochip->ngpio; offset++) { |
1483 | if (!gpiochip_irqchip_irq_valid(gpiochip, offset)) | ||
1484 | continue; | ||
1442 | irq_set_parent(irq_find_mapping(gpiochip->irqdomain, offset), | 1485 | irq_set_parent(irq_find_mapping(gpiochip->irqdomain, offset), |
1443 | parent_irq); | 1486 | parent_irq); |
1487 | } | ||
1444 | } | 1488 | } |
1445 | EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); | 1489 | EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); |
1446 | 1490 | ||
@@ -1547,9 +1591,12 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) | |||
1547 | 1591 | ||
1548 | /* Remove all IRQ mappings and delete the domain */ | 1592 | /* Remove all IRQ mappings and delete the domain */ |
1549 | if (gpiochip->irqdomain) { | 1593 | if (gpiochip->irqdomain) { |
1550 | for (offset = 0; offset < gpiochip->ngpio; offset++) | 1594 | for (offset = 0; offset < gpiochip->ngpio; offset++) { |
1595 | if (!gpiochip_irqchip_irq_valid(gpiochip, offset)) | ||
1596 | continue; | ||
1551 | irq_dispose_mapping( | 1597 | irq_dispose_mapping( |
1552 | irq_find_mapping(gpiochip->irqdomain, offset)); | 1598 | irq_find_mapping(gpiochip->irqdomain, offset)); |
1599 | } | ||
1553 | irq_domain_remove(gpiochip->irqdomain); | 1600 | irq_domain_remove(gpiochip->irqdomain); |
1554 | } | 1601 | } |
1555 | 1602 | ||
@@ -1558,6 +1605,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) | |||
1558 | gpiochip->irqchip->irq_release_resources = NULL; | 1605 | gpiochip->irqchip->irq_release_resources = NULL; |
1559 | gpiochip->irqchip = NULL; | 1606 | gpiochip->irqchip = NULL; |
1560 | } | 1607 | } |
1608 | |||
1609 | gpiochip_irqchip_free_valid_mask(gpiochip); | ||
1561 | } | 1610 | } |
1562 | 1611 | ||
1563 | /** | 1612 | /** |
@@ -1593,6 +1642,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, | |||
1593 | struct lock_class_key *lock_key) | 1642 | struct lock_class_key *lock_key) |
1594 | { | 1643 | { |
1595 | struct device_node *of_node; | 1644 | struct device_node *of_node; |
1645 | bool irq_base_set = false; | ||
1596 | unsigned int offset; | 1646 | unsigned int offset; |
1597 | unsigned irq_base = 0; | 1647 | unsigned irq_base = 0; |
1598 | 1648 | ||
@@ -1656,13 +1706,17 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, | |||
1656 | * necessary to allocate descriptors for all IRQs. | 1706 | * necessary to allocate descriptors for all IRQs. |
1657 | */ | 1707 | */ |
1658 | for (offset = 0; offset < gpiochip->ngpio; offset++) { | 1708 | for (offset = 0; offset < gpiochip->ngpio; offset++) { |
1709 | if (!gpiochip_irqchip_irq_valid(gpiochip, offset)) | ||
1710 | continue; | ||
1659 | irq_base = irq_create_mapping(gpiochip->irqdomain, offset); | 1711 | irq_base = irq_create_mapping(gpiochip->irqdomain, offset); |
1660 | if (offset == 0) | 1712 | if (!irq_base_set) { |
1661 | /* | 1713 | /* |
1662 | * Store the base into the gpiochip to be used when | 1714 | * Store the base into the gpiochip to be used when |
1663 | * unmapping the irqs. | 1715 | * unmapping the irqs. |
1664 | */ | 1716 | */ |
1665 | gpiochip->irq_base = irq_base; | 1717 | gpiochip->irq_base = irq_base; |
1718 | irq_base_set = true; | ||
1719 | } | ||
1666 | } | 1720 | } |
1667 | 1721 | ||
1668 | acpi_gpiochip_request_interrupts(gpiochip); | 1722 | acpi_gpiochip_request_interrupts(gpiochip); |
@@ -1674,6 +1728,12 @@ EXPORT_SYMBOL_GPL(_gpiochip_irqchip_add); | |||
1674 | #else /* CONFIG_GPIOLIB_IRQCHIP */ | 1728 | #else /* CONFIG_GPIOLIB_IRQCHIP */ |
1675 | 1729 | ||
1676 | static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {} | 1730 | static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {} |
1731 | static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip) | ||
1732 | { | ||
1733 | return 0; | ||
1734 | } | ||
1735 | static inline void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip) | ||
1736 | { } | ||
1677 | 1737 | ||
1678 | #endif /* CONFIG_GPIOLIB_IRQCHIP */ | 1738 | #endif /* CONFIG_GPIOLIB_IRQCHIP */ |
1679 | 1739 | ||
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 216e6f275aa8..1f0be7213e6d 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h | |||
@@ -112,6 +112,10 @@ enum single_ended_mode { | |||
112 | * initialization, provided by GPIO driver | 112 | * initialization, provided by GPIO driver |
113 | * @irq_parent: GPIO IRQ chip parent/bank linux irq number, | 113 | * @irq_parent: GPIO IRQ chip parent/bank linux irq number, |
114 | * provided by GPIO driver | 114 | * provided by GPIO driver |
115 | * @irq_need_valid_mask: If set core allocates @irq_valid_mask with all | ||
116 | * bits set to one | ||
117 | * @irq_valid_mask: If not %NULL holds bitmask of GPIOs which are valid to | ||
118 | * be included in IRQ domain of the chip | ||
115 | * @lock_key: per GPIO IRQ chip lockdep class | 119 | * @lock_key: per GPIO IRQ chip lockdep class |
116 | * | 120 | * |
117 | * A gpio_chip can help platforms abstract various sources of GPIOs so | 121 | * A gpio_chip can help platforms abstract various sources of GPIOs so |
@@ -190,6 +194,8 @@ struct gpio_chip { | |||
190 | irq_flow_handler_t irq_handler; | 194 | irq_flow_handler_t irq_handler; |
191 | unsigned int irq_default_type; | 195 | unsigned int irq_default_type; |
192 | int irq_parent; | 196 | int irq_parent; |
197 | bool irq_need_valid_mask; | ||
198 | unsigned long *irq_valid_mask; | ||
193 | struct lock_class_key *lock_key; | 199 | struct lock_class_key *lock_key; |
194 | #endif | 200 | #endif |
195 | 201 | ||