From: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> To: Jerome Brunet <jbrunet-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>, Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>, Marc Zyngier <marc.zyngier-5wv7dgnIgG8@public.gmane.org>, Linus Walleij <linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>, Kevin Hilman <khilman-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>, Thomas Gleixner <tglx-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>, Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>, Neil Armstrong <narmstrong-rdvid1DuHRBWk0Htik3J/w@public.gmane.org> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, linux-gpio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, "thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org" <thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>, Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org> Subject: [PATCH v5 6/9] pinctrl: meson: add support for GPIO interrupts Date: Tue, 30 May 2017 22:26:48 +0200 [thread overview] Message-ID: <12e8fe0e-d608-f560-9ddb-7287e10d3db2@gmail.com> (raw) In-Reply-To: <66c57893-0a9e-4f8c-a017-ab346abbdfd0-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> Add support for GPIO interrupts and make use of the just introduced irqchip driver handling the GPIO interrupt-controller. Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> --- v5: - changed Kconfig entry based on Neil's suggestion - extended comments - fixed indentation --- drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/meson/pinctrl-meson.c | 170 +++++++++++++++++++++++++++++++++- 2 files changed, 170 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 7ae04a97..86834dea 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -166,6 +166,7 @@ config PINCTRL_MESON select PINCONF select GENERIC_PINCONF select GPIOLIB + select GPIOLIB_IRQCHIP select OF_GPIO select REGMAP_MMIO diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c index 66ed70c1..7bacd4e3 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.c +++ b/drivers/pinctrl/meson/pinctrl-meson.c @@ -62,6 +62,8 @@ #include "../pinctrl-utils.h" #include "pinctrl-meson.h" +static struct irq_domain *meson_pinctrl_irq_domain; + /** * meson_get_bank() - find the bank containing a given pin * @@ -497,6 +499,154 @@ static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio) return !!(val & BIT(bit)); } +static struct meson_pinctrl *meson_gpio_data_to_pc(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + + return gpiochip_get_data(chip); +} + +static int meson_gpio_bank_hwirq(struct meson_bank *bank, unsigned int offset) +{ + int hwirq; + + if (bank->irq_first < 0) + /* this bank cannot generate irqs */ + return 0; + + hwirq = offset - bank->first + bank->irq_first; + + if (hwirq > bank->irq_last) + /* this pin cannot generate irqs */ + return 0; + + return hwirq; +} + +static int meson_gpio_to_hwirq(struct irq_data *data) +{ + struct meson_pinctrl *pc = meson_gpio_data_to_pc(data); + unsigned int offset = data->hwirq; + struct meson_bank *bank; + int hwirq, ret; + + offset += pc->data->pin_base; + + ret = meson_get_bank(pc, offset, &bank); + if (ret) + return ret; + + hwirq = meson_gpio_bank_hwirq(bank, offset); + if (!hwirq) + dev_dbg(pc->dev, "no interrupt for pin %u\n", offset); + + return hwirq; +} + +static void meson_gpio_irq_handler(struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + struct irq_data *gpio_irq_data = irq_desc_get_handler_data(desc); + + chained_irq_enter(chip, desc); + + if (gpio_irq_data) + generic_handle_irq(gpio_irq_data->irq); + + chained_irq_exit(chip, desc); +} + +static void meson_gpio_irq_unmask(struct irq_data *data) {} +static void meson_gpio_irq_mask(struct irq_data *data) {} + +static void meson_gpio_irq_shutdown(struct irq_data *data) +{ + int hwirq = meson_gpio_to_hwirq(data); + int irq; + + if (hwirq <= 0) + return; + + /* + * In case of IRQ_TYPE_EDGE_BOTH we need two parent interrupts, + * one for each edge. That's due to HW constraints. + * We use format 2 * GPIO_HWIRQ +(0|1) for the hwirq, so we can + * have one GPIO_HWIRQ twice and derive the GPIO_HWIRQ from hwirq + * by shifting hwirq one bit to the right. + */ + irq = irq_find_mapping(meson_pinctrl_irq_domain, hwirq * 2); + if (irq) { + irq_set_chained_handler_and_data(irq, handle_bad_irq, NULL); + irq_domain_free_irqs(irq, 1); + } + + irq = irq_find_mapping(meson_pinctrl_irq_domain, hwirq * 2 + 1); + if (irq) { + irq_set_chained_handler_and_data(irq, handle_bad_irq, NULL); + irq_domain_free_irqs(irq, 1); + } +} + +static int meson_gpio_irq_set_type(struct irq_data *data, unsigned int type) +{ + int hwirq = meson_gpio_to_hwirq(data); + struct irq_fwspec fwspec; + int irq, irq2, num_slots; + + if (irqd_is_activated(data)) + return -EBUSY; + + if (hwirq < 0) + return hwirq; + + if (!hwirq) + return -ENXIO; + + fwspec.fwnode = meson_pinctrl_irq_domain->fwnode; + fwspec.param_count = 2; + + /* + * The chip can create an interrupt for either rising or falling edge + * only. Therefore use two interrupts in case of IRQ_TYPE_EDGE_BOTH, + * first for falling edge and second one for rising edge. + */ + num_slots = (type == IRQ_TYPE_EDGE_BOTH) ? 2 : 1; + + /* see comment in meson_gpio_irq_shutdown why we shift one bit here */ + fwspec.param[0] = hwirq << 1; + if (num_slots == 1) + fwspec.param[1] = type; + else + fwspec.param[1] = IRQ_TYPE_EDGE_FALLING; + + irq = irq_create_fwspec_mapping(&fwspec); + if (!irq) + return -EINVAL; + + irq_set_chained_handler_and_data(irq, meson_gpio_irq_handler, data); + + if (num_slots > 1) { + fwspec.param[0]++; + fwspec.param[1] = IRQ_TYPE_EDGE_RISING; + irq2 = irq_create_fwspec_mapping(&fwspec); + if (!irq2) { + irq_domain_free_irqs(irq, 1); + return -EINVAL; + } + irq_set_chained_handler_and_data(irq2, meson_gpio_irq_handler, data); + } + + return 0; +} + +static struct irq_chip meson_gpio_irq_chip = { + .name = "GPIO", + .irq_set_type = meson_gpio_irq_set_type, + .irq_mask = meson_gpio_irq_mask, + .irq_unmask = meson_gpio_irq_unmask, + .irq_shutdown = meson_gpio_irq_shutdown, +}; + static const struct of_device_id meson_pinctrl_dt_match[] = { { .compatible = "amlogic,meson8-cbus-pinctrl", @@ -558,7 +708,8 @@ static int meson_gpiolib_register(struct meson_pinctrl *pc) return ret; } - return 0; + return gpiochip_irqchip_add(&pc->chip, &meson_gpio_irq_chip, 0, + handle_simple_irq, IRQ_TYPE_NONE); } static struct regmap_config meson_regmap_config = { @@ -637,6 +788,23 @@ static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc, return PTR_ERR(pc->reg_gpio); } + if (!meson_pinctrl_irq_domain) { + np = of_find_compatible_node(NULL, NULL, "amlogic,meson-gpio-intc"); + if (!np) { + dev_err(pc->dev, "interrupt controller DT node not found\n"); + return -EINVAL; + } + + meson_pinctrl_irq_domain = irq_find_host(np); + if (!meson_pinctrl_irq_domain) { + dev_err(pc->dev, "interrupt controller not found\n"); + of_node_put(np); + return -EINVAL; + } + + of_node_put(np); + } + return 0; } -- 2.13.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html
WARNING: multiple messages have this Message-ID (diff)
From: hkallweit1@gmail.com (Heiner Kallweit) To: linus-amlogic@lists.infradead.org Subject: [PATCH v5 6/9] pinctrl: meson: add support for GPIO interrupts Date: Tue, 30 May 2017 22:26:48 +0200 [thread overview] Message-ID: <12e8fe0e-d608-f560-9ddb-7287e10d3db2@gmail.com> (raw) In-Reply-To: <66c57893-0a9e-4f8c-a017-ab346abbdfd0@gmail.com> Add support for GPIO interrupts and make use of the just introduced irqchip driver handling the GPIO interrupt-controller. Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com> --- v5: - changed Kconfig entry based on Neil's suggestion - extended comments - fixed indentation --- drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/meson/pinctrl-meson.c | 170 +++++++++++++++++++++++++++++++++- 2 files changed, 170 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 7ae04a97..86834dea 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -166,6 +166,7 @@ config PINCTRL_MESON select PINCONF select GENERIC_PINCONF select GPIOLIB + select GPIOLIB_IRQCHIP select OF_GPIO select REGMAP_MMIO diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c index 66ed70c1..7bacd4e3 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.c +++ b/drivers/pinctrl/meson/pinctrl-meson.c @@ -62,6 +62,8 @@ #include "../pinctrl-utils.h" #include "pinctrl-meson.h" +static struct irq_domain *meson_pinctrl_irq_domain; + /** * meson_get_bank() - find the bank containing a given pin * @@ -497,6 +499,154 @@ static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio) return !!(val & BIT(bit)); } +static struct meson_pinctrl *meson_gpio_data_to_pc(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + + return gpiochip_get_data(chip); +} + +static int meson_gpio_bank_hwirq(struct meson_bank *bank, unsigned int offset) +{ + int hwirq; + + if (bank->irq_first < 0) + /* this bank cannot generate irqs */ + return 0; + + hwirq = offset - bank->first + bank->irq_first; + + if (hwirq > bank->irq_last) + /* this pin cannot generate irqs */ + return 0; + + return hwirq; +} + +static int meson_gpio_to_hwirq(struct irq_data *data) +{ + struct meson_pinctrl *pc = meson_gpio_data_to_pc(data); + unsigned int offset = data->hwirq; + struct meson_bank *bank; + int hwirq, ret; + + offset += pc->data->pin_base; + + ret = meson_get_bank(pc, offset, &bank); + if (ret) + return ret; + + hwirq = meson_gpio_bank_hwirq(bank, offset); + if (!hwirq) + dev_dbg(pc->dev, "no interrupt for pin %u\n", offset); + + return hwirq; +} + +static void meson_gpio_irq_handler(struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + struct irq_data *gpio_irq_data = irq_desc_get_handler_data(desc); + + chained_irq_enter(chip, desc); + + if (gpio_irq_data) + generic_handle_irq(gpio_irq_data->irq); + + chained_irq_exit(chip, desc); +} + +static void meson_gpio_irq_unmask(struct irq_data *data) {} +static void meson_gpio_irq_mask(struct irq_data *data) {} + +static void meson_gpio_irq_shutdown(struct irq_data *data) +{ + int hwirq = meson_gpio_to_hwirq(data); + int irq; + + if (hwirq <= 0) + return; + + /* + * In case of IRQ_TYPE_EDGE_BOTH we need two parent interrupts, + * one for each edge. That's due to HW constraints. + * We use format 2 * GPIO_HWIRQ +(0|1) for the hwirq, so we can + * have one GPIO_HWIRQ twice and derive the GPIO_HWIRQ from hwirq + * by shifting hwirq one bit to the right. + */ + irq = irq_find_mapping(meson_pinctrl_irq_domain, hwirq * 2); + if (irq) { + irq_set_chained_handler_and_data(irq, handle_bad_irq, NULL); + irq_domain_free_irqs(irq, 1); + } + + irq = irq_find_mapping(meson_pinctrl_irq_domain, hwirq * 2 + 1); + if (irq) { + irq_set_chained_handler_and_data(irq, handle_bad_irq, NULL); + irq_domain_free_irqs(irq, 1); + } +} + +static int meson_gpio_irq_set_type(struct irq_data *data, unsigned int type) +{ + int hwirq = meson_gpio_to_hwirq(data); + struct irq_fwspec fwspec; + int irq, irq2, num_slots; + + if (irqd_is_activated(data)) + return -EBUSY; + + if (hwirq < 0) + return hwirq; + + if (!hwirq) + return -ENXIO; + + fwspec.fwnode = meson_pinctrl_irq_domain->fwnode; + fwspec.param_count = 2; + + /* + * The chip can create an interrupt for either rising or falling edge + * only. Therefore use two interrupts in case of IRQ_TYPE_EDGE_BOTH, + * first for falling edge and second one for rising edge. + */ + num_slots = (type == IRQ_TYPE_EDGE_BOTH) ? 2 : 1; + + /* see comment in meson_gpio_irq_shutdown why we shift one bit here */ + fwspec.param[0] = hwirq << 1; + if (num_slots == 1) + fwspec.param[1] = type; + else + fwspec.param[1] = IRQ_TYPE_EDGE_FALLING; + + irq = irq_create_fwspec_mapping(&fwspec); + if (!irq) + return -EINVAL; + + irq_set_chained_handler_and_data(irq, meson_gpio_irq_handler, data); + + if (num_slots > 1) { + fwspec.param[0]++; + fwspec.param[1] = IRQ_TYPE_EDGE_RISING; + irq2 = irq_create_fwspec_mapping(&fwspec); + if (!irq2) { + irq_domain_free_irqs(irq, 1); + return -EINVAL; + } + irq_set_chained_handler_and_data(irq2, meson_gpio_irq_handler, data); + } + + return 0; +} + +static struct irq_chip meson_gpio_irq_chip = { + .name = "GPIO", + .irq_set_type = meson_gpio_irq_set_type, + .irq_mask = meson_gpio_irq_mask, + .irq_unmask = meson_gpio_irq_unmask, + .irq_shutdown = meson_gpio_irq_shutdown, +}; + static const struct of_device_id meson_pinctrl_dt_match[] = { { .compatible = "amlogic,meson8-cbus-pinctrl", @@ -558,7 +708,8 @@ static int meson_gpiolib_register(struct meson_pinctrl *pc) return ret; } - return 0; + return gpiochip_irqchip_add(&pc->chip, &meson_gpio_irq_chip, 0, + handle_simple_irq, IRQ_TYPE_NONE); } static struct regmap_config meson_regmap_config = { @@ -637,6 +788,23 @@ static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc, return PTR_ERR(pc->reg_gpio); } + if (!meson_pinctrl_irq_domain) { + np = of_find_compatible_node(NULL, NULL, "amlogic,meson-gpio-intc"); + if (!np) { + dev_err(pc->dev, "interrupt controller DT node not found\n"); + return -EINVAL; + } + + meson_pinctrl_irq_domain = irq_find_host(np); + if (!meson_pinctrl_irq_domain) { + dev_err(pc->dev, "interrupt controller not found\n"); + of_node_put(np); + return -EINVAL; + } + + of_node_put(np); + } + return 0; } -- 2.13.0
next prev parent reply other threads:[~2017-05-30 20:26 UTC|newest] Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top 2017-05-30 20:03 [PATCH v5 0/9] pinctrl: meson: add support for GPIO IRQs Heiner Kallweit 2017-05-30 20:03 ` Heiner Kallweit 2017-05-30 20:26 ` [PATCH v5 1/9] pinctrl: meson: add interrupts to pinctrl data Heiner Kallweit 2017-05-30 20:26 ` Heiner Kallweit 2017-05-30 20:26 ` [PATCH v5 2/9] irqchip: add Amlogic Meson GPIO irqchip driver Heiner Kallweit 2017-05-30 20:26 ` Heiner Kallweit 2017-05-30 20:26 ` [PATCH v5 3/9] dt-bindings: add Amlogic Meson GPIO interrupt-controller DT binding documentation Heiner Kallweit 2017-05-30 20:26 ` Heiner Kallweit 2017-06-07 21:13 ` Rob Herring 2017-06-07 21:13 ` Rob Herring 2017-06-09 7:50 ` Neil Armstrong 2017-06-09 7:50 ` Neil Armstrong 2017-06-09 20:58 ` Rob Herring 2017-06-09 20:58 ` Rob Herring 2017-05-30 20:26 ` [PATCH v5 4/9] ARM: dts: meson: add GPIO interrupt-controller support Heiner Kallweit 2017-05-30 20:26 ` Heiner Kallweit 2017-05-30 20:26 ` [PATCH v5 5/9] ARM64: " Heiner Kallweit 2017-05-30 20:26 ` Heiner Kallweit [not found] ` <66c57893-0a9e-4f8c-a017-ab346abbdfd0-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2017-05-30 20:26 ` Heiner Kallweit [this message] 2017-05-30 20:26 ` [PATCH v5 6/9] pinctrl: meson: add support for GPIO interrupts Heiner Kallweit 2017-05-30 20:26 ` [PATCH v5 7/9] pinctrl: meson: update DT binding documentation Heiner Kallweit 2017-05-30 20:26 ` Heiner Kallweit 2017-06-07 21:13 ` Rob Herring 2017-06-07 21:13 ` Rob Herring 2017-05-30 20:27 ` [PATCH v5 8/9] ARM: dts: meson: mark gpio controllers as interrupt controllers Heiner Kallweit 2017-05-30 20:27 ` Heiner Kallweit 2017-05-30 20:27 ` [PATCH v5 9/9] ARM64: " Heiner Kallweit 2017-05-30 20:27 ` Heiner Kallweit
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=12e8fe0e-d608-f560-9ddb-7287e10d3db2@gmail.com \ --to=hkallweit1-re5jqeeqqe8avxtiumwx3w@public.gmane.org \ --cc=devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \ --cc=jbrunet-rdvid1DuHRBWk0Htik3J/w@public.gmane.org \ --cc=khilman-rdvid1DuHRBWk0Htik3J/w@public.gmane.org \ --cc=linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \ --cc=linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \ --cc=linux-gpio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \ --cc=marc.zyngier-5wv7dgnIgG8@public.gmane.org \ --cc=mark.rutland-5wv7dgnIgG8@public.gmane.org \ --cc=narmstrong-rdvid1DuHRBWk0Htik3J/w@public.gmane.org \ --cc=robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \ --cc=tglx-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org \ --cc=thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \ --cc=treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.