[PATCH 5/5] pintrl: meson: add support for GPIO interrupts
Linus Walleij
linus.walleij at linaro.org
Thu May 11 08:10:36 PDT 2017
On Sun, May 7, 2017 at 6:34 PM, Heiner Kallweit <hkallweit1 at gmail.com> wrote:
> Add support for GPIO interrupts on Amlogic Meson SoC's.
>
> There's a limit of 8 parent interupts which can be used in total.
> Note that IRQ_TYPE_EDGE_BOTH interrupts reserve two parent IRQ's,
> one for each edge.
>
> Signed-off-by: Heiner Kallweit <hkallweit1 at gmail.com>
(..)
> select GPIOLIB
> + select GPIOLIB_IRQCHIP
This is nice.
> +static int meson_gpio_to_hwirq(struct meson_bank *bank, unsigned int offset)
> +{
> + int hwirq;
> +
> + if (bank->irq_first < 0)
> + /* this bank cannot generate irqs */
> + return -EINVAL;
> +
> + hwirq = offset - bank->first + bank->irq_first;
> +
> + if (hwirq > bank->irq_last)
> + /* this pin cannot generate irqs */
> + return -EINVAL;
> +
> + return hwirq;
> +}
So this is the kind of stuff I want the gpiolib core to handle. We
cant just proliferate
hundreds of drivers to bank-to-irq mappings of cascaded IRQs.
> +static int meson_gpio_alloc_irq_slot(struct irq_data *data, int num_slots,
> + int *slots)
> +{
> + int i, cnt = 0;
> +
> + mutex_lock(&meson_gpio_irq_slot_mutex);
> +
> + for (i = 0; i < meson_gpio_num_irq_slots; i++)
> + if (!meson_gpio_irq_slots[i].owner) {
> + meson_gpio_irq_slots[i].owner = data->irq;
> + slots[cnt++] = i;
> + if (cnt == num_slots)
> + break;
> + }
> +
> + if (cnt < num_slots)
> + for (i = 0; i < cnt; i++)
> + meson_gpio_irq_slots[i].owner = 0;
> +
> + mutex_unlock(&meson_gpio_irq_slot_mutex);
> +
> + return cnt == num_slots ? 0 : -ENOSPC;
> +}
I don't understand what is happening here but it looks like a hierarchical
IRQ domain.
> +static int meson_gpio_irq_request_resources(struct irq_data *data)
> +{
> + struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
> + unsigned gpio = irqd_to_hwirq(data);
> +
> + return gpiochip_lock_as_irq(chip, gpio);
> +}
> +
> +static void meson_gpio_irq_release_resources(struct irq_data *data)
> +{
> + struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
> + unsigned gpio = irqd_to_hwirq(data);
> +
> + meson_gpio_free_irq_slot(data);
> + gpiochip_unlock_as_irq(chip, gpio);
> +}
Nice that you implemented this though.
> +static void meson_gpio_set_hwirq(int idx, int hwirq)
> +{
> + int reg = idx > 3 ? REG_PIN_47_SEL : REG_PIN_03_SEL;
> + int shift = 8 * (idx % 4);
> +
> + regmap_update_bits(meson_gpio_irq_regmap, reg, 0xff << shift,
> + hwirq << shift);
> +}
So you program the hardware to route the IRQ, OK.
> +static int meson_gpio_irq_set_type(struct irq_data *data, unsigned int type)
> +{
(...)
> + for (i = 0; i < num_slots; i++) {
> + irq = meson_gpio_irq_slots[slots[i]].irq;
> + ret = irq_set_irq_type(irq, val);
> + if (ret)
> + break;
> + ret = request_irq(irq, meson_gpio_irq_handler, 0,
> + "GPIO parent", data);
> + if (ret)
> + break;
Issueing request_irq() inside .set_type() is definately wrong.
You want to do chained or nested IRQs for this, possible hierarchical
as well.
> + return gpiochip_irqchip_add(&pc->chip, &pc->irq_chip, 0,
> + handle_simple_irq, IRQ_TYPE_NONE);
gpiochip_irqchip_add() should be followed by
gpiochip_set_chained_irqchip() or gpiochip_set_nested_irqchip().
Else we are not providing the helpers you need.
Which I guess is the case.
I'm a bit confused, I think we need a better understanding of how the
hardware works.
Is it a chained interrupt handler where you can select a number of
GPIOs in each bank to cascade IRQs off?
Yours,
Linus Walleij
More information about the linux-amlogic
mailing list