Commit ef6d24cc authored by Hans de Goede's avatar Hans de Goede Committed by Linus Walleij

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: default avatarHans de Goede <hdegoede@redhat.com>
Acked-by: default avatarMaxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent bd873373
...@@ -1011,6 +1011,7 @@ static const struct sunxi_pinctrl_desc sun4i_a10_pinctrl_data = { ...@@ -1011,6 +1011,7 @@ static const struct sunxi_pinctrl_desc sun4i_a10_pinctrl_data = {
.pins = sun4i_a10_pins, .pins = sun4i_a10_pins,
.npins = ARRAY_SIZE(sun4i_a10_pins), .npins = ARRAY_SIZE(sun4i_a10_pins),
.irq_banks = 1, .irq_banks = 1,
.irq_read_needs_mux = true,
}; };
static int sun4i_a10_pinctrl_probe(struct platform_device *pdev) static int sun4i_a10_pinctrl_probe(struct platform_device *pdev)
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include "../core.h" #include "../core.h"
#include "../../gpio/gpiolib.h"
#include "pinctrl-sunxi.h" #include "pinctrl-sunxi.h"
static struct irq_chip sunxi_pinctrl_edge_irq_chip; static struct irq_chip sunxi_pinctrl_edge_irq_chip;
...@@ -464,10 +465,19 @@ static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *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) static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
{ {
struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev); struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
u32 reg = sunxi_data_reg(offset); u32 reg = sunxi_data_reg(offset);
u8 index = sunxi_data_offset(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; return val;
} }
......
...@@ -77,6 +77,9 @@ ...@@ -77,6 +77,9 @@
#define IRQ_LEVEL_LOW 0x03 #define IRQ_LEVEL_LOW 0x03
#define IRQ_EDGE_BOTH 0x04 #define IRQ_EDGE_BOTH 0x04
#define SUN4I_FUNC_INPUT 0
#define SUN4I_FUNC_IRQ 6
struct sunxi_desc_function { struct sunxi_desc_function {
const char *name; const char *name;
u8 muxval; u8 muxval;
...@@ -94,6 +97,7 @@ struct sunxi_pinctrl_desc { ...@@ -94,6 +97,7 @@ struct sunxi_pinctrl_desc {
int npins; int npins;
unsigned pin_base; unsigned pin_base;
unsigned irq_banks; unsigned irq_banks;
bool irq_read_needs_mux;
}; };
struct sunxi_pinctrl_function { struct sunxi_pinctrl_function {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment