diff mbox series

i2c: i2c-gpio: Fix GPIO output

Message ID 6fd4b2942c49075a1e96e6f24dc13f38d6c6721d.camel@nedap.com
State New
Delegated to: Heiko Schocher
Headers show
Series i2c: i2c-gpio: Fix GPIO output | expand

Commit Message

Harm Berntsen Nov. 29, 2020, 9:47 a.m. UTC
The dm_gpio_set_dir_flags function cannot be used to update the
configuration of a GPIO pin because it does a bitwise OR with the
existing flags. Looks like commit 788ea834124b ("gpio: add function
_dm_gpio_set_dir_flags") has introduced this behaviour and the i2c-gpio
driver has been broken since.

Signed-off-by: Harm Berntsen <harm.berntsen@nedap.com>
CC: Heiko Schocher <hs@denx.de>
CC: Patrick Delaunay <patrick.delaunay@st.com>
---

 drivers/i2c/i2c-gpio.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)
diff mbox series

Patch

diff --git a/drivers/i2c/i2c-gpio.c b/drivers/i2c/i2c-gpio.c
index 381938c956..9c5e0d4d68 100644
--- a/drivers/i2c/i2c-gpio.c
+++ b/drivers/i2c/i2c-gpio.c
@@ -50,9 +50,10 @@  static void i2c_gpio_sda_set(struct i2c_gpio_bus *bus, int bit)
 	struct gpio_desc *sda = &bus->gpios[PIN_SDA];
 
 	if (bit)
-		dm_gpio_set_dir_flags(sda, GPIOD_IS_IN);
+		sda->flags = (sda->flags & ~GPIOD_IS_OUT) | GPIOD_IS_IN;
 	else
-		dm_gpio_set_dir_flags(sda, GPIOD_IS_OUT);
+		sda->flags = (sda->flags & (~GPIOD_IS_IN & ~GPIOD_IS_OUT_ACTIVE)) | GPIOD_IS_OUT;
+	dm_gpio_set_dir(sda);
 }
 
 static void i2c_gpio_scl_set(struct i2c_gpio_bus *bus, int bit)
@@ -61,14 +62,16 @@  static void i2c_gpio_scl_set(struct i2c_gpio_bus *bus, int bit)
 	int count = 0;
 
 	if (bit) {
-		dm_gpio_set_dir_flags(scl, GPIOD_IS_IN);
+		scl->flags = (scl->flags & ~GPIOD_IS_OUT) | GPIOD_IS_IN;
+		dm_gpio_set_dir(scl);
 		while (!dm_gpio_get_value(scl) && count++ < 100000)
 			udelay(1);
 
 		if (!dm_gpio_get_value(scl))
 			pr_err("timeout waiting on slave to release scl\n");
 	} else {
-		dm_gpio_set_dir_flags(scl, GPIOD_IS_OUT);
+		scl->flags = (scl->flags & (~GPIOD_IS_IN & ~GPIOD_IS_OUT_ACTIVE)) | GPIOD_IS_OUT;
+		dm_gpio_set_dir(scl);
 	}
 }
 
@@ -76,11 +79,11 @@  static void i2c_gpio_scl_set(struct i2c_gpio_bus *bus, int bit)
 static void i2c_gpio_scl_set_output_only(struct i2c_gpio_bus *bus, int bit)
 {
 	struct gpio_desc *scl = &bus->gpios[PIN_SCL];
-	ulong flags = GPIOD_IS_OUT;
+	scl->flags = (scl->flags & (~GPIOD_IS_IN & ~GPIOD_IS_OUT_ACTIVE)) | GPIOD_IS_OUT;
 
 	if (bit)
-		flags |= GPIOD_IS_OUT_ACTIVE;
-	dm_gpio_set_dir_flags(scl, flags);
+		scl->flags |= GPIOD_IS_OUT_ACTIVE;
+	dm_gpio_set_dir(scl);
 }
 
 static void i2c_gpio_write_bit(struct i2c_gpio_bus *bus, int delay, uchar bit)