aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeiko Schocher2020-03-16 07:55:06 +0100
committerHeiko Schocher2020-03-16 07:55:06 +0100
commitba6fb2f6aca54c6555742d507290cbfaa655e623 (patch)
treeaed4a6fccbf47832226a0991a657683c779e1698
parent7383edc2fbd56573819f9ca7401105366191b715 (diff)
dm: i2c-gpio: add support for clock stretching
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>
-rw-r--r--doc/device-tree-bindings/i2c/i2c-gpio.txt2
-rw-r--r--drivers/i2c/i2c-gpio.c23
2 files changed, 24 insertions, 1 deletions
diff --git a/doc/device-tree-bindings/i2c/i2c-gpio.txt b/doc/device-tree-bindings/i2c/i2c-gpio.txt
index e29eeba9e6e..b06b8299337 100644
--- a/doc/device-tree-bindings/i2c/i2c-gpio.txt
+++ b/doc/device-tree-bindings/i2c/i2c-gpio.txt
@@ -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:
diff --git a/drivers/i2c/i2c-gpio.c b/drivers/i2c/i2c-gpio.c
index e3a21ad3b29..07fdd343f22 100644
--- a/drivers/i2c/i2c-gpio.c
+++ b/drivers/i2c/i2c-gpio.c
@@ -58,6 +58,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;
if (bit)
@@ -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: