From 57ef04288abd27a717287a652d324f95cb77c3c6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 14 Mar 2014 18:16:20 +0100 Subject: gpio: switch drivers to use new callback This switches all GPIO and pin control drivers with irqchips that were using .startup() and .shutdown() callbacks to lock GPIO lines for IRQ usage over to using the .request_resources() and .release_resources() callbacks just introduced into the irqchip vtable. Cc: Thomas Gleixner Cc: Jean-Jacques Hiblot Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-adi2.c | 1 + drivers/pinctrl/pinctrl-baytrail.c | 14 +++++++------- drivers/pinctrl/pinctrl-msm.c | 11 +++++------ drivers/pinctrl/pinctrl-nomadik.c | 25 +++++++++++++++++++++---- drivers/pinctrl/sirf/pinctrl-sirf.c | 14 +++++++------- 5 files changed, 41 insertions(+), 24 deletions(-) (limited to 'drivers/pinctrl') diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c index 7a39562c3e4..94138bca1f2 100644 --- a/drivers/pinctrl/pinctrl-adi2.c +++ b/drivers/pinctrl/pinctrl-adi2.c @@ -324,6 +324,7 @@ static unsigned int adi_gpio_irq_startup(struct irq_data *d) if (!port) { pr_err("GPIO IRQ %d :Not exist\n", d->irq); + /* FIXME: negative return code will be ignored */ return -ENODEV; } diff --git a/drivers/pinctrl/pinctrl-baytrail.c b/drivers/pinctrl/pinctrl-baytrail.c index 665b96bc0c3..9a4abd9cc87 100644 --- a/drivers/pinctrl/pinctrl-baytrail.c +++ b/drivers/pinctrl/pinctrl-baytrail.c @@ -371,23 +371,23 @@ static void byt_irq_mask(struct irq_data *d) { } -static unsigned int byt_irq_startup(struct irq_data *d) +static int byt_irq_reqres(struct irq_data *d) { struct byt_gpio *vg = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&vg->chip, irqd_to_hwirq(d))) + if (gpio_lock_as_irq(&vg->chip, irqd_to_hwirq(d))) { dev_err(vg->chip.dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - byt_irq_unmask(d); + return -EINVAL; + } return 0; } -static void byt_irq_shutdown(struct irq_data *d) +static void byt_irq_relres(struct irq_data *d) { struct byt_gpio *vg = irq_data_get_irq_chip_data(d); - byt_irq_mask(d); gpio_unlock_as_irq(&vg->chip, irqd_to_hwirq(d)); } @@ -396,8 +396,8 @@ static struct irq_chip byt_irqchip = { .irq_mask = byt_irq_mask, .irq_unmask = byt_irq_unmask, .irq_set_type = byt_irq_type, - .irq_startup = byt_irq_startup, - .irq_shutdown = byt_irq_shutdown, + .irq_request_resources = byt_irq_reqres, + .irq_release_resources = byt_irq_relres, }; static void byt_gpio_irq_init_hw(struct byt_gpio *vg) diff --git a/drivers/pinctrl/pinctrl-msm.c b/drivers/pinctrl/pinctrl-msm.c index ef2bf3126da..81ecd6ba416 100644 --- a/drivers/pinctrl/pinctrl-msm.c +++ b/drivers/pinctrl/pinctrl-msm.c @@ -805,23 +805,22 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on) return 0; } -static unsigned int msm_gpio_irq_startup(struct irq_data *d) +static int msm_gpio_irq_reqres(struct irq_data *d) { struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d); if (gpio_lock_as_irq(&pctrl->chip, d->hwirq)) { dev_err(pctrl->dev, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); + return -EINVAL; } - msm_gpio_irq_unmask(d); return 0; } -static void msm_gpio_irq_shutdown(struct irq_data *d) +static void msm_gpio_irq_relres(struct irq_data *d) { struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d); - msm_gpio_irq_mask(d); gpio_unlock_as_irq(&pctrl->chip, d->hwirq); } @@ -832,8 +831,8 @@ static struct irq_chip msm_gpio_irq_chip = { .irq_ack = msm_gpio_irq_ack, .irq_set_type = msm_gpio_irq_set_type, .irq_set_wake = msm_gpio_irq_set_wake, - .irq_startup = msm_gpio_irq_startup, - .irq_shutdown = msm_gpio_irq_shutdown, + .irq_request_resources = msm_gpio_irq_reqres, + .irq_release_resources = msm_gpio_irq_relres, }; static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 53a11114927..2ea3f3738ea 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -848,10 +848,6 @@ static unsigned int nmk_gpio_irq_startup(struct irq_data *d) { struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&nmk_chip->chip, d->hwirq)) - dev_err(nmk_chip->chip.dev, - "unable to lock HW IRQ %lu for IRQ\n", - d->hwirq); clk_enable(nmk_chip->clk); nmk_gpio_irq_unmask(d); return 0; @@ -863,6 +859,25 @@ static void nmk_gpio_irq_shutdown(struct irq_data *d) nmk_gpio_irq_mask(d); clk_disable(nmk_chip->clk); +} + +static int nmk_gpio_irq_reqres(struct irq_data *d) +{ + struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); + + if (gpio_lock_as_irq(&nmk_chip->chip, d->hwirq)) { + dev_err(nmk_chip->chip.dev, + "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); + return -EINVAL; + } + return 0; +} + +static void nmk_gpio_irq_relres(struct irq_data *d) +{ + struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); + gpio_unlock_as_irq(&nmk_chip->chip, d->hwirq); } @@ -875,6 +890,8 @@ static struct irq_chip nmk_gpio_irq_chip = { .irq_set_wake = nmk_gpio_irq_set_wake, .irq_startup = nmk_gpio_irq_startup, .irq_shutdown = nmk_gpio_irq_shutdown, + .irq_request_resources = nmk_gpio_irq_reqres, + .irq_release_resources = nmk_gpio_irq_relres, .flags = IRQCHIP_MASK_ON_SUSPEND, }; diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c index 617a4916b50..3ce6e258bc8 100644 --- a/drivers/pinctrl/sirf/pinctrl-sirf.c +++ b/drivers/pinctrl/sirf/pinctrl-sirf.c @@ -594,23 +594,23 @@ static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type) return 0; } -static unsigned int sirfsoc_gpio_irq_startup(struct irq_data *d) +static int sirfsoc_gpio_irq_reqres(struct irq_data *d) { struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE)) + if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE)) { dev_err(bank->chip.gc.dev, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); - sirfsoc_gpio_irq_unmask(d); + return -EINVAL; + } return 0; } -static void sirfsoc_gpio_irq_shutdown(struct irq_data *d) +static void sirfsoc_gpio_irq_relres(struct irq_data *d) { struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); - sirfsoc_gpio_irq_mask(d); gpio_unlock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE); } @@ -620,8 +620,8 @@ static struct irq_chip sirfsoc_irq_chip = { .irq_mask = sirfsoc_gpio_irq_mask, .irq_unmask = sirfsoc_gpio_irq_unmask, .irq_set_type = sirfsoc_gpio_irq_type, - .irq_startup = sirfsoc_gpio_irq_startup, - .irq_shutdown = sirfsoc_gpio_irq_shutdown, + .irq_request_resources = sirfsoc_gpio_irq_reqres, + .irq_release_resources = sirfsoc_gpio_irq_relres, }; static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) -- cgit v1.2.3-70-g09d2 From 8c1d50a6a7aa29a45a43b6073cf540eb7ee028a5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 14 Mar 2014 18:24:30 +0100 Subject: pinctrl: coh901: move irq line locking to resource callbacks This switches the COH901 GPIO driver over to using the .request_resources() and .release_resources() callbacks from the irqchip vtable and separate the calls from the .enable() and .disable() callbacks as the latter cannot really say no to a request, whereas the resource callbacks can. Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-coh901.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'drivers/pinctrl') diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index 162ac0d7373..749db595640 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -529,10 +529,6 @@ static void u300_gpio_irq_enable(struct irq_data *d) dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n", d->hwirq, port->name, offset); - if (gpio_lock_as_irq(&gpio->chip, d->hwirq)) - dev_err(gpio->dev, - "unable to lock HW IRQ %lu for IRQ\n", - d->hwirq); local_irq_save(flags); val = readl(U300_PIN_REG(offset, ien)); writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); @@ -551,6 +547,27 @@ static void u300_gpio_irq_disable(struct irq_data *d) val = readl(U300_PIN_REG(offset, ien)); writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); local_irq_restore(flags); +} + +static int u300_gpio_irq_reqres(struct irq_data *d) +{ + struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); + struct u300_gpio *gpio = port->gpio; + + if (gpio_lock_as_irq(&gpio->chip, d->hwirq)) { + dev_err(gpio->dev, + "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); + return -EINVAL; + } + return 0; +} + +static void u300_gpio_irq_relres(struct irq_data *d) +{ + struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); + struct u300_gpio *gpio = port->gpio; + gpio_unlock_as_irq(&gpio->chip, d->hwirq); } @@ -559,7 +576,8 @@ static struct irq_chip u300_gpio_irqchip = { .irq_enable = u300_gpio_irq_enable, .irq_disable = u300_gpio_irq_disable, .irq_set_type = u300_gpio_irq_type, - + .irq_request_resources = u300_gpio_irq_reqres, + .irq_release_resources = u300_gpio_irq_relres, }; static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) -- cgit v1.2.3-70-g09d2 From 194e15ba00d90a6e8779b9cd87f1feec0d55427f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 21 Mar 2014 10:24:42 +0100 Subject: pinctrl: nomadik: rename secondary to latent The "secondary irq" in the nomadik pin control driver is actually not secondary (as in: can occur any time alongside the ordinary irq), it is a latent IRQ. It is an IRQ that has occurred when the system was in sleep state and has been cached in a special register flagged from the low power management unit (PRCM). Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-nomadik.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/pinctrl') diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 2ea3f3738ea..41e808d9edb 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -254,7 +254,7 @@ struct nmk_gpio_platform_data { int first_gpio; int first_irq; int num_gpio; - u32 (*get_secondary_status)(unsigned int bank); + u32 (*get_latent_status)(unsigned int bank); void (*set_ioforce)(bool enable); bool supports_sleepmode; }; @@ -266,8 +266,8 @@ struct nmk_gpio_chip { struct clk *clk; unsigned int bank; unsigned int parent_irq; - int secondary_parent_irq; - u32 (*get_secondary_status)(unsigned int bank); + int latent_parent_irq; + u32 (*get_latent_status)(unsigned int bank); void (*set_ioforce)(bool enable); spinlock_t lock; bool sleepmode; @@ -926,11 +926,11 @@ static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) __nmk_gpio_irq_handler(irq, desc, status); } -static void nmk_gpio_secondary_irq_handler(unsigned int irq, +static void nmk_gpio_latent_irq_handler(unsigned int irq, struct irq_desc *desc) { struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq); - u32 status = nmk_chip->get_secondary_status(nmk_chip->bank); + u32 status = nmk_chip->get_latent_status(nmk_chip->bank); __nmk_gpio_irq_handler(irq, desc, status); } @@ -940,10 +940,10 @@ static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip) irq_set_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler); irq_set_handler_data(nmk_chip->parent_irq, nmk_chip); - if (nmk_chip->secondary_parent_irq >= 0) { - irq_set_chained_handler(nmk_chip->secondary_parent_irq, - nmk_gpio_secondary_irq_handler); - irq_set_handler_data(nmk_chip->secondary_parent_irq, nmk_chip); + if (nmk_chip->latent_parent_irq >= 0) { + irq_set_chained_handler(nmk_chip->latent_parent_irq, + nmk_gpio_latent_irq_handler); + irq_set_handler_data(nmk_chip->latent_parent_irq, nmk_chip); } return 0; @@ -1263,7 +1263,7 @@ static int nmk_gpio_probe(struct platform_device *dev) struct gpio_chip *chip; struct resource *res; struct clk *clk; - int secondary_irq; + int latent_irq; void __iomem *base; int irq; int ret; @@ -1287,8 +1287,8 @@ static int nmk_gpio_probe(struct platform_device *dev) if (irq < 0) return irq; - secondary_irq = platform_get_irq(dev, 1); - if (secondary_irq >= 0 && !pdata->get_secondary_status) + latent_irq = platform_get_irq(dev, 1); + if (latent_irq >= 0 && !pdata->get_latent_status) return -EINVAL; res = platform_get_resource(dev, IORESOURCE_MEM, 0); @@ -1314,8 +1314,8 @@ static int nmk_gpio_probe(struct platform_device *dev) nmk_chip->addr = base; nmk_chip->chip = nmk_gpio_template; nmk_chip->parent_irq = irq; - nmk_chip->secondary_parent_irq = secondary_irq; - nmk_chip->get_secondary_status = pdata->get_secondary_status; + nmk_chip->latent_parent_irq = latent_irq; + nmk_chip->get_latent_status = pdata->get_latent_status; nmk_chip->set_ioforce = pdata->set_ioforce; nmk_chip->sleepmode = pdata->supports_sleepmode; spin_lock_init(&nmk_chip->lock); -- cgit v1.2.3-70-g09d2 From 8f18bcfcd2bc30cb9a5924a6b4af49c8388bc785 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 21 Mar 2014 10:40:24 +0100 Subject: pinctrl: nomadik: factor in platform data container The old platform data struct is just a leftover from the times when the driver was not probed exclusively from the device tree. Factor this into the general state container and simplify the probe path. Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-nomadik.c | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) (limited to 'drivers/pinctrl') diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 41e808d9edb..98a36a0969f 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -246,19 +246,6 @@ enum nmk_gpio_slpm { NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE, }; -/* - * Platform data to register a block: only the initial gpio/irq number. - */ -struct nmk_gpio_platform_data { - char *name; - int first_gpio; - int first_irq; - int num_gpio; - u32 (*get_latent_status)(unsigned int bank); - void (*set_ioforce)(bool enable); - bool supports_sleepmode; -}; - struct nmk_gpio_chip { struct gpio_chip chip; struct irq_domain *domain; @@ -1257,39 +1244,33 @@ static const struct irq_domain_ops nmk_gpio_irq_simple_ops = { static int nmk_gpio_probe(struct platform_device *dev) { - struct nmk_gpio_platform_data *pdata; struct device_node *np = dev->dev.of_node; struct nmk_gpio_chip *nmk_chip; struct gpio_chip *chip; struct resource *res; struct clk *clk; int latent_irq; + bool supports_sleepmode; void __iomem *base; int irq; int ret; - pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - if (of_get_property(np, "st,supports-sleepmode", NULL)) - pdata->supports_sleepmode = true; + supports_sleepmode = true; + else + supports_sleepmode = false; if (of_property_read_u32(np, "gpio-bank", &dev->id)) { dev_err(&dev->dev, "gpio-bank property not found\n"); return -EINVAL; } - pdata->first_gpio = dev->id * NMK_GPIO_PER_CHIP; - pdata->num_gpio = NMK_GPIO_PER_CHIP; - irq = platform_get_irq(dev, 0); if (irq < 0) return irq; + /* It's OK for this IRQ not to be present */ latent_irq = platform_get_irq(dev, 1); - if (latent_irq >= 0 && !pdata->get_latent_status) - return -EINVAL; res = platform_get_resource(dev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&dev->dev, res); @@ -1315,15 +1296,13 @@ static int nmk_gpio_probe(struct platform_device *dev) nmk_chip->chip = nmk_gpio_template; nmk_chip->parent_irq = irq; nmk_chip->latent_parent_irq = latent_irq; - nmk_chip->get_latent_status = pdata->get_latent_status; - nmk_chip->set_ioforce = pdata->set_ioforce; - nmk_chip->sleepmode = pdata->supports_sleepmode; + nmk_chip->sleepmode = supports_sleepmode; spin_lock_init(&nmk_chip->lock); chip = &nmk_chip->chip; - chip->base = pdata->first_gpio; - chip->ngpio = pdata->num_gpio; - chip->label = pdata->name ?: dev_name(&dev->dev); + chip->base = dev->id * NMK_GPIO_PER_CHIP; + chip->ngpio = NMK_GPIO_PER_CHIP; + chip->label = dev_name(&dev->dev); chip->dev = &dev->dev; chip->owner = THIS_MODULE; -- cgit v1.2.3-70-g09d2 From e0bc34a3dada03a48ff5501381ff7fdef885ed25 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 25 Mar 2014 10:44:09 +0100 Subject: pinctrl: nomadik: convert driver to use gpiolib irqchip This converts the Nomadik pin control driver to register its chained irq handler and irqchip using the helpers in the gpiolib core. Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 3 + drivers/pinctrl/pinctrl-nomadik.c | 123 ++++++++++---------------------------- 2 files changed, 36 insertions(+), 90 deletions(-) (limited to 'drivers/pinctrl') diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 1e4e69384ba..a05087bd195 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -235,6 +235,9 @@ config PINCTRL_NOMADIK depends on ARCH_U8500 || ARCH_NOMADIK select PINMUX select PINCONF + select GPIOLIB + select OF_GPIO + select GPIOLIB_IRQCHIP config PINCTRL_STN8815 bool "STN8815 pin controller driver" diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 98a36a0969f..db0cc30c82d 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -21,9 +21,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -248,7 +245,6 @@ enum nmk_gpio_slpm { struct nmk_gpio_chip { struct gpio_chip chip; - struct irq_domain *domain; void __iomem *addr; struct clk *clk; unsigned int bank; @@ -419,7 +415,7 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset) u32 falling = nmk_chip->fimsc & BIT(offset); u32 rising = nmk_chip->rimsc & BIT(offset); int gpio = nmk_chip->chip.base + offset; - int irq = irq_find_mapping(nmk_chip->domain, offset); + int irq = irq_find_mapping(nmk_chip->chip.irqdomain, offset); struct irq_data *d = irq_get_irq_data(irq); if (!rising && !falling) @@ -647,11 +643,8 @@ static inline int nmk_gpio_get_bitmask(int gpio) static void nmk_gpio_irq_ack(struct irq_data *d) { - struct nmk_gpio_chip *nmk_chip; - - nmk_chip = irq_data_get_irq_chip_data(d); - if (!nmk_chip) - return; + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); clk_enable(nmk_chip->clk); writel(nmk_gpio_get_bitmask(d->hwirq), nmk_chip->addr + NMK_GPIO_IC); @@ -848,26 +841,6 @@ static void nmk_gpio_irq_shutdown(struct irq_data *d) clk_disable(nmk_chip->clk); } -static int nmk_gpio_irq_reqres(struct irq_data *d) -{ - struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); - - if (gpio_lock_as_irq(&nmk_chip->chip, d->hwirq)) { - dev_err(nmk_chip->chip.dev, - "unable to lock HW IRQ %lu for IRQ\n", - d->hwirq); - return -EINVAL; - } - return 0; -} - -static void nmk_gpio_irq_relres(struct irq_data *d) -{ - struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); - - gpio_unlock_as_irq(&nmk_chip->chip, d->hwirq); -} - static struct irq_chip nmk_gpio_irq_chip = { .name = "Nomadik-GPIO", .irq_ack = nmk_gpio_irq_ack, @@ -877,24 +850,21 @@ static struct irq_chip nmk_gpio_irq_chip = { .irq_set_wake = nmk_gpio_irq_set_wake, .irq_startup = nmk_gpio_irq_startup, .irq_shutdown = nmk_gpio_irq_shutdown, - .irq_request_resources = nmk_gpio_irq_reqres, - .irq_release_resources = nmk_gpio_irq_relres, .flags = IRQCHIP_MASK_ON_SUSPEND, }; static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc, u32 status) { - struct nmk_gpio_chip *nmk_chip; struct irq_chip *host_chip = irq_get_chip(irq); + struct gpio_chip *chip = irq_desc_get_handler_data(desc); chained_irq_enter(host_chip, desc); - nmk_chip = irq_get_handler_data(irq); while (status) { int bit = __ffs(status); - generic_handle_irq(irq_find_mapping(nmk_chip->domain, bit)); + generic_handle_irq(irq_find_mapping(chip->irqdomain, bit)); status &= ~BIT(bit); } @@ -903,9 +873,11 @@ static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc, static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { - struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq); + struct gpio_chip *chip = irq_desc_get_handler_data(desc); + struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); u32 status; + pr_err("PLONK IRQ %d\n", irq); clk_enable(nmk_chip->clk); status = readl(nmk_chip->addr + NMK_GPIO_IS); clk_disable(nmk_chip->clk); @@ -916,26 +888,13 @@ static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) static void nmk_gpio_latent_irq_handler(unsigned int irq, struct irq_desc *desc) { - struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq); + struct gpio_chip *chip = irq_desc_get_handler_data(desc); + struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); u32 status = nmk_chip->get_latent_status(nmk_chip->bank); __nmk_gpio_irq_handler(irq, desc, status); } -static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip) -{ - irq_set_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler); - irq_set_handler_data(nmk_chip->parent_irq, nmk_chip); - - if (nmk_chip->latent_parent_irq >= 0) { - irq_set_chained_handler(nmk_chip->latent_parent_irq, - nmk_gpio_latent_irq_handler); - irq_set_handler_data(nmk_chip->latent_parent_irq, nmk_chip); - } - - return 0; -} - /* I/O Functions */ static int nmk_gpio_request(struct gpio_chip *chip, unsigned offset) @@ -1014,14 +973,6 @@ static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset, return 0; } -static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct nmk_gpio_chip *nmk_chip = - container_of(chip, struct nmk_gpio_chip, chip); - - return irq_create_mapping(nmk_chip->domain, offset); -} - #ifdef CONFIG_DEBUG_FS #include @@ -1120,7 +1071,6 @@ static struct gpio_chip nmk_gpio_template = { .get = nmk_gpio_get_input, .direction_output = nmk_gpio_make_output, .set = nmk_gpio_set_output, - .to_irq = nmk_gpio_to_irq, .dbg_show = nmk_gpio_dbg_show, .can_sleep = false, }; @@ -1221,27 +1171,6 @@ void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up) } } -static int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct nmk_gpio_chip *nmk_chip = d->host_data; - - if (!nmk_chip) - return -EINVAL; - - irq_set_chip_and_handler(irq, &nmk_gpio_irq_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID); - irq_set_chip_data(irq, nmk_chip); - irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING); - - return 0; -} - -static const struct irq_domain_ops nmk_gpio_irq_simple_ops = { - .map = nmk_gpio_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - static int nmk_gpio_probe(struct platform_device *dev) { struct device_node *np = dev->dev.of_node; @@ -1321,17 +1250,31 @@ static int nmk_gpio_probe(struct platform_device *dev) platform_set_drvdata(dev, nmk_chip); - nmk_chip->domain = irq_domain_add_simple(np, - NMK_GPIO_PER_CHIP, 0, - &nmk_gpio_irq_simple_ops, nmk_chip); - if (!nmk_chip->domain) { - dev_err(&dev->dev, "failed to create irqdomain\n"); - /* Just do this, no matter if it fails */ + /* + * Let the generic code handle this edge IRQ, the the chained + * handler will perform the actual work of handling the parent + * interrupt. + */ + ret = gpiochip_irqchip_add(&nmk_chip->chip, + &nmk_gpio_irq_chip, + 0, + handle_edge_irq, + IRQ_TYPE_EDGE_FALLING); + if (ret) { + dev_err(&dev->dev, "could not add irqchip\n"); ret = gpiochip_remove(&nmk_chip->chip); - return -ENOSYS; + return -ENODEV; } - - nmk_gpio_init_irq(nmk_chip); + /* Then register the chain on the parent IRQ */ + gpiochip_set_chained_irqchip(&nmk_chip->chip, + &nmk_gpio_irq_chip, + nmk_chip->parent_irq, + nmk_gpio_irq_handler); + if (nmk_chip->latent_parent_irq > 0) + gpiochip_set_chained_irqchip(&nmk_chip->chip, + &nmk_gpio_irq_chip, + nmk_chip->latent_parent_irq, + nmk_gpio_latent_irq_handler); dev_info(&dev->dev, "at address %p\n", nmk_chip->addr); -- cgit v1.2.3-70-g09d2 From 523dcce72c72e829b9d391f8020277038c6aab82 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 25 Mar 2014 13:37:17 +0100 Subject: pinctrl: coh901: convert driver to use gpiolib irqchip This converts the COH901 pin control driver to register its chained irq handler and irqchip using the helpers in the gpiolib core. Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/pinctrl-coh901.c | 204 ++++++++++----------------------------- 2 files changed, 54 insertions(+), 151 deletions(-) (limited to 'drivers/pinctrl') diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index a05087bd195..0c6eb33daa8 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -324,6 +324,7 @@ config PINCTRL_U300 config PINCTRL_COH901 bool "ST-Ericsson U300 COH 901 335/571 GPIO" depends on GPIOLIB && ARCH_U300 && PINCTRL_U300 + select GPIOLIB_IRQCHIP help Say yes here to support GPIO interface on ST-Ericsson U300. The names of the two IP block variants supported are diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index 749db595640..d182fdd2e71 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -8,17 +8,14 @@ * Author: Jonas Aaberg */ #include -#include #include #include #include #include -#include #include #include #include #include -#include #include #include #include @@ -61,9 +58,17 @@ #define U300_GPIO_PINS_PER_PORT 8 #define U300_GPIO_MAX (U300_GPIO_PINS_PER_PORT * U300_GPIO_NUM_PORTS) +struct u300_gpio_port { + struct u300_gpio *gpio; + char name[8]; + int irq; + int number; + u8 toggle_edge_mode; +}; + struct u300_gpio { struct gpio_chip chip; - struct list_head port_list; + struct u300_gpio_port ports[U300_GPIO_NUM_PORTS]; struct clk *clk; void __iomem *base; struct device *dev; @@ -78,16 +83,6 @@ struct u300_gpio { u32 iev; }; -struct u300_gpio_port { - struct list_head node; - struct u300_gpio *gpio; - char name[8]; - struct irq_domain *domain; - int irq; - int number; - u8 toggle_edge_mode; -}; - /* * Macro to expand to read a specific register found in the "gpio" * struct. It requires the struct u300_gpio *gpio variable to exist in @@ -308,39 +303,6 @@ static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset, return 0; } -static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct u300_gpio *gpio = to_u300_gpio(chip); - int portno = offset >> 3; - struct u300_gpio_port *port = NULL; - struct list_head *p; - int retirq; - bool found = false; - - list_for_each(p, &gpio->port_list) { - port = list_entry(p, struct u300_gpio_port, node); - if (port->number == portno) { - found = true; - break; - } - } - if (!found) { - dev_err(gpio->dev, "could not locate port for GPIO %d IRQ\n", - offset); - return -EINVAL; - } - - /* - * The local hwirqs on the port are the lower three bits, there - * are exactly 8 IRQs per port since they are 8-bit - */ - retirq = irq_find_mapping(port->domain, (offset & 0x7)); - - dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d from port %d\n", - offset, retirq, port->number); - return retirq; -} - /* Returning -EINVAL means "supported but not available" */ int u300_gpio_config_get(struct gpio_chip *chip, unsigned offset, @@ -461,7 +423,6 @@ static struct gpio_chip u300_gpio_chip = { .set = u300_gpio_set, .direction_input = u300_gpio_direction_input, .direction_output = u300_gpio_direction_output, - .to_irq = u300_gpio_to_irq, }; static void u300_toggle_trigger(struct u300_gpio *gpio, unsigned offset) @@ -485,9 +446,10 @@ static void u300_toggle_trigger(struct u300_gpio *gpio, unsigned offset) static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger) { - struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); - struct u300_gpio *gpio = port->gpio; - int offset = (port->number << 3) + d->hwirq; + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct u300_gpio *gpio = to_u300_gpio(chip); + struct u300_gpio_port *port = &gpio->ports[d->hwirq >> 3]; + int offset = d->hwirq; u32 val; if ((trigger & IRQF_TRIGGER_RISING) && @@ -521,9 +483,10 @@ static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger) static void u300_gpio_irq_enable(struct irq_data *d) { - struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); - struct u300_gpio *gpio = port->gpio; - int offset = (port->number << 3) + d->hwirq; + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct u300_gpio *gpio = to_u300_gpio(chip); + struct u300_gpio_port *port = &gpio->ports[d->hwirq >> 3]; + int offset = d->hwirq; u32 val; unsigned long flags; @@ -537,9 +500,9 @@ static void u300_gpio_irq_enable(struct irq_data *d) static void u300_gpio_irq_disable(struct irq_data *d) { - struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); - struct u300_gpio *gpio = port->gpio; - int offset = (port->number << 3) + d->hwirq; + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct u300_gpio *gpio = to_u300_gpio(chip); + int offset = d->hwirq; u32 val; unsigned long flags; @@ -549,45 +512,24 @@ static void u300_gpio_irq_disable(struct irq_data *d) local_irq_restore(flags); } -static int u300_gpio_irq_reqres(struct irq_data *d) -{ - struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); - struct u300_gpio *gpio = port->gpio; - - if (gpio_lock_as_irq(&gpio->chip, d->hwirq)) { - dev_err(gpio->dev, - "unable to lock HW IRQ %lu for IRQ\n", - d->hwirq); - return -EINVAL; - } - return 0; -} - -static void u300_gpio_irq_relres(struct irq_data *d) -{ - struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); - struct u300_gpio *gpio = port->gpio; - - gpio_unlock_as_irq(&gpio->chip, d->hwirq); -} - static struct irq_chip u300_gpio_irqchip = { .name = "u300-gpio-irqchip", .irq_enable = u300_gpio_irq_enable, .irq_disable = u300_gpio_irq_disable, .irq_set_type = u300_gpio_irq_type, - .irq_request_resources = u300_gpio_irq_reqres, - .irq_release_resources = u300_gpio_irq_relres, }; static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) { - struct u300_gpio_port *port = irq_get_handler_data(irq); - struct u300_gpio *gpio = port->gpio; + struct irq_chip *parent_chip = irq_get_chip(irq); + struct gpio_chip *chip = irq_get_handler_data(irq); + struct u300_gpio *gpio = to_u300_gpio(chip); + struct u300_gpio_port *port = &gpio->ports[irq - chip->base]; int pinoffset = port->number << 3; /* get the right stride */ unsigned long val; - desc->irq_data.chip->irq_ack(&desc->irq_data); + chained_irq_enter(parent_chip, desc); + /* Read event register */ val = readl(U300_PIN_REG(pinoffset, iev)); /* Mask relevant bits */ @@ -600,8 +542,8 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) int irqoffset; for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) { - int pin_irq = irq_find_mapping(port->domain, irqoffset); int offset = pinoffset + irqoffset; + int pin_irq = irq_find_mapping(chip->irqdomain, offset); dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n", pin_irq, offset); @@ -615,7 +557,7 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) } } - desc->irq_data.chip->irq_unmask(&desc->irq_data); + chained_irq_exit(parent_chip, desc); } static void __init u300_gpio_init_pin(struct u300_gpio *gpio, @@ -666,20 +608,6 @@ static void __init u300_gpio_init_coh901571(struct u300_gpio *gpio) } } -static inline void u300_gpio_free_ports(struct u300_gpio *gpio) -{ - struct u300_gpio_port *port; - struct list_head *p, *n; - - list_for_each_safe(p, n, &gpio->port_list) { - port = list_entry(p, struct u300_gpio_port, node); - list_del(&port->node); - if (port->domain) - irq_domain_remove(port->domain); - kfree(port); - } -} - /* * Here we map a GPIO in the local gpio_chip pin space to a pin in * the local pinctrl pin space. The pin controller used is @@ -770,17 +698,28 @@ static int __init u300_gpio_probe(struct platform_device *pdev) gpio->base + U300_GPIO_CR); u300_gpio_init_coh901571(gpio); +#ifdef CONFIG_OF_GPIO + gpio->chip.of_node = pdev->dev.of_node; +#endif + err = gpiochip_add(&gpio->chip); + if (err) { + dev_err(gpio->dev, "unable to add gpiochip: %d\n", err); + goto err_no_chip; + } + + err = gpiochip_irqchip_add(&gpio->chip, + &u300_gpio_irqchip, + 0, + handle_simple_irq, + IRQ_TYPE_EDGE_FALLING); + if (err) { + dev_err(gpio->dev, "no GPIO irqchip\n"); + goto err_no_irqchip; + } + /* Add each port with its IRQ separately */ - INIT_LIST_HEAD(&gpio->port_list); for (portno = 0 ; portno < U300_GPIO_NUM_PORTS; portno++) { - struct u300_gpio_port *port = - kmalloc(sizeof(struct u300_gpio_port), GFP_KERNEL); - - if (!port) { - dev_err(gpio->dev, "out of memory\n"); - err = -ENOMEM; - goto err_no_port; - } + struct u300_gpio_port *port = &gpio->ports[portno]; snprintf(port->name, 8, "gpio%d", portno); port->number = portno; @@ -788,50 +727,16 @@ static int __init u300_gpio_probe(struct platform_device *pdev) port->irq = platform_get_irq(pdev, portno); - dev_dbg(gpio->dev, "register IRQ %d for port %s\n", port->irq, - port->name); - - port->domain = irq_domain_add_linear(pdev->dev.of_node, - U300_GPIO_PINS_PER_PORT, - &irq_domain_simple_ops, - port); - if (!port->domain) { - err = -ENOMEM; - goto err_no_domain; - } - - irq_set_chained_handler(port->irq, u300_gpio_irq_handler); - irq_set_handler_data(port->irq, port); - - /* For each GPIO pin set the unique IRQ handler */ - for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) { - int irqno = irq_create_mapping(port->domain, i); - - dev_dbg(gpio->dev, "GPIO%d on port %s gets IRQ %d\n", - gpio->chip.base + (port->number << 3) + i, - port->name, irqno); - irq_set_chip_and_handler(irqno, &u300_gpio_irqchip, - handle_simple_irq); - set_irq_flags(irqno, IRQF_VALID); - irq_set_chip_data(irqno, port); - } + gpiochip_set_chained_irqchip(&gpio->chip, + &u300_gpio_irqchip, + port->irq, + u300_gpio_irq_handler); /* Turns off irq force (test register) for this port */ writel(0x0, gpio->base + portno * gpio->stride + ifr); - - list_add_tail(&port->node, &gpio->port_list); } dev_dbg(gpio->dev, "initialized %d GPIO ports\n", portno); -#ifdef CONFIG_OF_GPIO - gpio->chip.of_node = pdev->dev.of_node; -#endif - err = gpiochip_add(&gpio->chip); - if (err) { - dev_err(gpio->dev, "unable to add gpiochip: %d\n", err); - goto err_no_chip; - } - /* * Add pinctrl pin ranges, the pin controller must be registered * at this point @@ -850,12 +755,10 @@ static int __init u300_gpio_probe(struct platform_device *pdev) return 0; err_no_range: +err_no_irqchip: if (gpiochip_remove(&gpio->chip)) dev_err(&pdev->dev, "failed to remove gpio chip\n"); err_no_chip: -err_no_domain: -err_no_port: - u300_gpio_free_ports(gpio); clk_disable_unprepare(gpio->clk); dev_err(&pdev->dev, "module ERROR:%d\n", err); return err; @@ -874,7 +777,6 @@ static int __exit u300_gpio_remove(struct platform_device *pdev) dev_err(gpio->dev, "unable to remove gpiochip: %d\n", err); return err; } - u300_gpio_free_ports(gpio); clk_disable_unprepare(gpio->clk); return 0; } -- cgit v1.2.3-70-g09d2