Skip to content

Commit

Permalink
pinctrl: rockchip: Fix enable/disable/mask/unmask
Browse files Browse the repository at this point in the history
The Rockchip pinctrl driver was only implementing the "mask" and
"unmask" operations though the hardware actually has two distinct
things: enable/disable and mask/unmask.  It was implementing the
"mask" operations as a hardware enable/disable and always leaving all
interrupts unmasked.

I believe that the old system had some downsides, specifically:
- (Untested) if an interrupt went off while interrupts were "masked"
  it would be lost.  Now it will be kept track of.
- If someone wanted to change an interrupt back into a GPIO (is such a
  thing sensible?) by calling irq_disable() it wouldn't actually take
  effect.  That's because Linux does some extra optimizations when
  there's no true "disable" function: it does a lazy mask.

Let's actually implement enable/disable/mask/unmask properly.

Signed-off-by: Doug Anderson <dianders@chromium.org>
Reviewed-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
  • Loading branch information
Doug Anderson authored and Linus Walleij committed Dec 30, 2014
1 parent 68bda47 commit f2dd028
Showing 1 changed file with 33 additions and 3 deletions.
36 changes: 33 additions & 3 deletions drivers/pinctrl/pinctrl-rockchip.c
Original file line number Diff line number Diff line change
Expand Up @@ -1562,6 +1562,34 @@ static void rockchip_irq_resume(struct irq_data *d)
irq_reg_writel(gc, bank->saved_enables, GPIO_INTEN);
}

static void rockchip_irq_disable(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
u32 val;

irq_gc_lock(gc);

val = irq_reg_readl(gc, GPIO_INTEN);
val &= ~d->mask;
irq_reg_writel(gc, val, GPIO_INTEN);

irq_gc_unlock(gc);
}

static void rockchip_irq_enable(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
u32 val;

irq_gc_lock(gc);

val = irq_reg_readl(gc, GPIO_INTEN);
val |= d->mask;
irq_reg_writel(gc, val, GPIO_INTEN);

irq_gc_unlock(gc);
}

static int rockchip_interrupts_register(struct platform_device *pdev,
struct rockchip_pinctrl *info)
{
Expand Down Expand Up @@ -1600,11 +1628,13 @@ static int rockchip_interrupts_register(struct platform_device *pdev,
gc = irq_get_domain_generic_chip(bank->domain, 0);
gc->reg_base = bank->reg_base;
gc->private = bank;
gc->chip_types[0].regs.mask = GPIO_INTEN;
gc->chip_types[0].regs.mask = GPIO_INTMASK;
gc->chip_types[0].regs.ack = GPIO_PORTS_EOI;
gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit;
gc->chip_types[0].chip.irq_enable = rockchip_irq_enable;
gc->chip_types[0].chip.irq_disable = rockchip_irq_disable;
gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake;
gc->chip_types[0].chip.irq_suspend = rockchip_irq_suspend;
gc->chip_types[0].chip.irq_resume = rockchip_irq_resume;
Expand Down

0 comments on commit f2dd028

Please sign in to comment.