2018-03-30 07:06:13

by Baolin Wang

[permalink] [raw]
Subject: [PATCH 1/2] gpio: eic: Add edge trigger emulation for EIC

The Spreadtrum debounce EIC and latch EIC can not support edge trigger,
but most GPIO users (like gpio-key driver) only use the edge trigger,
thus the EIC driver need add some support to emulate the edge trigger
to satisfy this requirement.

Signed-off-by: Baolin Wang <[email protected]>
---
drivers/gpio/gpio-eic-sprd.c | 73 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 73 insertions(+)

diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c
index de7dd93..e0d6a0a 100644
--- a/drivers/gpio/gpio-eic-sprd.c
+++ b/drivers/gpio/gpio-eic-sprd.c
@@ -300,6 +300,7 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
u32 offset = irqd_to_hwirq(data);
+ int state;

switch (sprd_eic->type) {
case SPRD_EIC_DEBOUNCE:
@@ -310,6 +311,17 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
case IRQ_TYPE_LEVEL_LOW:
sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0);
break;
+ case IRQ_TYPE_EDGE_RISING:
+ case IRQ_TYPE_EDGE_FALLING:
+ case IRQ_TYPE_EDGE_BOTH:
+ state = sprd_eic_get(chip, offset);
+ if (state)
+ sprd_eic_update(chip, offset,
+ SPRD_EIC_DBNC_IEV, 0);
+ else
+ sprd_eic_update(chip, offset,
+ SPRD_EIC_DBNC_IEV, 1);
+ break;
default:
return -ENOTSUPP;
}
@@ -324,6 +336,17 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
case IRQ_TYPE_LEVEL_LOW:
sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 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)
+ sprd_eic_update(chip, offset,
+ SPRD_EIC_LATCH_INTPOL, 0);
+ else
+ sprd_eic_update(chip, offset,
+ SPRD_EIC_LATCH_INTPOL, 1);
+ break;
default:
return -ENOTSUPP;
}
@@ -405,6 +428,55 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
return 0;
}

+static void sprd_eic_toggle_trigger(struct gpio_chip *chip, unsigned int irq,
+ unsigned int offset)
+{
+ struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
+ struct irq_data *data = irq_get_irq_data(irq);
+ u32 trigger = irqd_get_trigger_type(data);
+ int state, post_state;
+
+ /*
+ * The debounce EIC and latch EIC can only support level trigger, so we
+ * can toggle the level trigger to emulate the edge trigger.
+ */
+ if ((sprd_eic->type != SPRD_EIC_DEBOUNCE &&
+ sprd_eic->type != SPRD_EIC_LATCH) ||
+ !(trigger & IRQ_TYPE_EDGE_BOTH))
+ return;
+
+ sprd_eic_irq_mask(data);
+ state = sprd_eic_get(chip, offset);
+
+retry:
+ switch (sprd_eic->type) {
+ case SPRD_EIC_DEBOUNCE:
+ if (state)
+ sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0);
+ else
+ sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 1);
+ break;
+ case SPRD_EIC_LATCH:
+ if (state)
+ sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 0);
+ else
+ sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1);
+ break;
+ default:
+ sprd_eic_irq_unmask(data);
+ return;
+ }
+
+ post_state = sprd_eic_get(chip, offset);
+ if (state != post_state) {
+ dev_warn(chip->parent, "EIC level was changed.\n");
+ state = post_state;
+ goto retry;
+ }
+
+ sprd_eic_irq_unmask(data);
+}
+
static int sprd_eic_match_chip_by_type(struct gpio_chip *chip, void *data)
{
enum sprd_eic_type type = *(enum sprd_eic_type *)data;
@@ -448,6 +520,7 @@ static void sprd_eic_handle_one_type(struct gpio_chip *chip)
bank * SPRD_EIC_PER_BANK_NR + n);

generic_handle_irq(girq);
+ sprd_eic_toggle_trigger(chip, girq, n);
}
}
}
--
1.7.9.5



2018-03-30 07:04:58

by Baolin Wang

[permalink] [raw]
Subject: [PATCH 2/2] gpio: pmic_eic: Add edge trigger emulation for PMIC EIC

This patch will toggle the EIC level to emulate the edge trigger to
support PMIC EIC egdge trigger function, which is required by gpio-keys
driver.

Signed-off-by: Baolin Wang <[email protected]>
---
drivers/gpio/gpio-pmic-eic-sprd.c | 58 +++++++++++++++++++++++++++++++++++--
1 file changed, 56 insertions(+), 2 deletions(-)

diff --git a/drivers/gpio/gpio-pmic-eic-sprd.c b/drivers/gpio/gpio-pmic-eic-sprd.c
index 66d68d9..29e044f 100644
--- a/drivers/gpio/gpio-pmic-eic-sprd.c
+++ b/drivers/gpio/gpio-pmic-eic-sprd.c
@@ -178,6 +178,14 @@ static int sprd_pmic_eic_irq_set_type(struct irq_data *data,
case IRQ_TYPE_LEVEL_LOW:
pmic_eic->reg[REG_IEV] = 0;
break;
+ case IRQ_TYPE_EDGE_RISING:
+ case IRQ_TYPE_EDGE_FALLING:
+ case IRQ_TYPE_EDGE_BOTH:
+ /*
+ * Will set the trigger level according to current EIC level
+ * in irq_bus_sync_unlock() interface, so here nothing to do.
+ */
+ break;
default:
return -ENOTSUPP;
}
@@ -197,11 +205,22 @@ static void sprd_pmic_eic_bus_sync_unlock(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip);
+ u32 trigger = irqd_get_trigger_type(data);
u32 offset = irqd_to_hwirq(data);
+ int state;

/* Set irq type */
- sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IEV,
- pmic_eic->reg[REG_IEV]);
+ if (trigger & IRQ_TYPE_EDGE_BOTH) {
+ state = sprd_pmic_eic_get(chip, offset);
+ if (state)
+ sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IEV, 0);
+ else
+ sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IEV, 1);
+ } else {
+ sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IEV,
+ pmic_eic->reg[REG_IEV]);
+ }
+
/* Set irq unmask */
sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IE,
pmic_eic->reg[REG_IE]);
@@ -212,6 +231,35 @@ static void sprd_pmic_eic_bus_sync_unlock(struct irq_data *data)
mutex_unlock(&pmic_eic->buslock);
}

+static void sprd_pmic_eic_toggle_trigger(struct gpio_chip *chip,
+ unsigned int irq, unsigned int offset)
+{
+ u32 trigger = irq_get_trigger_type(irq);
+ int state, post_state;
+
+ if (!(trigger & IRQ_TYPE_EDGE_BOTH))
+ return;
+
+ state = sprd_pmic_eic_get(chip, offset);
+retry:
+ if (state)
+ sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IEV, 0);
+ else
+ sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IEV, 1);
+
+ post_state = sprd_pmic_eic_get(chip, offset);
+ if (state != post_state) {
+ dev_warn(chip->parent, "PMIC EIC level was changed.\n");
+ state = post_state;
+ goto retry;
+ }
+
+ /* Set irq unmask */
+ sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IE, 1);
+ /* Generate trigger start pulse for debounce EIC */
+ sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_TRIG, 1);
+}
+
static irqreturn_t sprd_pmic_eic_irq_handler(int irq, void *data)
{
struct sprd_pmic_eic *pmic_eic = data;
@@ -233,6 +281,12 @@ static irqreturn_t sprd_pmic_eic_irq_handler(int irq, void *data)

girq = irq_find_mapping(chip->irq.domain, n);
handle_nested_irq(girq);
+
+ /*
+ * The PMIC EIC can only support level trigger, so we can
+ * toggle the level trigger to emulate the edge trigger.
+ */
+ sprd_pmic_eic_toggle_trigger(chip, girq, n);
}

return IRQ_HANDLED;
--
1.7.9.5


2018-04-16 08:28:14

by Baolin Wang

[permalink] [raw]
Subject: Re: [PATCH 1/2] gpio: eic: Add edge trigger emulation for EIC

Hi,

On 30 March 2018 at 15:02, Baolin Wang <[email protected]> wrote:
> The Spreadtrum debounce EIC and latch EIC can not support edge trigger,
> but most GPIO users (like gpio-key driver) only use the edge trigger,
> thus the EIC driver need add some support to emulate the edge trigger
> to satisfy this requirement.
>
> Signed-off-by: Baolin Wang <[email protected]>

Any comments for this patch set? Thanks.

> ---
> drivers/gpio/gpio-eic-sprd.c | 73 ++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 73 insertions(+)
>
> diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c
> index de7dd93..e0d6a0a 100644
> --- a/drivers/gpio/gpio-eic-sprd.c
> +++ b/drivers/gpio/gpio-eic-sprd.c
> @@ -300,6 +300,7 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
> struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
> struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
> u32 offset = irqd_to_hwirq(data);
> + int state;
>
> switch (sprd_eic->type) {
> case SPRD_EIC_DEBOUNCE:
> @@ -310,6 +311,17 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
> case IRQ_TYPE_LEVEL_LOW:
> sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0);
> break;
> + case IRQ_TYPE_EDGE_RISING:
> + case IRQ_TYPE_EDGE_FALLING:
> + case IRQ_TYPE_EDGE_BOTH:
> + state = sprd_eic_get(chip, offset);
> + if (state)
> + sprd_eic_update(chip, offset,
> + SPRD_EIC_DBNC_IEV, 0);
> + else
> + sprd_eic_update(chip, offset,
> + SPRD_EIC_DBNC_IEV, 1);
> + break;
> default:
> return -ENOTSUPP;
> }
> @@ -324,6 +336,17 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
> case IRQ_TYPE_LEVEL_LOW:
> sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 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)
> + sprd_eic_update(chip, offset,
> + SPRD_EIC_LATCH_INTPOL, 0);
> + else
> + sprd_eic_update(chip, offset,
> + SPRD_EIC_LATCH_INTPOL, 1);
> + break;
> default:
> return -ENOTSUPP;
> }
> @@ -405,6 +428,55 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
> return 0;
> }
>
> +static void sprd_eic_toggle_trigger(struct gpio_chip *chip, unsigned int irq,
> + unsigned int offset)
> +{
> + struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
> + struct irq_data *data = irq_get_irq_data(irq);
> + u32 trigger = irqd_get_trigger_type(data);
> + int state, post_state;
> +
> + /*
> + * The debounce EIC and latch EIC can only support level trigger, so we
> + * can toggle the level trigger to emulate the edge trigger.
> + */
> + if ((sprd_eic->type != SPRD_EIC_DEBOUNCE &&
> + sprd_eic->type != SPRD_EIC_LATCH) ||
> + !(trigger & IRQ_TYPE_EDGE_BOTH))
> + return;
> +
> + sprd_eic_irq_mask(data);
> + state = sprd_eic_get(chip, offset);
> +
> +retry:
> + switch (sprd_eic->type) {
> + case SPRD_EIC_DEBOUNCE:
> + if (state)
> + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0);
> + else
> + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 1);
> + break;
> + case SPRD_EIC_LATCH:
> + if (state)
> + sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 0);
> + else
> + sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1);
> + break;
> + default:
> + sprd_eic_irq_unmask(data);
> + return;
> + }
> +
> + post_state = sprd_eic_get(chip, offset);
> + if (state != post_state) {
> + dev_warn(chip->parent, "EIC level was changed.\n");
> + state = post_state;
> + goto retry;
> + }
> +
> + sprd_eic_irq_unmask(data);
> +}
> +
> static int sprd_eic_match_chip_by_type(struct gpio_chip *chip, void *data)
> {
> enum sprd_eic_type type = *(enum sprd_eic_type *)data;
> @@ -448,6 +520,7 @@ static void sprd_eic_handle_one_type(struct gpio_chip *chip)
> bank * SPRD_EIC_PER_BANK_NR + n);
>
> generic_handle_irq(girq);
> + sprd_eic_toggle_trigger(chip, girq, n);
> }
> }
> }
> --
> 1.7.9.5
>



--
Baolin.wang
Best Regards

2018-04-26 08:12:27

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH 1/2] gpio: eic: Add edge trigger emulation for EIC

On Fri, Mar 30, 2018 at 9:02 AM, Baolin Wang <[email protected]> wrote:

> The Spreadtrum debounce EIC and latch EIC can not support edge trigger,
> but most GPIO users (like gpio-key driver) only use the edge trigger,
> thus the EIC driver need add some support to emulate the edge trigger
> to satisfy this requirement.
>
> Signed-off-by: Baolin Wang <[email protected]>

Patch applied.

The patch is fine and in line with other kernel drivers doing edge
trigger emulation and we do not hold back on useful features.

But I want to take this opportunity to ping Uwe Kleine-König about
his ideas for an edge trigger emulation library in the gpiolib core,
and whether this also follows the pattern.

I think we have a slew of these drivers doing similar stuff around.

Yours,
Linus Walleij

2018-04-26 08:14:44

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH 2/2] gpio: pmic_eic: Add edge trigger emulation for PMIC EIC

On Fri, Mar 30, 2018 at 9:02 AM, Baolin Wang <[email protected]> wrote:

> This patch will toggle the EIC level to emulate the edge trigger to
> support PMIC EIC egdge trigger function, which is required by gpio-keys
> driver.
>
> Signed-off-by: Baolin Wang <[email protected]>

Patch applied.

Also adding Uwe to this thread so he can have a look.

Yours,
Linus Walleij

2018-04-26 08:32:14

by Uwe Kleine-König

[permalink] [raw]
Subject: Re: [PATCH 1/2] gpio: eic: Add edge trigger emulation for EIC

Hello Linus,

On Thu, Apr 26, 2018 at 10:10:11AM +0200, Linus Walleij wrote:
> On Fri, Mar 30, 2018 at 9:02 AM, Baolin Wang <[email protected]> wrote:
>
> > The Spreadtrum debounce EIC and latch EIC can not support edge trigger,
> > but most GPIO users (like gpio-key driver) only use the edge trigger,
> > thus the EIC driver need add some support to emulate the edge trigger
> > to satisfy this requirement.
> >
> > Signed-off-by: Baolin Wang <[email protected]>
>
> Patch applied.
>
> The patch is fine and in line with other kernel drivers doing edge
> trigger emulation and we do not hold back on useful features.
>
> But I want to take this opportunity to ping Uwe Kleine-K?nig about
> his ideas for an edge trigger emulation library in the gpiolib core,
> and whether this also follows the pattern.

up to now it's still only this: an idea.

Best regards
Uwe

--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |