[PATCH 1/4] i2c: Make deblock delay and SCL clock configurable

Make the delay between SCL line changes and the number of SCL clock changes configurable as a parameter of the deblock function. No functional change.
Signed-off-by: Marek Vasut marex@denx.de --- drivers/i2c/i2c-uclass.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c index 2aa3efe8aa..25af1fabdb 100644 --- a/drivers/i2c/i2c-uclass.c +++ b/drivers/i2c/i2c-uclass.c @@ -502,34 +502,35 @@ static int i2c_gpio_get_pin(struct gpio_desc *pin) }
static int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin, - struct gpio_desc *scl_pin) + struct gpio_desc *scl_pin, + unsigned int scl_count, + unsigned int delay) { - int counter = 9; int ret = 0;
i2c_gpio_set_pin(sda_pin, 1); i2c_gpio_set_pin(scl_pin, 1); - udelay(5); + udelay(delay);
/* Toggle SCL until slave release SDA */ - while (counter-- >= 0) { + while (scl_count-- >= 0) { i2c_gpio_set_pin(scl_pin, 1); - udelay(5); + udelay(delay); i2c_gpio_set_pin(scl_pin, 0); - udelay(5); + udelay(delay); if (i2c_gpio_get_pin(sda_pin)) break; }
/* Then, send I2C stop */ i2c_gpio_set_pin(sda_pin, 0); - udelay(5); + udelay(delay);
i2c_gpio_set_pin(scl_pin, 1); - udelay(5); + udelay(delay);
i2c_gpio_set_pin(sda_pin, 1); - udelay(5); + udelay(delay);
if (!i2c_gpio_get_pin(sda_pin) || !i2c_gpio_get_pin(scl_pin)) ret = -EREMOTEIO; @@ -561,7 +562,7 @@ static int i2c_deblock_gpio(struct udevice *bus) goto out_no_pinctrl; }
- ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL]); + ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL], 9, 5);
ret = pinctrl_select_state(bus, "default"); if (ret) {

Export the i2c_deblock_gpio_loop() so it can be used in other places in U-Boot. In particular, this is useful in the GPIO I2C driver, which claims the SDA/SCL GPIOs and thus prevents the i2c_deblock() implementation from claiming the pins as GPIOs again.
Signed-off-by: Marek Vasut marex@denx.de --- drivers/i2c/i2c-uclass.c | 8 ++++---- include/i2c.h | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c index 25af1fabdb..86f529241f 100644 --- a/drivers/i2c/i2c-uclass.c +++ b/drivers/i2c/i2c-uclass.c @@ -501,10 +501,10 @@ static int i2c_gpio_get_pin(struct gpio_desc *pin) return dm_gpio_get_value(pin); }
-static int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin, - struct gpio_desc *scl_pin, - unsigned int scl_count, - unsigned int delay) +int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin, + struct gpio_desc *scl_pin, + unsigned int scl_count, + unsigned int delay) { int ret = 0;
diff --git a/include/i2c.h b/include/i2c.h index 0faf8542e2..7c92042c58 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -330,6 +330,22 @@ uint i2c_get_chip_addr_offset_mask(struct udevice *dev); */ int i2c_deblock(struct udevice *bus);
+/** + * i2c_deblock_gpio_loop() - recover a bus from an unknown state by toggling SDA/SCL + * + * This is the inner logic used for toggling I2C SDA/SCL lines as GPIOs + * for deblocking the I2C bus. + * + * @sda_pin: SDA GPIO + * @scl_pin: SCL GPIO + * @scl_count: Number of SCL clock cycles generated to deblock SDA + * @delay: Delay between SCL clock line changes + * @return 0 if OK, -ve on error + */ +struct gpio_desc; +int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin, struct gpio_desc *scl_pin, + unsigned int scl_count, unsigned int delay); + /** * struct dm_i2c_ops - driver operations for I2C uclass *

Hello Marek,
Am 07.02.2020 um 16:57 schrieb Marek Vasut:
Export the i2c_deblock_gpio_loop() so it can be used in other places in U-Boot. In particular, this is useful in the GPIO I2C driver, which claims the SDA/SCL GPIOs and thus prevents the i2c_deblock() implementation from claiming the pins as GPIOs again.
Signed-off-by: Marek Vasut marex@denx.de
drivers/i2c/i2c-uclass.c | 8 ++++---- include/i2c.h | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-)
Reviewed-by: Heiko Schocher hs@denx.de
bye, Heiko

Hello Marek,
Am 07.02.2020 um 16:57 schrieb Marek Vasut:
Export the i2c_deblock_gpio_loop() so it can be used in other places in U-Boot. In particular, this is useful in the GPIO I2C driver, which claims the SDA/SCL GPIOs and thus prevents the i2c_deblock() implementation from claiming the pins as GPIOs again.
Signed-off-by: Marek Vasut marex@denx.de
drivers/i2c/i2c-uclass.c | 8 ++++---- include/i2c.h | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-)
Applied to u-boot-i2c next, thanks!
bye, Heiko

Add option to send start condition after deblocking SDA.
Signed-off-by: Marek Vasut marex@denx.de --- drivers/i2c/i2c-uclass.c | 23 ++++++++++++++++++++--- include/i2c.h | 4 +++- 2 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c index 86f529241f..e9ec388576 100644 --- a/drivers/i2c/i2c-uclass.c +++ b/drivers/i2c/i2c-uclass.c @@ -504,9 +504,10 @@ static int i2c_gpio_get_pin(struct gpio_desc *pin) int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin, struct gpio_desc *scl_pin, unsigned int scl_count, + unsigned int start_count, unsigned int delay) { - int ret = 0; + int i, ret = -EREMOTEIO;
i2c_gpio_set_pin(sda_pin, 1); i2c_gpio_set_pin(scl_pin, 1); @@ -518,8 +519,24 @@ int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin, udelay(delay); i2c_gpio_set_pin(scl_pin, 0); udelay(delay); - if (i2c_gpio_get_pin(sda_pin)) + if (i2c_gpio_get_pin(sda_pin)) { + ret = 0; break; + } + } + + if (!ret && start_count) { + for (i = 0; i < start_count; i++) { + /* Send start condition */ + udelay(delay); + i2c_gpio_set_pin(sda_pin, 1); + udelay(delay); + i2c_gpio_set_pin(scl_pin, 1); + udelay(delay); + i2c_gpio_set_pin(sda_pin, 0); + udelay(delay); + i2c_gpio_set_pin(scl_pin, 0); + } }
/* Then, send I2C stop */ @@ -562,7 +579,7 @@ static int i2c_deblock_gpio(struct udevice *bus) goto out_no_pinctrl; }
- ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL], 9, 5); + ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL], 9, 0, 5);
ret = pinctrl_select_state(bus, "default"); if (ret) { diff --git a/include/i2c.h b/include/i2c.h index 7c92042c58..059200115a 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -339,12 +339,14 @@ int i2c_deblock(struct udevice *bus); * @sda_pin: SDA GPIO * @scl_pin: SCL GPIO * @scl_count: Number of SCL clock cycles generated to deblock SDA + * @start_count:Number of I2C start conditions sent after deblocking SDA * @delay: Delay between SCL clock line changes * @return 0 if OK, -ve on error */ struct gpio_desc; int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin, struct gpio_desc *scl_pin, - unsigned int scl_count, unsigned int delay); + unsigned int scl_count, unsigned int start_count, + unsigned int delay);
/** * struct dm_i2c_ops - driver operations for I2C uclass

Hello Marek,
Am 07.02.2020 um 16:57 schrieb Marek Vasut:
Add option to send start condition after deblocking SDA.
Signed-off-by: Marek Vasut marex@denx.de
drivers/i2c/i2c-uclass.c | 23 ++++++++++++++++++++--- include/i2c.h | 4 +++- 2 files changed, 23 insertions(+), 4 deletions(-)
Reviewed-by: Heiko Schocher hs@denx.de
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c index 86f529241f..e9ec388576 100644 --- a/drivers/i2c/i2c-uclass.c +++ b/drivers/i2c/i2c-uclass.c @@ -504,9 +504,10 @@ static int i2c_gpio_get_pin(struct gpio_desc *pin) int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin, struct gpio_desc *scl_pin, unsigned int scl_count,
{unsigned int start_count, unsigned int delay)
- int ret = 0;
int i, ret = -EREMOTEIO;
i2c_gpio_set_pin(sda_pin, 1); i2c_gpio_set_pin(scl_pin, 1);
@@ -518,8 +519,24 @@ int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin, udelay(delay); i2c_gpio_set_pin(scl_pin, 0); udelay(delay);
if (i2c_gpio_get_pin(sda_pin))
if (i2c_gpio_get_pin(sda_pin)) {
ret = 0; break;
}
}
if (!ret && start_count) {
for (i = 0; i < start_count; i++) {
/* Send start condition */
udelay(delay);
i2c_gpio_set_pin(sda_pin, 1);
udelay(delay);
i2c_gpio_set_pin(scl_pin, 1);
udelay(delay);
i2c_gpio_set_pin(sda_pin, 0);
udelay(delay);
i2c_gpio_set_pin(scl_pin, 0);
}
}
/* Then, send I2C stop */
@@ -562,7 +579,7 @@ static int i2c_deblock_gpio(struct udevice *bus) goto out_no_pinctrl; }
- ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL], 9, 5);
ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL], 9, 0, 5);
ret = pinctrl_select_state(bus, "default"); if (ret) {
diff --git a/include/i2c.h b/include/i2c.h index 7c92042c58..059200115a 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -339,12 +339,14 @@ int i2c_deblock(struct udevice *bus);
- @sda_pin: SDA GPIO
- @scl_pin: SCL GPIO
- @scl_count: Number of SCL clock cycles generated to deblock SDA
- @start_count:Number of I2C start conditions sent after deblocking SDA
Is there a tab missing? If so I can add it, when applying this patch.
- @delay: Delay between SCL clock line changes
- @return 0 if OK, -ve on error
*/ struct gpio_desc; int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin, struct gpio_desc *scl_pin,
unsigned int scl_count, unsigned int delay);
unsigned int scl_count, unsigned int start_count,
unsigned int delay);
/**
- struct dm_i2c_ops - driver operations for I2C uclass
bye, Heiko

On 2/18/20 8:07 AM, Heiko Schocher wrote:
Hello Marek,
Hi,
Am 07.02.2020 um 16:57 schrieb Marek Vasut:
Add option to send start condition after deblocking SDA.
Signed-off-by: Marek Vasut marex@denx.de
drivers/i2c/i2c-uclass.c | 23 ++++++++++++++++++++--- include/i2c.h | 4 +++- 2 files changed, 23 insertions(+), 4 deletions(-)
Reviewed-by: Heiko Schocher hs@denx.de
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c index 86f529241f..e9ec388576 100644 --- a/drivers/i2c/i2c-uclass.c +++ b/drivers/i2c/i2c-uclass.c @@ -504,9 +504,10 @@ static int i2c_gpio_get_pin(struct gpio_desc *pin) int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin, struct gpio_desc *scl_pin, unsigned int scl_count, + unsigned int start_count, unsigned int delay) { - int ret = 0; + int i, ret = -EREMOTEIO; i2c_gpio_set_pin(sda_pin, 1); i2c_gpio_set_pin(scl_pin, 1); @@ -518,8 +519,24 @@ int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin, udelay(delay); i2c_gpio_set_pin(scl_pin, 0); udelay(delay); - if (i2c_gpio_get_pin(sda_pin)) + if (i2c_gpio_get_pin(sda_pin)) { + ret = 0; break; + } + }
+ if (!ret && start_count) { + for (i = 0; i < start_count; i++) { + /* Send start condition */ + udelay(delay); + i2c_gpio_set_pin(sda_pin, 1); + udelay(delay); + i2c_gpio_set_pin(scl_pin, 1); + udelay(delay); + i2c_gpio_set_pin(sda_pin, 0); + udelay(delay); + i2c_gpio_set_pin(scl_pin, 0); + } } /* Then, send I2C stop */ @@ -562,7 +579,7 @@ static int i2c_deblock_gpio(struct udevice *bus) goto out_no_pinctrl; } - ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL], 9, 5); + ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL], 9, 0, 5); ret = pinctrl_select_state(bus, "default"); if (ret) { diff --git a/include/i2c.h b/include/i2c.h index 7c92042c58..059200115a 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -339,12 +339,14 @@ int i2c_deblock(struct udevice *bus); * @sda_pin: SDA GPIO * @scl_pin: SCL GPIO * @scl_count: Number of SCL clock cycles generated to deblock SDA
- @start_count:Number of I2C start conditions sent after deblocking SDA
Is there a tab missing? If so I can add it, when applying this patch.
Nope, if you add tab, the formatting starts to look real awful. You can add a space if you feel very inclined to do so, but it would still look ugly.

Hello Marek,
Am 07.02.2020 um 16:57 schrieb Marek Vasut:
Add option to send start condition after deblocking SDA.
Signed-off-by: Marek Vasut marex@denx.de
drivers/i2c/i2c-uclass.c | 23 ++++++++++++++++++++--- include/i2c.h | 4 +++- 2 files changed, 23 insertions(+), 4 deletions(-)
Applied to u-boot-i2c next, thanks!
bye, Heiko

Add deblock dequence for the I2C bus, needed on some devices. This sequence is issued once, when probing the driver, and is controlled by DT property, "i2c-gpio,deblock".
Signed-off-by: Marek Vasut marex@denx.de --- drivers/i2c/i2c-gpio.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/drivers/i2c/i2c-gpio.c b/drivers/i2c/i2c-gpio.c index 4e8fa21473..b6b6ba9ee8 100644 --- a/drivers/i2c/i2c-gpio.c +++ b/drivers/i2c/i2c-gpio.c @@ -305,6 +305,20 @@ static int i2c_gpio_set_bus_speed(struct udevice *dev, unsigned int speed_hz) return 0; }
+static int i2c_gpio_drv_probe(struct udevice *dev) +{ + if (dev_read_bool(dev, "i2c-gpio,deblock")) { + /* @200kHz 9 clocks = 44us, 62us is ok */ + const unsigned int DELAY_ABORT_SEQ = 62; + struct i2c_gpio_bus *bus = dev_get_priv(dev); + return i2c_deblock_gpio_loop(&bus->gpios[PIN_SDA], + &bus->gpios[PIN_SCL], + 16, 5, DELAY_ABORT_SEQ); + } + + return 0; +} + static int i2c_gpio_ofdata_to_platdata(struct udevice *dev) { struct i2c_gpio_bus *bus = dev_get_priv(dev); @@ -341,6 +355,7 @@ U_BOOT_DRIVER(i2c_gpio) = { .name = "i2c-gpio", .id = UCLASS_I2C, .of_match = i2c_gpio_ids, + .probe = i2c_gpio_drv_probe, .ofdata_to_platdata = i2c_gpio_ofdata_to_platdata, .priv_auto_alloc_size = sizeof(struct i2c_gpio_bus), .ops = &i2c_gpio_ops,

Hello Marek,
Am 07.02.2020 um 16:57 schrieb Marek Vasut:
Add deblock dequence for the I2C bus, needed on some devices. This sequence is issued once, when probing the driver, and is controlled by DT property, "i2c-gpio,deblock".
Signed-off-by: Marek Vasut marex@denx.de
drivers/i2c/i2c-gpio.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
Nitpick: I see no entry in doc/device-tree-bindings/i2c/i2c-gpio.txt for the new dts binding ... please send a follow up patch which adds it, or a v2 for this one, thanks!
Reviewed-by: Heiko Schocher hs@denx.de
bye, Heiko
diff --git a/drivers/i2c/i2c-gpio.c b/drivers/i2c/i2c-gpio.c index 4e8fa21473..b6b6ba9ee8 100644 --- a/drivers/i2c/i2c-gpio.c +++ b/drivers/i2c/i2c-gpio.c @@ -305,6 +305,20 @@ static int i2c_gpio_set_bus_speed(struct udevice *dev, unsigned int speed_hz) return 0; }
+static int i2c_gpio_drv_probe(struct udevice *dev) +{
- if (dev_read_bool(dev, "i2c-gpio,deblock")) {
/* @200kHz 9 clocks = 44us, 62us is ok */
const unsigned int DELAY_ABORT_SEQ = 62;
struct i2c_gpio_bus *bus = dev_get_priv(dev);
return i2c_deblock_gpio_loop(&bus->gpios[PIN_SDA],
&bus->gpios[PIN_SCL],
16, 5, DELAY_ABORT_SEQ);
- }
- return 0;
+}
- static int i2c_gpio_ofdata_to_platdata(struct udevice *dev) { struct i2c_gpio_bus *bus = dev_get_priv(dev);
@@ -341,6 +355,7 @@ U_BOOT_DRIVER(i2c_gpio) = { .name = "i2c-gpio", .id = UCLASS_I2C, .of_match = i2c_gpio_ids,
- .probe = i2c_gpio_drv_probe, .ofdata_to_platdata = i2c_gpio_ofdata_to_platdata, .priv_auto_alloc_size = sizeof(struct i2c_gpio_bus), .ops = &i2c_gpio_ops,

On 2/18/20 8:11 AM, Heiko Schocher wrote:
Hello Marek,
Am 07.02.2020 um 16:57 schrieb Marek Vasut:
Add deblock dequence for the I2C bus, needed on some devices. This sequence is issued once, when probing the driver, and is controlled by DT property, "i2c-gpio,deblock".
Signed-off-by: Marek Vasut marex@denx.de
drivers/i2c/i2c-gpio.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
Nitpick: I see no entry in doc/device-tree-bindings/i2c/i2c-gpio.txt for the new dts binding ... please send a follow up patch which adds it, or a v2 for this one, thanks!
Done in [PATCH] doc: i2c: gpio: Document deblock sequence on probe

Hello Marek,
Am 07.02.2020 um 16:57 schrieb Marek Vasut:
Add deblock dequence for the I2C bus, needed on some devices. This sequence is issued once, when probing the driver, and is controlled by DT property, "i2c-gpio,deblock".
Signed-off-by: Marek Vasut marex@denx.de
drivers/i2c/i2c-gpio.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
Applied to u-boot-i2c next, thanks!
bye, Heiko

Hello Marek,
Am 07.02.2020 um 16:57 schrieb Marek Vasut:
Make the delay between SCL line changes and the number of SCL clock changes configurable as a parameter of the deblock function. No functional change.
Signed-off-by: Marek Vasut marex@denx.de
drivers/i2c/i2c-uclass.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-)
Reviewed-by: Heiko Schocher hs@denx.de
bye, Heiko

Hello Marek,
Am 07.02.2020 um 16:57 schrieb Marek Vasut:
Make the delay between SCL line changes and the number of SCL clock changes configurable as a parameter of the deblock function. No functional change.
Signed-off-by: Marek Vasut marex@denx.de
drivers/i2c/i2c-uclass.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-)
Applied to u-boot-i2c next, thanks!
bye, Heiko
participants (2)
-
Heiko Schocher
-
Marek Vasut