Re: [PATCH V4 1/2] gpio: eic-sprd: Clear interrupt after set the interrupt type

From: Chunyan Zhang
Date: Mon Jan 22 2024 - 05:02:05 EST


On Tue, 9 Jan 2024 at 15:39, Wenhua Lin <Wenhua.Lin@xxxxxxxxxx> wrote:
>
> The raw interrupt status of eic maybe set before the interrupt is enabled,
> since the eic interrupt has a latch function, which would trigger the
> interrupt event once enabled it from user side. To solve this problem,
> interrupts generated before setting the interrupt trigger type are ignored.
>
> Fixes: 25518e024e3a ("gpio: Add Spreadtrum EIC driver support")
> Signed-off-by: Wenhua Lin <Wenhua.Lin@xxxxxxxxxx>

Acked-by: Chunyan Zhang <zhang.lyra@xxxxxxxxx>

> ---
> drivers/gpio/gpio-eic-sprd.c | 32 ++++++++++++++++++++++++++++----
> 1 file changed, 28 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c
> index be7f2fa5aa7b..806b88d8dfb7 100644
> --- a/drivers/gpio/gpio-eic-sprd.c
> +++ b/drivers/gpio/gpio-eic-sprd.c
> @@ -330,20 +330,27 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
> switch (flow_type) {
> case IRQ_TYPE_LEVEL_HIGH:
> sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 1);
> + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IC, 1);
> break;
> case IRQ_TYPE_LEVEL_LOW:
> sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0);
> + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IC, 1);
> break;
> case IRQ_TYPE_EDGE_RISING:
> case IRQ_TYPE_EDGE_FALLING:
> case IRQ_TYPE_EDGE_BOTH:
> state = sprd_eic_get(chip, offset);
> - if (state)
> + if (state) {
> sprd_eic_update(chip, offset,
> SPRD_EIC_DBNC_IEV, 0);
> - else
> + sprd_eic_update(chip, offset,
> + SPRD_EIC_DBNC_IC, 1);
> + } else {
> sprd_eic_update(chip, offset,
> SPRD_EIC_DBNC_IEV, 1);
> + sprd_eic_update(chip, offset,
> + SPRD_EIC_DBNC_IC, 1);
> + }
> break;
> default:
> return -ENOTSUPP;
> @@ -355,20 +362,27 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
> switch (flow_type) {
> case IRQ_TYPE_LEVEL_HIGH:
> sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 0);
> + sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTCLR, 1);
> break;
> case IRQ_TYPE_LEVEL_LOW:
> sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1);
> + sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTCLR, 1);
> break;
> case IRQ_TYPE_EDGE_RISING:
> case IRQ_TYPE_EDGE_FALLING:
> case IRQ_TYPE_EDGE_BOTH:
> state = sprd_eic_get(chip, offset);
> - if (state)
> + if (state) {
> sprd_eic_update(chip, offset,
> SPRD_EIC_LATCH_INTPOL, 0);
> - else
> + sprd_eic_update(chip, offset,
> + SPRD_EIC_LATCH_INTCLR, 1);
> + } else {
> sprd_eic_update(chip, offset,
> SPRD_EIC_LATCH_INTPOL, 1);
> + sprd_eic_update(chip, offset,
> + SPRD_EIC_LATCH_INTCLR, 1);
> + }
> break;
> default:
> return -ENOTSUPP;
> @@ -382,29 +396,34 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
> sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0);
> sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0);
> sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1);
> + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1);
> irq_set_handler_locked(data, handle_edge_irq);
> break;
> case IRQ_TYPE_EDGE_FALLING:
> sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0);
> sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0);
> sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0);
> + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1);
> irq_set_handler_locked(data, handle_edge_irq);
> break;
> case IRQ_TYPE_EDGE_BOTH:
> sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0);
> sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 1);
> + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1);
> irq_set_handler_locked(data, handle_edge_irq);
> break;
> case IRQ_TYPE_LEVEL_HIGH:
> sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0);
> sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1);
> sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1);
> + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1);
> irq_set_handler_locked(data, handle_level_irq);
> break;
> case IRQ_TYPE_LEVEL_LOW:
> sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0);
> sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1);
> sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0);
> + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1);
> irq_set_handler_locked(data, handle_level_irq);
> break;
> default:
> @@ -417,29 +436,34 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
> sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0);
> sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0);
> sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1);
> + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1);
> irq_set_handler_locked(data, handle_edge_irq);
> break;
> case IRQ_TYPE_EDGE_FALLING:
> sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0);
> sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0);
> sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0);
> + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1);
> irq_set_handler_locked(data, handle_edge_irq);
> break;
> case IRQ_TYPE_EDGE_BOTH:
> sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0);
> sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 1);
> + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1);
> irq_set_handler_locked(data, handle_edge_irq);
> break;
> case IRQ_TYPE_LEVEL_HIGH:
> sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0);
> sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1);
> sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1);
> + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1);
> irq_set_handler_locked(data, handle_level_irq);
> break;
> case IRQ_TYPE_LEVEL_LOW:
> sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0);
> sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1);
> sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0);
> + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1);
> irq_set_handler_locked(data, handle_level_irq);
> break;
> default:
> --
> 2.17.1
>