diff options
author | Hans de Goede <hdegoede@redhat.com> | 2015-03-08 22:13:57 +0100 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2015-03-18 10:56:46 +0100 |
commit | ef6d24cc7f5b2b5c4184eddb039e2add6231a122 (patch) | |
tree | e32481835c8e61ef2dc01c7e1ea797c9c8206c00 /drivers/pinctrl/sunxi/pinctrl-sunxi.c | |
parent | bd8733738c5af6114dd15d340b3f8713e9b624c2 (diff) | |
download | blackbird-obmc-linux-ef6d24cc7f5b2b5c4184eddb039e2add6231a122.tar.gz blackbird-obmc-linux-ef6d24cc7f5b2b5c4184eddb039e2add6231a122.zip |
pinctrl: sun4i: GPIOs configured as irq must be set to input before reading
On sun4i-a10, when GPIOs are configured as external interrupt the value for
them in the data register does not seem to get updated, so set their mux to
input (and restore afterwards) when reading the pin.
Missed edges seem to be buffered, so this does not introduce a race
condition.
I've also tested this on sun5i-a13 and sun7i-a20 and those do not seem to
be affected, the input value representation in the data register does seem
to correctly get updated to the actual pin value while in irq mode there.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/sunxi/pinctrl-sunxi.c')
-rw-r--r-- | drivers/pinctrl/sunxi/pinctrl-sunxi.c | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 3d0744337736..f8e171b76693 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -29,6 +29,7 @@ #include <linux/slab.h> #include "../core.h" +#include "../../gpio/gpiolib.h" #include "pinctrl-sunxi.h" static struct irq_chip sunxi_pinctrl_edge_irq_chip; @@ -464,10 +465,19 @@ static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip, static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset) { struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev); - u32 reg = sunxi_data_reg(offset); u8 index = sunxi_data_offset(offset); - u32 val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK; + u32 set_mux = pctl->desc->irq_read_needs_mux && + test_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags); + u32 val; + + if (set_mux) + sunxi_pmx_set(pctl->pctl_dev, offset, SUN4I_FUNC_INPUT); + + val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK; + + if (set_mux) + sunxi_pmx_set(pctl->pctl_dev, offset, SUN4I_FUNC_IRQ); return val; } |