gpio: mmio: introduce BGPIOF_NO_SET_ON_INPUT
authorChuanhong Guo <gch981213@gmail.com>
Sun, 15 Mar 2020 12:13:37 +0000 (20:13 +0800)
committerBartosz Golaszewski <bgolaszewski@baylibre.com>
Wed, 25 Mar 2020 08:50:45 +0000 (09:50 +0100)
Some gpio controllers ignores pin value writing when that pin is
configured as input mode. As a result, bgpio_dir_out should set
pin to output before configuring pin values or gpio pin values
can't be set up properly.
Introduce two variants of bgpio_dir_out: bgpio_dir_out_val_first
and bgpio_dir_out_dir_first, and assign direction_output according
to a new flag: BGPIOF_NO_SET_ON_INPUT.

Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
Tested-by: René van Dorst <opensource@vdorst.com>
Reviewed-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
drivers/gpio/gpio-mmio.c
include/linux/gpio/driver.h

index f729e3e..b778f33 100644 (file)
@@ -389,12 +389,10 @@ static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
        return GPIO_LINE_DIRECTION_IN;
 }
 
-static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+static void bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 {
        unsigned long flags;
 
-       gc->set(gc, gpio, val);
-
        spin_lock_irqsave(&gc->bgpio_lock, flags);
 
        gc->bgpio_dir |= bgpio_line2mask(gc, gpio);
@@ -405,7 +403,21 @@ static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
                gc->write_reg(gc->reg_dir_out, gc->bgpio_dir);
 
        spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+}
 
+static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio,
+                                  int val)
+{
+       bgpio_dir_out(gc, gpio, val);
+       gc->set(gc, gpio, val);
+       return 0;
+}
+
+static int bgpio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio,
+                                  int val)
+{
+       gc->set(gc, gpio, val);
+       bgpio_dir_out(gc, gpio, val);
        return 0;
 }
 
@@ -538,7 +550,10 @@ static int bgpio_setup_direction(struct gpio_chip *gc,
        if (dirout || dirin) {
                gc->reg_dir_out = dirout;
                gc->reg_dir_in = dirin;
-               gc->direction_output = bgpio_dir_out;
+               if (flags & BGPIOF_NO_SET_ON_INPUT)
+                       gc->direction_output = bgpio_dir_out_dir_first;
+               else
+                       gc->direction_output = bgpio_dir_out_val_first;
                gc->direction_input = bgpio_dir_in;
                gc->get_direction = bgpio_get_dir;
        } else {
index 6ef05bc..ed65e00 100644 (file)
@@ -572,6 +572,7 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
 #define BGPIOF_BIG_ENDIAN_BYTE_ORDER   BIT(3)
 #define BGPIOF_READ_OUTPUT_REG_SET     BIT(4) /* reg_set stores output value */
 #define BGPIOF_NO_OUTPUT               BIT(5) /* only input */
+#define BGPIOF_NO_SET_ON_INPUT         BIT(6)
 
 int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
                     irq_hw_number_t hwirq);