Commit 47beed51 authored by Alexandre Torgue's avatar Alexandre Torgue Committed by Marc Zyngier

pinctrl: stm32: Add level interrupt support to gpio irq chip

GPIO hardware block is directly linked to EXTI block but EXTI handles
external interrupts only on edge. To be able to handle GPIO interrupt on
level a "hack" is done in gpio irq chip: parent interrupt (exti irq chip)
is retriggered following interrupt type and gpio line value.
Signed-off-by: default avatarAlexandre Torgue <alexandre.torgue@st.com>
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Tested-by: default avatarMarek Vasut <marex@denx.de>
Reviewed-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20200219143229.18084-3-alexandre.torgue@st.com
parent 25591d4c
...@@ -92,6 +92,7 @@ struct stm32_gpio_bank { ...@@ -92,6 +92,7 @@ struct stm32_gpio_bank {
u32 bank_nr; u32 bank_nr;
u32 bank_ioport_nr; u32 bank_ioport_nr;
u32 pin_backup[STM32_GPIO_PINS_PER_BANK]; u32 pin_backup[STM32_GPIO_PINS_PER_BANK];
u8 irq_type[STM32_GPIO_PINS_PER_BANK];
}; };
struct stm32_pinctrl { struct stm32_pinctrl {
...@@ -303,6 +304,46 @@ static const struct gpio_chip stm32_gpio_template = { ...@@ -303,6 +304,46 @@ static const struct gpio_chip stm32_gpio_template = {
.get_direction = stm32_gpio_get_direction, .get_direction = stm32_gpio_get_direction,
}; };
void stm32_gpio_irq_eoi(struct irq_data *d)
{
struct stm32_gpio_bank *bank = d->domain->host_data;
int level;
irq_chip_eoi_parent(d);
/* If level interrupt type then retrig */
level = stm32_gpio_get(&bank->gpio_chip, d->hwirq);
if ((level == 0 && bank->irq_type[d->hwirq] == IRQ_TYPE_LEVEL_LOW) ||
(level == 1 && bank->irq_type[d->hwirq] == IRQ_TYPE_LEVEL_HIGH))
irq_chip_retrigger_hierarchy(d);
};
static int stm32_gpio_set_type(struct irq_data *d, unsigned int type)
{
struct stm32_gpio_bank *bank = d->domain->host_data;
u32 parent_type;
switch (type) {
case IRQ_TYPE_EDGE_RISING:
case IRQ_TYPE_EDGE_FALLING:
case IRQ_TYPE_EDGE_BOTH:
parent_type = type;
break;
case IRQ_TYPE_LEVEL_HIGH:
parent_type = IRQ_TYPE_EDGE_RISING;
break;
case IRQ_TYPE_LEVEL_LOW:
parent_type = IRQ_TYPE_EDGE_FALLING;
break;
default:
return -EINVAL;
}
bank->irq_type[d->hwirq] = type;
return irq_chip_set_type_parent(d, parent_type);
};
static int stm32_gpio_irq_request_resources(struct irq_data *irq_data) static int stm32_gpio_irq_request_resources(struct irq_data *irq_data)
{ {
struct stm32_gpio_bank *bank = irq_data->domain->host_data; struct stm32_gpio_bank *bank = irq_data->domain->host_data;
...@@ -332,11 +373,11 @@ static void stm32_gpio_irq_release_resources(struct irq_data *irq_data) ...@@ -332,11 +373,11 @@ static void stm32_gpio_irq_release_resources(struct irq_data *irq_data)
static struct irq_chip stm32_gpio_irq_chip = { static struct irq_chip stm32_gpio_irq_chip = {
.name = "stm32gpio", .name = "stm32gpio",
.irq_eoi = irq_chip_eoi_parent, .irq_eoi = stm32_gpio_irq_eoi,
.irq_ack = irq_chip_ack_parent, .irq_ack = irq_chip_ack_parent,
.irq_mask = irq_chip_mask_parent, .irq_mask = irq_chip_mask_parent,
.irq_unmask = irq_chip_unmask_parent, .irq_unmask = irq_chip_unmask_parent,
.irq_set_type = irq_chip_set_type_parent, .irq_set_type = stm32_gpio_set_type,
.irq_set_wake = irq_chip_set_wake_parent, .irq_set_wake = irq_chip_set_wake_parent,
.irq_request_resources = stm32_gpio_irq_request_resources, .irq_request_resources = stm32_gpio_irq_request_resources,
.irq_release_resources = stm32_gpio_irq_release_resources, .irq_release_resources = stm32_gpio_irq_release_resources,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment