From abdc08a3a263a20e49534a36291d657bf53dda5b Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 19 Aug 2014 10:06:09 -0700 Subject: gpio: change gpiochip_request_own_desc() prototype The current prototype of gpiochip_request_own_desc() requires to obtain a pointer to a descriptor. This is in contradiction to all other GPIO request schemes, and imposes an extra step of obtaining a descriptor to drivers. Most drivers actually cannot even perform that step since the function that does it (gpichip_get_desc()) is gpiolib-private. Change gpiochip_request_own_desc() to return a descriptor from a (chip, hwnum) tuple and update users of this function (currently gpiolib-acpi only). Signed-off-by: Alexandre Courbot Tested-by: Mika Westerberg Signed-off-by: Linus Walleij --- Documentation/gpio/driver.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Documentation/gpio') diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt index 18790c237977..23b751a10d7b 100644 --- a/Documentation/gpio/driver.txt +++ b/Documentation/gpio/driver.txt @@ -178,7 +178,8 @@ does not help since it pins the module to the kernel forever (it calls try_module_get()). A GPIO driver can use the following functions instead to request and free descriptors without being pinned to the kernel forever. - int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label) + struct gpio_desc *gpiochip_request_own_desc(struct gpio_desc *desc, + const char *label) void gpiochip_free_own_desc(struct gpio_desc *desc) -- cgit v1.2.3-59-g8ed1b From 3f97d5fcf99cb87f590ffe1d9422b2a26a8ef3ed Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 26 Sep 2014 14:19:52 +0200 Subject: gpio: handle also nested irqchips in the chained handler set-up To unify how we connect cascaded IRQ chips to parent IRQs, if NULL us passed as handler to the gpiochip_set_chained_irqchip() function, assume the chips is nested rather than chained, and we still get the parent set up correctly by way of this function call. Alter the drivers for tc3589x and stmpe to use this to set up their chained handlers as a demonstration of the usage. Signed-off-by: Linus Walleij --- Documentation/gpio/driver.txt | 3 ++- drivers/gpio/gpio-stmpe.c | 18 ++++++++++++------ drivers/gpio/gpio-tc3589x.c | 5 +++++ drivers/gpio/gpiolib.c | 34 +++++++++++++++++++--------------- 4 files changed, 38 insertions(+), 22 deletions(-) (limited to 'Documentation/gpio') diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt index 23b751a10d7b..31e0b5db55d8 100644 --- a/Documentation/gpio/driver.txt +++ b/Documentation/gpio/driver.txt @@ -124,7 +124,8 @@ symbol: * gpiochip_set_chained_irqchip(): sets up a chained irq handler for a gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler data. (Notice handler data, since the irqchip data is likely used by the - parent irqchip!) This is for the chained type of chip. + parent irqchip!) This is for the chained type of chip. This is also used + to set up a nested irqchip if NULL is passed as handler. To use the helpers please keep the following in mind: diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 845025a57240..b0b342787c37 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -308,6 +308,12 @@ static int stmpe_gpio_probe(struct platform_device *pdev) if (ret) goto out_free; + ret = gpiochip_add(&stmpe_gpio->chip); + if (ret) { + dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); + goto out_disable; + } + if (irq > 0) { ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT, @@ -324,14 +330,13 @@ static int stmpe_gpio_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n"); - return ret; + goto out_disable; } - } - ret = gpiochip_add(&stmpe_gpio->chip); - if (ret) { - dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); - goto out_disable; + gpiochip_set_chained_irqchip(&stmpe_gpio->chip, + &stmpe_gpio_irq_chip, + irq, + NULL); } if (pdata && pdata->setup) @@ -343,6 +348,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev) out_disable: stmpe_disable(stmpe, STMPE_BLOCK_GPIO); + gpiochip_remove(&stmpe_gpio->chip); out_free: kfree(stmpe_gpio); return ret; diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 7324869c38e0..ae0f6466eb09 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -300,6 +300,11 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) return ret; } + gpiochip_set_chained_irqchip(&tc3589x_gpio->chip, + &tc3589x_gpio_irq_chip, + irq, + NULL); + if (pdata && pdata->setup) pdata->setup(tc3589x, tc3589x_gpio->chip.base); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9362b5b817af..6e00c82be142 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -385,13 +385,14 @@ static struct gpio_chip *find_chip_by_name(const char *name) */ /** - * gpiochip_add_chained_irqchip() - adds a chained irqchip to a gpiochip - * @gpiochip: the gpiochip to add the irqchip to - * @irqchip: the irqchip to add to the gpiochip + * gpiochip_set_chained_irqchip() - sets a chained irqchip to a gpiochip + * @gpiochip: the gpiochip to set the irqchip chain to + * @irqchip: the irqchip to chain to the gpiochip * @parent_irq: the irq number corresponding to the parent IRQ for this * chained irqchip * @parent_handler: the parent interrupt handler for the accumulated IRQ - * coming out of the gpiochip + * coming out of the gpiochip. If the interrupt is nested rather than + * cascaded, pass NULL in this handler argument */ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, struct irq_chip *irqchip, @@ -400,23 +401,26 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, { unsigned int offset; - if (gpiochip->can_sleep) { - chip_err(gpiochip, "you cannot have chained interrupts on a chip that may sleep\n"); - return; - } if (!gpiochip->irqdomain) { chip_err(gpiochip, "called %s before setting up irqchip\n", __func__); return; } - irq_set_chained_handler(parent_irq, parent_handler); - - /* - * The parent irqchip is already using the chip_data for this - * irqchip, so our callbacks simply use the handler_data. - */ - irq_set_handler_data(parent_irq, gpiochip); + if (parent_handler) { + if (gpiochip->can_sleep) { + chip_err(gpiochip, + "you cannot have chained interrupts on a " + "chip that may sleep\n"); + return; + } + irq_set_chained_handler(parent_irq, parent_handler); + /* + * The parent irqchip is already using the chip_data for this + * irqchip, so our callbacks simply use the handler_data. + */ + irq_set_handler_data(parent_irq, gpiochip); + } /* Set the parent IRQ for all affected IRQs */ for (offset = 0; offset < gpiochip->ngpio; offset++) -- cgit v1.2.3-59-g8ed1b