Skip to content

Commit e7dd7ab

Browse files
bas-archembeddednashif
authored andcommitted
drivers: i2c: Add support for clock stretching in the i2c-gpio module.
Some I2C peripherals like TI charger or gauge chips need support for I2C clock stretching. This patch includes that and makes these modules usable with I2C emulation over GPIO. Signed-off-by: Bas van Loon <bas@arch-embedded.com>
1 parent d3a7b7d commit e7dd7ab

File tree

4 files changed

+49
-0
lines changed

4 files changed

+49
-0
lines changed

drivers/i2c/Kconfig.gpio

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,19 @@ config I2C_GPIO
88
select I2C_BITBANG
99
help
1010
Enable software driven (bit banging) I2C support using GPIO pins
11+
12+
if I2C_GPIO
13+
14+
config I2C_GPIO_CLOCK_STRETCHING
15+
bool "GPIO bit banging I2C clock stretching support"
16+
default y
17+
help
18+
Enable Slave clock stretching support
19+
20+
config I2C_GPIO_CLOCK_STRETCHING_TIMEOUT_US
21+
int "GPIO bit banging I2C clock stretching timeout (us)"
22+
default 100000
23+
help
24+
Timeout for clock stretching in microseconds.
25+
26+
endif # I2C_GPIO

drivers/i2c/i2c_bitbang.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <errno.h>
2121
#include <zephyr/kernel.h>
2222
#include <zephyr/drivers/i2c.h>
23+
#include <zephyr/sys/util.h>
2324
#include "i2c_bitbang.h"
2425

2526
/*
@@ -79,6 +80,14 @@ int i2c_bitbang_get_config(struct i2c_bitbang *context, uint32_t *config)
7980
static void i2c_set_scl(struct i2c_bitbang *context, int state)
8081
{
8182
context->io->set_scl(context->io_context, state);
83+
#ifdef CONFIG_I2C_GPIO_CLOCK_STRETCHING
84+
if (state == 1) {
85+
/* Wait for slave to release the clock */
86+
WAIT_FOR(context->io->get_scl(context->io_context) != 0,
87+
CONFIG_I2C_GPIO_CLOCK_STRETCHING_TIMEOUT_US,
88+
;);
89+
}
90+
#endif
8291
}
8392

8493
static void i2c_set_sda(struct i2c_bitbang *context, int state)

drivers/i2c/i2c_bitbang.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
struct i2c_bitbang_io {
1313
/* Set the state of the SCL line (zero/non-zero value) */
1414
void (*set_scl)(void *io_context, int state);
15+
#ifdef CONFIG_I2C_GPIO_CLOCK_STRETCHING
16+
/* Return the state of the SCL line (zero/non-zero value) */
17+
int (*get_scl)(void *io_context);
18+
#endif
1519
/* Set the state of the SDA line (zero/non-zero value) */
1620
void (*set_sda)(void *io_context, int state);
1721
/* Return the state of the SDA line (zero/non-zero value) */

drivers/i2c/i2c_gpio.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ static void i2c_gpio_set_scl(void *io_context, int state)
5757
gpio_pin_set_dt(&config->scl_gpio, state);
5858
}
5959

60+
#ifdef CONFIG_I2C_GPIO_CLOCK_STRETCHING
61+
static int i2c_gpio_get_scl(void *io_context)
62+
{
63+
const struct i2c_gpio_config *config = io_context;
64+
int rc = gpio_pin_get_dt(&config->scl_gpio);
65+
66+
return rc != 0;
67+
}
68+
#endif
69+
6070
static void i2c_gpio_set_sda(void *io_context, int state)
6171
{
6272
const struct i2c_gpio_config *config = io_context;
@@ -75,6 +85,9 @@ static int i2c_gpio_get_sda(void *io_context)
7585

7686
static const struct i2c_bitbang_io io_fns = {
7787
.set_scl = &i2c_gpio_set_scl,
88+
#ifdef CONFIG_I2C_GPIO_CLOCK_STRETCHING
89+
.get_scl = &i2c_gpio_get_scl,
90+
#endif
7891
.set_sda = &i2c_gpio_set_sda,
7992
.get_sda = &i2c_gpio_get_sda,
8093
};
@@ -162,7 +175,14 @@ static int i2c_gpio_init(const struct device *dev)
162175
return -ENODEV;
163176
}
164177

178+
#ifdef CONFIG_I2C_GPIO_CLOCK_STRETCHING
179+
err = gpio_pin_configure_dt(&config->scl_gpio, GPIO_INPUT | GPIO_OUTPUT_HIGH);
180+
if (err == -ENOTSUP) {
181+
err = gpio_pin_configure_dt(&config->scl_gpio, GPIO_OUTPUT_HIGH);
182+
}
183+
#else
165184
err = gpio_pin_configure_dt(&config->scl_gpio, GPIO_OUTPUT_HIGH);
185+
#endif
166186
if (err) {
167187
LOG_ERR("failed to configure SCL GPIO pin (err %d)", err);
168188
return err;

0 commit comments

Comments
 (0)