diff options
author | Doug Anderson <dianders@chromium.org> | 2014-11-19 17:51:33 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2014-12-30 07:17:27 -0500 |
commit | f2dd028c2632d107c26b1daed543d9efd4f0decd (patch) | |
tree | bcdd09a8392ca258ef81eac43c1a486f65e79272 /drivers/pinctrl/pinctrl-rockchip.c | |
parent | 68bda47c57c9d671820672badc1cb62211ec4700 (diff) |
pinctrl: rockchip: Fix enable/disable/mask/unmask
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>
Diffstat (limited to 'drivers/pinctrl/pinctrl-rockchip.c')
-rw-r--r-- | drivers/pinctrl/pinctrl-rockchip.c | 36 |
1 files changed, 33 insertions, 3 deletions
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index e91e8453aa78..3c22dbebc80f 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c | |||
@@ -1562,6 +1562,34 @@ static void rockchip_irq_resume(struct irq_data *d) | |||
1562 | irq_reg_writel(gc, bank->saved_enables, GPIO_INTEN); | 1562 | irq_reg_writel(gc, bank->saved_enables, GPIO_INTEN); |
1563 | } | 1563 | } |
1564 | 1564 | ||
1565 | static void rockchip_irq_disable(struct irq_data *d) | ||
1566 | { | ||
1567 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
1568 | u32 val; | ||
1569 | |||
1570 | irq_gc_lock(gc); | ||
1571 | |||
1572 | val = irq_reg_readl(gc, GPIO_INTEN); | ||
1573 | val &= ~d->mask; | ||
1574 | irq_reg_writel(gc, val, GPIO_INTEN); | ||
1575 | |||
1576 | irq_gc_unlock(gc); | ||
1577 | } | ||
1578 | |||
1579 | static void rockchip_irq_enable(struct irq_data *d) | ||
1580 | { | ||
1581 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
1582 | u32 val; | ||
1583 | |||
1584 | irq_gc_lock(gc); | ||
1585 | |||
1586 | val = irq_reg_readl(gc, GPIO_INTEN); | ||
1587 | val |= d->mask; | ||
1588 | irq_reg_writel(gc, val, GPIO_INTEN); | ||
1589 | |||
1590 | irq_gc_unlock(gc); | ||
1591 | } | ||
1592 | |||
1565 | static int rockchip_interrupts_register(struct platform_device *pdev, | 1593 | static int rockchip_interrupts_register(struct platform_device *pdev, |
1566 | struct rockchip_pinctrl *info) | 1594 | struct rockchip_pinctrl *info) |
1567 | { | 1595 | { |
@@ -1600,11 +1628,13 @@ static int rockchip_interrupts_register(struct platform_device *pdev, | |||
1600 | gc = irq_get_domain_generic_chip(bank->domain, 0); | 1628 | gc = irq_get_domain_generic_chip(bank->domain, 0); |
1601 | gc->reg_base = bank->reg_base; | 1629 | gc->reg_base = bank->reg_base; |
1602 | gc->private = bank; | 1630 | gc->private = bank; |
1603 | gc->chip_types[0].regs.mask = GPIO_INTEN; | 1631 | gc->chip_types[0].regs.mask = GPIO_INTMASK; |
1604 | gc->chip_types[0].regs.ack = GPIO_PORTS_EOI; | 1632 | gc->chip_types[0].regs.ack = GPIO_PORTS_EOI; |
1605 | gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit; | 1633 | gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit; |
1606 | gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit; | 1634 | gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; |
1607 | gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; | 1635 | gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit; |
1636 | gc->chip_types[0].chip.irq_enable = rockchip_irq_enable; | ||
1637 | gc->chip_types[0].chip.irq_disable = rockchip_irq_disable; | ||
1608 | gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake; | 1638 | gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake; |
1609 | gc->chip_types[0].chip.irq_suspend = rockchip_irq_suspend; | 1639 | gc->chip_types[0].chip.irq_suspend = rockchip_irq_suspend; |
1610 | gc->chip_types[0].chip.irq_resume = rockchip_irq_resume; | 1640 | gc->chip_types[0].chip.irq_resume = rockchip_irq_resume; |