Skip to content

Commit e0d8972

Browse files
thierryredingLinus Walleij
authored andcommitted
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 <[email protected]> Acked-by: Grygorii Strashko <[email protected]> Signed-off-by: Linus Walleij <[email protected]>
1 parent ca9df05 commit e0d8972

File tree

2 files changed

+114
-1
lines changed

2 files changed

+114
-1
lines changed

drivers/gpio/gpiolib.c

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ static LIST_HEAD(gpio_lookup_list);
7272
LIST_HEAD(gpio_devices);
7373

7474
static void gpiochip_free_hogs(struct gpio_chip *chip);
75+
static int gpiochip_add_irqchip(struct gpio_chip *gpiochip);
7576
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
7677
static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip);
7778
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)
12661267
if (status)
12671268
goto err_remove_from_list;
12681269

1270+
status = gpiochip_add_irqchip(chip);
1271+
if (status)
1272+
goto err_remove_chip;
1273+
12691274
status = of_gpiochip_add(chip);
12701275
if (status)
12711276
goto err_remove_chip;
@@ -1637,6 +1642,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
16371642
irq_hw_number_t hwirq)
16381643
{
16391644
struct gpio_chip *chip = d->host_data;
1645+
int err = 0;
16401646

16411647
if (!gpiochip_irqchip_irq_valid(chip, hwirq))
16421648
return -ENXIO;
@@ -1653,6 +1659,14 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
16531659
irq_set_nested_thread(irq, 1);
16541660
irq_set_noprobe(irq);
16551661

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+
16561670
/*
16571671
* No set-up of the hardware will happen if IRQ_TYPE_NONE
16581672
* is passed as default type.
@@ -1709,9 +1723,96 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
17091723
{
17101724
if (!gpiochip_irqchip_irq_valid(chip, offset))
17111725
return -ENXIO;
1726+
17121727
return irq_create_mapping(chip->irq.domain, offset);
17131728
}
17141729

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+
17151816
/**
17161817
* gpiochip_irqchip_remove() - removes an irqchip added to a gpiochip
17171818
* @gpiochip: the gpiochip to remove the irqchip from
@@ -1724,7 +1825,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
17241825

17251826
acpi_gpiochip_free_interrupts(gpiochip);
17261827

1727-
if (gpiochip->irq.num_parents > 0) {
1828+
if (gpiochip->irq.chip && gpiochip->irq.parent_handler) {
17281829
struct gpio_irq_chip *irq = &gpiochip->irq;
17291830
unsigned int i;
17301831

@@ -1857,6 +1958,11 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
18571958

18581959
#else /* CONFIG_GPIOLIB_IRQCHIP */
18591960

1961+
static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
1962+
{
1963+
return 0;
1964+
}
1965+
18601966
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {}
18611967
static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
18621968
{

include/linux/gpio/driver.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ struct gpio_irq_chip {
100100
*/
101101
unsigned int *parents;
102102

103+
/**
104+
* @map:
105+
*
106+
* A list of interrupt parents for each line of a GPIO chip.
107+
*/
108+
unsigned int *map;
109+
103110
/**
104111
* @nested:
105112
*

0 commit comments

Comments
 (0)