diff options
author | Thierry Reding <treding@nvidia.com> | 2017-11-07 13:15:54 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2017-11-08 08:12:01 -0500 |
commit | e0d89728981393b7d694bd3419b7794b9882c92d (patch) | |
tree | 4e8a009a3d71898f3ba4db28b32425cac190b883 | |
parent | ca9df053fb2bb2fcc64f37a1668321c7e19edd04 (diff) |
gpio: Implement tighter IRQ chip integration
Currently GPIO drivers are required to add the GPIO chip and its
corresponding IRQ chip separately, which can result in a lot of
boilerplate. Use the newly introduced struct gpio_irq_chip, embedded in
struct gpio_chip, that drivers can fill in if they want the GPIO core
to automatically register the IRQ chip associated with a GPIO chip.
Signed-off-by: Thierry Reding <treding@nvidia.com>
Acked-by: Grygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r-- | drivers/gpio/gpiolib.c | 108 | ||||
-rw-r--r-- | include/linux/gpio/driver.h | 7 |
2 files changed, 114 insertions, 1 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 685a05caf1ba..003d1bb85165 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c | |||
@@ -72,6 +72,7 @@ static LIST_HEAD(gpio_lookup_list); | |||
72 | LIST_HEAD(gpio_devices); | 72 | LIST_HEAD(gpio_devices); |
73 | 73 | ||
74 | static void gpiochip_free_hogs(struct gpio_chip *chip); | 74 | static void gpiochip_free_hogs(struct gpio_chip *chip); |
75 | static int gpiochip_add_irqchip(struct gpio_chip *gpiochip); | ||
75 | static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); | 76 | static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); |
76 | static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip); | 77 | static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip); |
77 | static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip); | 78 | static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip); |
@@ -1266,6 +1267,10 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data) | |||
1266 | if (status) | 1267 | if (status) |
1267 | goto err_remove_from_list; | 1268 | goto err_remove_from_list; |
1268 | 1269 | ||
1270 | status = gpiochip_add_irqchip(chip); | ||
1271 | if (status) | ||
1272 | goto err_remove_chip; | ||
1273 | |||
1269 | status = of_gpiochip_add(chip); | 1274 | status = of_gpiochip_add(chip); |
1270 | if (status) | 1275 | if (status) |
1271 | goto err_remove_chip; | 1276 | goto err_remove_chip; |
@@ -1637,6 +1642,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, | |||
1637 | irq_hw_number_t hwirq) | 1642 | irq_hw_number_t hwirq) |
1638 | { | 1643 | { |
1639 | struct gpio_chip *chip = d->host_data; | 1644 | struct gpio_chip *chip = d->host_data; |
1645 | int err = 0; | ||
1640 | 1646 | ||
1641 | if (!gpiochip_irqchip_irq_valid(chip, hwirq)) | 1647 | if (!gpiochip_irqchip_irq_valid(chip, hwirq)) |
1642 | return -ENXIO; | 1648 | return -ENXIO; |
@@ -1653,6 +1659,14 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, | |||
1653 | irq_set_nested_thread(irq, 1); | 1659 | irq_set_nested_thread(irq, 1); |
1654 | irq_set_noprobe(irq); | 1660 | irq_set_noprobe(irq); |
1655 | 1661 | ||
1662 | if (chip->irq.num_parents == 1) | ||
1663 | err = irq_set_parent(irq, chip->irq.parents[0]); | ||
1664 | else if (chip->irq.map) | ||
1665 | err = irq_set_parent(irq, chip->irq.map[hwirq]); | ||
1666 | |||
1667 | if (err < 0) | ||
1668 | return err; | ||
1669 | |||
1656 | /* | 1670 | /* |
1657 | * No set-up of the hardware will happen if IRQ_TYPE_NONE | 1671 | * No set-up of the hardware will happen if IRQ_TYPE_NONE |
1658 | * is passed as default type. | 1672 | * is passed as default type. |
@@ -1709,10 +1723,97 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) | |||
1709 | { | 1723 | { |
1710 | if (!gpiochip_irqchip_irq_valid(chip, offset)) | 1724 | if (!gpiochip_irqchip_irq_valid(chip, offset)) |
1711 | return -ENXIO; | 1725 | return -ENXIO; |
1726 | |||
1712 | return irq_create_mapping(chip->irq.domain, offset); | 1727 | return irq_create_mapping(chip->irq.domain, offset); |
1713 | } | 1728 | } |
1714 | 1729 | ||
1715 | /** | 1730 | /** |
1731 | * gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip | ||
1732 | * @gpiochip: the GPIO chip to add the IRQ chip to | ||
1733 | */ | ||
1734 | static int gpiochip_add_irqchip(struct gpio_chip *gpiochip) | ||
1735 | { | ||
1736 | struct irq_chip *irqchip = gpiochip->irq.chip; | ||
1737 | const struct irq_domain_ops *ops; | ||
1738 | struct device_node *np; | ||
1739 | unsigned int type; | ||
1740 | unsigned int i; | ||
1741 | |||
1742 | if (!irqchip) | ||
1743 | return 0; | ||
1744 | |||
1745 | if (gpiochip->irq.parent_handler && gpiochip->can_sleep) { | ||
1746 | chip_err(gpiochip, "you cannot have chained interrupts on a " | ||
1747 | "chip that may sleep\n"); | ||
1748 | return -EINVAL; | ||
1749 | } | ||
1750 | |||
1751 | np = gpiochip->gpiodev->dev.of_node; | ||
1752 | type = gpiochip->irq.default_type; | ||
1753 | |||
1754 | /* | ||
1755 | * Specifying a default trigger is a terrible idea if DT or ACPI is | ||
1756 | * used to configure the interrupts, as you may end up with | ||
1757 | * conflicting triggers. Tell the user, and reset to NONE. | ||
1758 | */ | ||
1759 | if (WARN(np && type != IRQ_TYPE_NONE, | ||
1760 | "%s: Ignoring %u default trigger\n", np->full_name, type)) | ||
1761 | type = IRQ_TYPE_NONE; | ||
1762 | |||
1763 | if (has_acpi_companion(gpiochip->parent) && type != IRQ_TYPE_NONE) { | ||
1764 | acpi_handle_warn(ACPI_HANDLE(gpiochip->parent), | ||
1765 | "Ignoring %u default trigger\n", type); | ||
1766 | type = IRQ_TYPE_NONE; | ||
1767 | } | ||
1768 | |||
1769 | gpiochip->to_irq = gpiochip_to_irq; | ||
1770 | gpiochip->irq.default_type = type; | ||
1771 | |||
1772 | if (gpiochip->irq.domain_ops) | ||
1773 | ops = gpiochip->irq.domain_ops; | ||
1774 | else | ||
1775 | ops = &gpiochip_domain_ops; | ||
1776 | |||
1777 | gpiochip->irq.domain = irq_domain_add_simple(np, gpiochip->ngpio, | ||
1778 | 0, ops, gpiochip); | ||
1779 | if (!gpiochip->irq.domain) | ||
1780 | return -EINVAL; | ||
1781 | |||
1782 | /* | ||
1783 | * It is possible for a driver to override this, but only if the | ||
1784 | * alternative functions are both implemented. | ||
1785 | */ | ||
1786 | if (!irqchip->irq_request_resources && | ||
1787 | !irqchip->irq_release_resources) { | ||
1788 | irqchip->irq_request_resources = gpiochip_irq_reqres; | ||
1789 | irqchip->irq_release_resources = gpiochip_irq_relres; | ||
1790 | } | ||
1791 | |||
1792 | if (gpiochip->irq.parent_handler) { | ||
1793 | void *data = gpiochip->irq.parent_handler_data ?: gpiochip; | ||
1794 | |||
1795 | for (i = 0; i < gpiochip->irq.num_parents; i++) { | ||
1796 | /* | ||
1797 | * The parent IRQ chip is already using the chip_data | ||
1798 | * for this IRQ chip, so our callbacks simply use the | ||
1799 | * handler_data. | ||
1800 | */ | ||
1801 | irq_set_chained_handler_and_data(gpiochip->irq.parents[i], | ||
1802 | gpiochip->irq.parent_handler, | ||
1803 | data); | ||
1804 | } | ||
1805 | |||
1806 | gpiochip->irq.nested = false; | ||
1807 | } else { | ||
1808 | gpiochip->irq.nested = true; | ||
1809 | } | ||
1810 | |||
1811 | acpi_gpiochip_request_interrupts(gpiochip); | ||
1812 | |||
1813 | return 0; | ||
1814 | } | ||
1815 | |||
1816 | /** | ||
1716 | * gpiochip_irqchip_remove() - removes an irqchip added to a gpiochip | 1817 | * gpiochip_irqchip_remove() - removes an irqchip added to a gpiochip |
1717 | * @gpiochip: the gpiochip to remove the irqchip from | 1818 | * @gpiochip: the gpiochip to remove the irqchip from |
1718 | * | 1819 | * |
@@ -1724,7 +1825,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) | |||
1724 | 1825 | ||
1725 | acpi_gpiochip_free_interrupts(gpiochip); | 1826 | acpi_gpiochip_free_interrupts(gpiochip); |
1726 | 1827 | ||
1727 | if (gpiochip->irq.num_parents > 0) { | 1828 | if (gpiochip->irq.chip && gpiochip->irq.parent_handler) { |
1728 | struct gpio_irq_chip *irq = &gpiochip->irq; | 1829 | struct gpio_irq_chip *irq = &gpiochip->irq; |
1729 | unsigned int i; | 1830 | unsigned int i; |
1730 | 1831 | ||
@@ -1857,6 +1958,11 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key); | |||
1857 | 1958 | ||
1858 | #else /* CONFIG_GPIOLIB_IRQCHIP */ | 1959 | #else /* CONFIG_GPIOLIB_IRQCHIP */ |
1859 | 1960 | ||
1961 | static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip) | ||
1962 | { | ||
1963 | return 0; | ||
1964 | } | ||
1965 | |||
1860 | static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {} | 1966 | static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {} |
1861 | static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip) | 1967 | static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip) |
1862 | { | 1968 | { |
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index c363ee198ff9..51fc7b023364 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h | |||
@@ -101,6 +101,13 @@ struct gpio_irq_chip { | |||
101 | unsigned int *parents; | 101 | unsigned int *parents; |
102 | 102 | ||
103 | /** | 103 | /** |
104 | * @map: | ||
105 | * | ||
106 | * A list of interrupt parents for each line of a GPIO chip. | ||
107 | */ | ||
108 | unsigned int *map; | ||
109 | |||
110 | /** | ||
104 | * @nested: | 111 | * @nested: |
105 | * | 112 | * |
106 | * True if set the interrupt handling is nested. | 113 | * True if set the interrupt handling is nested. |