]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
dm: i2c-gpio: add support for clock stretching
authorHeiko Schocher <hs@denx.de>
Mon, 16 Mar 2020 06:55:06 +0000 (07:55 +0100)
committerHeiko Schocher <hs@denx.de>
Mon, 16 Mar 2020 06:55:06 +0000 (07:55 +0100)
This adds support for clock stretching to the i2c-gpio driver. This is
accomplished by switching the GPIO used for the SCL line to an input
when it should be driven high, and polling on the SCL line value until
it goes high (indicating that the I2C slave is no longer pulling it
low).

This is enabled by default; for gpios which cannot be configured as
inputs, the i2c-gpio,scl-output-only property can be used to fall back
to the previous behavior.

Signed-off-by: Michael Auchter <michael.auchter@ni.com>
Cc: Heiko Schocher <hs@denx.de>
Reviewed-by: Heiko Schocher <hs@denx.de>
doc/device-tree-bindings/i2c/i2c-gpio.txt
drivers/i2c/i2c-gpio.c

index e29eeba9e6e51fac400424625aab6ceb935c145e..b06b829933746227387b4435a91f2035c191db85 100644 (file)
@@ -18,6 +18,8 @@ Optional:
    It not defined, then default is 5us (~50KHz).
 * i2c-gpio,deblock
    Run deblocking sequence when the driver gets probed.
+* i2c-gpio,scl-output-only;
+   Set if SCL is an output only
 
 Example:
 
index e3a21ad3b294f65bfcd634753c66178dcf69d0f8..07fdd343f22c6938f421fd440789e73f7c928f6b 100644 (file)
@@ -56,6 +56,24 @@ static void i2c_gpio_sda_set(struct i2c_gpio_bus *bus, int bit)
 }
 
 static void i2c_gpio_scl_set(struct i2c_gpio_bus *bus, int bit)
+{
+       struct gpio_desc *scl = &bus->gpios[PIN_SCL];
+       int count = 0;
+
+       if (bit) {
+               dm_gpio_set_dir_flags(scl, GPIOD_IS_IN);
+               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);
+       }
+}
+
+/* variant for output only gpios which cannot support clock stretching */
+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;
@@ -328,7 +346,10 @@ static int i2c_gpio_ofdata_to_platdata(struct udevice *dev)
 
        bus->get_sda = i2c_gpio_sda_get;
        bus->set_sda = i2c_gpio_sda_set;
-       bus->set_scl = i2c_gpio_scl_set;
+       if (fdtdec_get_bool(blob, node, "i2c-gpio,scl-output-only"))
+               bus->set_scl = i2c_gpio_scl_set_output_only;
+       else
+               bus->set_scl = i2c_gpio_scl_set;
 
        return 0;
 error: