Skip to content

Commit 1425052

Browse files
author
Linus Walleij
committed
gpio: add IRQ chip helpers in gpiolib
This provides a function gpiochip_irqchip_add() to set up an irqchip for a GPIO controller, and a function gpiochip_set_chained_irqchip() to chain it to a parent irqchip. Most GPIOs are of the type where a number of lines form a cascaded interrupt controller chained onto the primary system interrupt controller (or further down the chain) so let's add this helper and factor the code to request the lines to be used as IRQs, the .to_irq() function and the irqdomain into the core as well. Acked-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Alexandre Courbot <acourbot@nvidia.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
1 parent 8f18bcf commit 1425052

File tree

3 files changed

+220
-0
lines changed

3 files changed

+220
-0
lines changed

drivers/gpio/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ config GPIO_ACPI
5555
def_bool y
5656
depends on ACPI
5757

58+
config GPIOLIB_IRQCHIP
59+
bool
60+
5861
config DEBUG_GPIO
5962
bool "Debug GPIO calls"
6063
depends on DEBUG_KERNEL

drivers/gpio/gpiolib.c

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,6 +1254,9 @@ int gpiochip_add(struct gpio_chip *chip)
12541254
}
12551255
EXPORT_SYMBOL_GPL(gpiochip_add);
12561256

1257+
/* Forward-declaration */
1258+
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
1259+
12571260
/**
12581261
* gpiochip_remove() - unregister a gpio_chip
12591262
* @chip: the chip to unregister
@@ -1270,6 +1273,7 @@ int gpiochip_remove(struct gpio_chip *chip)
12701273

12711274
spin_lock_irqsave(&gpio_lock, flags);
12721275

1276+
gpiochip_irqchip_remove(chip);
12731277
gpiochip_remove_pin_ranges(chip);
12741278
of_gpiochip_remove(chip);
12751279

@@ -1339,6 +1343,190 @@ static struct gpio_chip *find_chip_by_name(const char *name)
13391343
return gpiochip_find((void *)name, gpiochip_match_name);
13401344
}
13411345

1346+
#ifdef CONFIG_GPIOLIB_IRQCHIP
1347+
1348+
/*
1349+
* The following is irqchip helper code for gpiochips.
1350+
*/
1351+
1352+
/**
1353+
* gpiochip_add_chained_irqchip() - adds a chained irqchip to a gpiochip
1354+
* @gpiochip: the gpiochip to add the irqchip to
1355+
* @irqchip: the irqchip to add to the gpiochip
1356+
* @parent_irq: the irq number corresponding to the parent IRQ for this
1357+
* chained irqchip
1358+
* @parent_handler: the parent interrupt handler for the accumulated IRQ
1359+
* coming out of the gpiochip
1360+
*/
1361+
void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
1362+
struct irq_chip *irqchip,
1363+
int parent_irq,
1364+
irq_flow_handler_t parent_handler)
1365+
{
1366+
irq_set_chained_handler(parent_irq, parent_handler);
1367+
/*
1368+
* The parent irqchip is already using the chip_data for this
1369+
* irqchip, so our callbacks simply use the handler_data.
1370+
*/
1371+
irq_set_handler_data(parent_irq, gpiochip);
1372+
}
1373+
EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
1374+
1375+
/**
1376+
* gpiochip_irq_map() - maps an IRQ into a GPIO irqchip
1377+
* @d: the irqdomain used by this irqchip
1378+
* @irq: the global irq number used by this GPIO irqchip irq
1379+
* @hwirq: the local IRQ/GPIO line offset on this gpiochip
1380+
*
1381+
* This function will set up the mapping for a certain IRQ line on a
1382+
* gpiochip by assigning the gpiochip as chip data, and using the irqchip
1383+
* stored inside the gpiochip.
1384+
*/
1385+
static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
1386+
irq_hw_number_t hwirq)
1387+
{
1388+
struct gpio_chip *chip = d->host_data;
1389+
1390+
irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler);
1391+
irq_set_chip_data(irq, chip);
1392+
#ifdef CONFIG_ARM
1393+
set_irq_flags(irq, IRQF_VALID);
1394+
#else
1395+
irq_set_noprobe(irq);
1396+
#endif
1397+
irq_set_irq_type(irq, chip->irq_default_type);
1398+
1399+
return 0;
1400+
}
1401+
1402+
static const struct irq_domain_ops gpiochip_domain_ops = {
1403+
.map = gpiochip_irq_map,
1404+
/* Virtually all GPIO irqchips are twocell:ed */
1405+
.xlate = irq_domain_xlate_twocell,
1406+
};
1407+
1408+
static int gpiochip_irq_reqres(struct irq_data *d)
1409+
{
1410+
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
1411+
1412+
if (gpio_lock_as_irq(chip, d->hwirq)) {
1413+
chip_err(chip,
1414+
"unable to lock HW IRQ %lu for IRQ\n",
1415+
d->hwirq);
1416+
return -EINVAL;
1417+
}
1418+
return 0;
1419+
}
1420+
1421+
static void gpiochip_irq_relres(struct irq_data *d)
1422+
{
1423+
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
1424+
1425+
gpio_unlock_as_irq(chip, d->hwirq);
1426+
}
1427+
1428+
static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
1429+
{
1430+
return irq_find_mapping(chip->irqdomain, offset);
1431+
}
1432+
1433+
/**
1434+
* gpiochip_irqchip_remove() - removes an irqchip added to a gpiochip
1435+
* @gpiochip: the gpiochip to remove the irqchip from
1436+
*
1437+
* This is called only from gpiochip_remove()
1438+
*/
1439+
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
1440+
{
1441+
if (gpiochip->irqdomain)
1442+
irq_domain_remove(gpiochip->irqdomain);
1443+
1444+
if (gpiochip->irqchip) {
1445+
gpiochip->irqchip->irq_request_resources = NULL;
1446+
gpiochip->irqchip->irq_release_resources = NULL;
1447+
gpiochip->irqchip = NULL;
1448+
}
1449+
}
1450+
1451+
/**
1452+
* gpiochip_irqchip_add() - adds an irqchip to a gpiochip
1453+
* @gpiochip: the gpiochip to add the irqchip to
1454+
* @irqchip: the irqchip to add to the gpiochip
1455+
* @first_irq: if not dynamically assigned, the base (first) IRQ to
1456+
* allocate gpiochip irqs from
1457+
* @handler: the irq handler to use (often a predefined irq core function)
1458+
* @type: the default type for IRQs on this irqchip
1459+
*
1460+
* This function closely associates a certain irqchip with a certain
1461+
* gpiochip, providing an irq domain to translate the local IRQs to
1462+
* global irqs in the gpiolib core, and making sure that the gpiochip
1463+
* is passed as chip data to all related functions. Driver callbacks
1464+
* need to use container_of() to get their local state containers back
1465+
* from the gpiochip passed as chip data. An irqdomain will be stored
1466+
* in the gpiochip that shall be used by the driver to handle IRQ number
1467+
* translation. The gpiochip will need to be initialized and registered
1468+
* before calling this function.
1469+
*
1470+
* This function will handle two cell:ed simple IRQs. Everything else
1471+
* need to be open coded.
1472+
*/
1473+
int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
1474+
struct irq_chip *irqchip,
1475+
unsigned int first_irq,
1476+
irq_flow_handler_t handler,
1477+
unsigned int type)
1478+
{
1479+
struct device_node *of_node;
1480+
unsigned int offset;
1481+
1482+
if (!gpiochip || !irqchip)
1483+
return -EINVAL;
1484+
1485+
if (!gpiochip->dev) {
1486+
pr_err("missing gpiochip .dev parent pointer\n");
1487+
return -EINVAL;
1488+
}
1489+
of_node = gpiochip->dev->of_node;
1490+
#ifdef CONFIG_OF_GPIO
1491+
/*
1492+
* If the gpiochip has an assigned OF node this takes precendence
1493+
* FIXME: get rid of this and use gpiochip->dev->of_node everywhere
1494+
*/
1495+
if (gpiochip->of_node)
1496+
of_node = gpiochip->of_node;
1497+
#endif
1498+
gpiochip->irqchip = irqchip;
1499+
gpiochip->irq_handler = handler;
1500+
gpiochip->irq_default_type = type;
1501+
gpiochip->to_irq = gpiochip_to_irq;
1502+
gpiochip->irqdomain = irq_domain_add_simple(of_node,
1503+
gpiochip->ngpio, first_irq,
1504+
&gpiochip_domain_ops, gpiochip);
1505+
if (!gpiochip->irqdomain) {
1506+
gpiochip->irqchip = NULL;
1507+
return -EINVAL;
1508+
}
1509+
irqchip->irq_request_resources = gpiochip_irq_reqres;
1510+
irqchip->irq_release_resources = gpiochip_irq_relres;
1511+
1512+
/*
1513+
* Prepare the mapping since the irqchip shall be orthogonal to
1514+
* any gpiochip calls. If the first_irq was zero, this is
1515+
* necessary to allocate descriptors for all IRQs.
1516+
*/
1517+
for (offset = 0; offset < gpiochip->ngpio; offset++)
1518+
irq_create_mapping(gpiochip->irqdomain, offset);
1519+
1520+
return 0;
1521+
}
1522+
EXPORT_SYMBOL_GPL(gpiochip_irqchip_add);
1523+
1524+
#else /* CONFIG_GPIOLIB_IRQCHIP */
1525+
1526+
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {}
1527+
1528+
#endif /* CONFIG_GPIOLIB_IRQCHIP */
1529+
13421530
#ifdef CONFIG_PINCTRL
13431531

13441532
/**

include/linux/gpio/driver.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
#include <linux/types.h>
55
#include <linux/module.h>
6+
#include <linux/irq.h>
7+
#include <linux/irqchip/chained_irq.h>
8+
#include <linux/irqdomain.h>
69

710
struct device;
811
struct gpio_desc;
@@ -97,6 +100,17 @@ struct gpio_chip {
97100
bool can_sleep;
98101
bool exported;
99102

103+
#ifdef CONFIG_GPIOLIB_IRQCHIP
104+
/*
105+
* With CONFIG_GPIO_IRQCHIP we get an irqchip inside the gpiolib
106+
* to handle IRQs for most practical cases.
107+
*/
108+
struct irq_chip *irqchip;
109+
struct irq_domain *irqdomain;
110+
irq_flow_handler_t irq_handler;
111+
unsigned int irq_default_type;
112+
#endif
113+
100114
#if defined(CONFIG_OF_GPIO)
101115
/*
102116
* If CONFIG_OF is enabled, then all GPIO controllers described in the
@@ -190,6 +204,21 @@ struct gpiod_lookup_table {
190204

191205
void gpiod_add_lookup_table(struct gpiod_lookup_table *table);
192206

207+
#ifdef CONFIG_GPIOLIB_IRQCHIP
208+
209+
void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
210+
struct irq_chip *irqchip,
211+
int parent_irq,
212+
irq_flow_handler_t parent_handler);
213+
214+
int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
215+
struct irq_chip *irqchip,
216+
unsigned int first_irq,
217+
irq_flow_handler_t handler,
218+
unsigned int type);
219+
220+
#endif /* CONFIG_GPIO_IRQCHIP */
221+
193222
#else /* CONFIG_GPIOLIB */
194223

195224
static inline struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)

0 commit comments

Comments
 (0)