Skip to content

Commit 86de2d6

Browse files
Johan Carlssonkartben
authored andcommitted
drivers: i2c_mcux_flexcomm: add support for bus recovery.
use the bit bang driver to recover the i2c bus using gpio. Signed-off-by: Johan Carlsson <[email protected]>
1 parent 2bf61e5 commit 86de2d6

File tree

3 files changed

+125
-0
lines changed

3 files changed

+125
-0
lines changed

drivers/i2c/Kconfig.mcux

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ menuconfig I2C_MCUX_FLEXCOMM
1212
help
1313
Enable the mcux flexcomm i2c driver.
1414

15+
config I2C_MCUX_FLEXCOMM_BUS_RECOVERY
16+
bool "Bus recovery support"
17+
depends on I2C_MCUX_FLEXCOMM && PINCTRL
18+
select I2C_BITBANG
19+
help
20+
Enable flexcomm i2c driver bus recovery support via GPIO bitbanging.
21+
1522
config I2C_NXP_TRANSFER_TIMEOUT
1623
int "Transfer timeout [ms]"
1724
default 0

drivers/i2c/i2c_mcux_flexcomm.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
#include <zephyr/drivers/pinctrl.h>
1515
#include <zephyr/drivers/reset.h>
1616

17+
#ifdef CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY
18+
#include "i2c_bitbang.h"
19+
#include <zephyr/drivers/gpio.h>
20+
#endif /* CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY */
21+
1722
#include <zephyr/logging/log.h>
1823
#include <zephyr/irq.h>
1924
LOG_MODULE_REGISTER(mcux_flexcomm);
@@ -34,6 +39,10 @@ struct mcux_flexcomm_config {
3439
uint32_t bitrate;
3540
const struct pinctrl_dev_config *pincfg;
3641
const struct reset_dt_spec reset;
42+
#ifdef CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY
43+
struct gpio_dt_spec scl;
44+
struct gpio_dt_spec sda;
45+
#endif /* CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY */
3746
};
3847

3948
#ifdef CONFIG_I2C_TARGET
@@ -204,6 +213,89 @@ static int mcux_flexcomm_transfer(const struct device *dev,
204213
return ret;
205214
}
206215

216+
#if CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY
217+
static void mcux_flexcomm_bitbang_set_scl(void *io_context, int state)
218+
{
219+
const struct mcux_flexcomm_config *config = io_context;
220+
221+
gpio_pin_set_dt(&config->scl, state);
222+
}
223+
224+
static void mcux_flexcomm_bitbang_set_sda(void *io_context, int state)
225+
{
226+
const struct mcux_flexcomm_config *config = io_context;
227+
228+
gpio_pin_set_dt(&config->sda, state);
229+
}
230+
231+
static int mcux_flexcomm_bitbang_get_sda(void *io_context)
232+
{
233+
const struct mcux_flexcomm_config *config = io_context;
234+
235+
return gpio_pin_get_dt(&config->sda) == 0 ? 0 : 1;
236+
}
237+
238+
static int mcux_flexcomm_recover_bus(const struct device *dev)
239+
{
240+
const struct mcux_flexcomm_config *config = dev->config;
241+
struct mcux_flexcomm_data *data = dev->data;
242+
struct i2c_bitbang bitbang_ctx;
243+
struct i2c_bitbang_io bitbang_io = {
244+
.set_scl = mcux_flexcomm_bitbang_set_scl,
245+
.set_sda = mcux_flexcomm_bitbang_set_sda,
246+
.get_sda = mcux_flexcomm_bitbang_get_sda,
247+
};
248+
uint32_t bitrate_cfg;
249+
int error = 0;
250+
251+
if (!gpio_is_ready_dt(&config->scl)) {
252+
LOG_ERR("SCL GPIO device not ready");
253+
return -EIO;
254+
}
255+
256+
if (!gpio_is_ready_dt(&config->sda)) {
257+
LOG_ERR("SDA GPIO device not ready");
258+
return -EIO;
259+
}
260+
261+
k_sem_take(&data->lock, K_FOREVER);
262+
263+
error = gpio_pin_configure_dt(&config->scl, GPIO_OUTPUT_HIGH);
264+
if (error != 0) {
265+
LOG_ERR("failed to configure SCL GPIO (err %d)", error);
266+
goto restore;
267+
}
268+
269+
error = gpio_pin_configure_dt(&config->sda, GPIO_OUTPUT_HIGH);
270+
if (error != 0) {
271+
LOG_ERR("failed to configure SDA GPIO (err %d)", error);
272+
goto restore;
273+
}
274+
275+
i2c_bitbang_init(&bitbang_ctx, &bitbang_io, (void *)config);
276+
277+
bitrate_cfg = i2c_map_dt_bitrate(config->bitrate) | I2C_MODE_CONTROLLER;
278+
error = i2c_bitbang_configure(&bitbang_ctx, bitrate_cfg);
279+
if (error != 0) {
280+
LOG_ERR("failed to configure I2C bitbang (err %d)", error);
281+
goto restore;
282+
}
283+
284+
error = i2c_bitbang_recover_bus(&bitbang_ctx);
285+
if (error != 0) {
286+
LOG_ERR("failed to recover bus (err %d)", error);
287+
goto restore;
288+
}
289+
290+
restore:
291+
(void)pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
292+
293+
k_sem_give(&data->lock);
294+
295+
return error;
296+
}
297+
#endif /* CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY */
298+
207299
#if defined(CONFIG_I2C_TARGET)
208300

209301
static struct mcux_flexcomm_target_data *mcux_flexcomm_find_free_target(
@@ -522,6 +614,9 @@ static int mcux_flexcomm_init(const struct device *dev)
522614
static DEVICE_API(i2c, mcux_flexcomm_driver_api) = {
523615
.configure = mcux_flexcomm_configure,
524616
.transfer = mcux_flexcomm_transfer,
617+
#if CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY
618+
.recover_bus = mcux_flexcomm_recover_bus,
619+
#endif /* CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY */
525620
#if defined(CONFIG_I2C_TARGET)
526621
.target_register = mcux_flexcomm_target_register,
527622
.target_unregister = mcux_flexcomm_target_unregister,
@@ -531,6 +626,14 @@ static DEVICE_API(i2c, mcux_flexcomm_driver_api) = {
531626
#endif
532627
};
533628

629+
#if CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY
630+
#define I2C_MCUX_FLEXCOMM_SCL_INIT(n) .scl = GPIO_DT_SPEC_INST_GET_OR(n, scl_gpios, {0}),
631+
#define I2C_MCUX_FLEXCOMM_SDA_INIT(n) .sda = GPIO_DT_SPEC_INST_GET_OR(n, sda_gpios, {0}),
632+
#else
633+
#define I2C_MCUX_FLEXCOMM_SCL_INIT(n)
634+
#define I2C_MCUX_FLEXCOMM_SDA_INIT(n)
635+
#endif /* CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY */
636+
534637
#define I2C_MCUX_FLEXCOMM_DEVICE(id) \
535638
PINCTRL_DT_INST_DEFINE(id); \
536639
static void mcux_flexcomm_config_func_##id(const struct device *dev); \
@@ -542,6 +645,8 @@ static DEVICE_API(i2c, mcux_flexcomm_driver_api) = {
542645
.irq_config_func = mcux_flexcomm_config_func_##id, \
543646
.bitrate = DT_INST_PROP(id, clock_frequency), \
544647
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \
648+
I2C_MCUX_FLEXCOMM_SCL_INIT(id) \
649+
I2C_MCUX_FLEXCOMM_SDA_INIT(id) \
545650
.reset = RESET_DT_SPEC_INST_GET(id), \
546651
}; \
547652
static struct mcux_flexcomm_data mcux_flexcomm_data_##id; \

dts/bindings/i2c/nxp,lpc-i2c.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,16 @@ description: LPC I2C node
66
compatible: "nxp,lpc-i2c"
77

88
include: [i2c-controller.yaml, "nxp,lpc-flexcomm.yaml"]
9+
10+
properties:
11+
scl-gpios:
12+
type: phandle-array
13+
description: |
14+
GPIO to which the I2C SCL signal is routed. This is only needed for I2C bus recovery
15+
support.
16+
17+
sda-gpios:
18+
type: phandle-array
19+
description: |
20+
GPIO to which the I2C SDA signal is routed. This is only needed for I2C bus recovery
21+
support.

0 commit comments

Comments
 (0)