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 <johan.carlsson@teenage.engineering>
This commit is contained in:
parent
2bf61e51fe
commit
86de2d69ad
3 changed files with 125 additions and 0 deletions
|
|
@ -12,6 +12,13 @@ menuconfig I2C_MCUX_FLEXCOMM
|
|||
help
|
||||
Enable the mcux flexcomm i2c driver.
|
||||
|
||||
config I2C_MCUX_FLEXCOMM_BUS_RECOVERY
|
||||
bool "Bus recovery support"
|
||||
depends on I2C_MCUX_FLEXCOMM && PINCTRL
|
||||
select I2C_BITBANG
|
||||
help
|
||||
Enable flexcomm i2c driver bus recovery support via GPIO bitbanging.
|
||||
|
||||
config I2C_NXP_TRANSFER_TIMEOUT
|
||||
int "Transfer timeout [ms]"
|
||||
default 0
|
||||
|
|
|
|||
|
|
@ -14,6 +14,11 @@
|
|||
#include <zephyr/drivers/pinctrl.h>
|
||||
#include <zephyr/drivers/reset.h>
|
||||
|
||||
#ifdef CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY
|
||||
#include "i2c_bitbang.h"
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#endif /* CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY */
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/irq.h>
|
||||
LOG_MODULE_REGISTER(mcux_flexcomm);
|
||||
|
|
@ -34,6 +39,10 @@ struct mcux_flexcomm_config {
|
|||
uint32_t bitrate;
|
||||
const struct pinctrl_dev_config *pincfg;
|
||||
const struct reset_dt_spec reset;
|
||||
#ifdef CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY
|
||||
struct gpio_dt_spec scl;
|
||||
struct gpio_dt_spec sda;
|
||||
#endif /* CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_I2C_TARGET
|
||||
|
|
@ -204,6 +213,89 @@ static int mcux_flexcomm_transfer(const struct device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
#if CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY
|
||||
static void mcux_flexcomm_bitbang_set_scl(void *io_context, int state)
|
||||
{
|
||||
const struct mcux_flexcomm_config *config = io_context;
|
||||
|
||||
gpio_pin_set_dt(&config->scl, state);
|
||||
}
|
||||
|
||||
static void mcux_flexcomm_bitbang_set_sda(void *io_context, int state)
|
||||
{
|
||||
const struct mcux_flexcomm_config *config = io_context;
|
||||
|
||||
gpio_pin_set_dt(&config->sda, state);
|
||||
}
|
||||
|
||||
static int mcux_flexcomm_bitbang_get_sda(void *io_context)
|
||||
{
|
||||
const struct mcux_flexcomm_config *config = io_context;
|
||||
|
||||
return gpio_pin_get_dt(&config->sda) == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
static int mcux_flexcomm_recover_bus(const struct device *dev)
|
||||
{
|
||||
const struct mcux_flexcomm_config *config = dev->config;
|
||||
struct mcux_flexcomm_data *data = dev->data;
|
||||
struct i2c_bitbang bitbang_ctx;
|
||||
struct i2c_bitbang_io bitbang_io = {
|
||||
.set_scl = mcux_flexcomm_bitbang_set_scl,
|
||||
.set_sda = mcux_flexcomm_bitbang_set_sda,
|
||||
.get_sda = mcux_flexcomm_bitbang_get_sda,
|
||||
};
|
||||
uint32_t bitrate_cfg;
|
||||
int error = 0;
|
||||
|
||||
if (!gpio_is_ready_dt(&config->scl)) {
|
||||
LOG_ERR("SCL GPIO device not ready");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!gpio_is_ready_dt(&config->sda)) {
|
||||
LOG_ERR("SDA GPIO device not ready");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
k_sem_take(&data->lock, K_FOREVER);
|
||||
|
||||
error = gpio_pin_configure_dt(&config->scl, GPIO_OUTPUT_HIGH);
|
||||
if (error != 0) {
|
||||
LOG_ERR("failed to configure SCL GPIO (err %d)", error);
|
||||
goto restore;
|
||||
}
|
||||
|
||||
error = gpio_pin_configure_dt(&config->sda, GPIO_OUTPUT_HIGH);
|
||||
if (error != 0) {
|
||||
LOG_ERR("failed to configure SDA GPIO (err %d)", error);
|
||||
goto restore;
|
||||
}
|
||||
|
||||
i2c_bitbang_init(&bitbang_ctx, &bitbang_io, (void *)config);
|
||||
|
||||
bitrate_cfg = i2c_map_dt_bitrate(config->bitrate) | I2C_MODE_CONTROLLER;
|
||||
error = i2c_bitbang_configure(&bitbang_ctx, bitrate_cfg);
|
||||
if (error != 0) {
|
||||
LOG_ERR("failed to configure I2C bitbang (err %d)", error);
|
||||
goto restore;
|
||||
}
|
||||
|
||||
error = i2c_bitbang_recover_bus(&bitbang_ctx);
|
||||
if (error != 0) {
|
||||
LOG_ERR("failed to recover bus (err %d)", error);
|
||||
goto restore;
|
||||
}
|
||||
|
||||
restore:
|
||||
(void)pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
|
||||
|
||||
k_sem_give(&data->lock);
|
||||
|
||||
return error;
|
||||
}
|
||||
#endif /* CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY */
|
||||
|
||||
#if defined(CONFIG_I2C_TARGET)
|
||||
|
||||
static struct mcux_flexcomm_target_data *mcux_flexcomm_find_free_target(
|
||||
|
|
@ -522,6 +614,9 @@ static int mcux_flexcomm_init(const struct device *dev)
|
|||
static DEVICE_API(i2c, mcux_flexcomm_driver_api) = {
|
||||
.configure = mcux_flexcomm_configure,
|
||||
.transfer = mcux_flexcomm_transfer,
|
||||
#if CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY
|
||||
.recover_bus = mcux_flexcomm_recover_bus,
|
||||
#endif /* CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY */
|
||||
#if defined(CONFIG_I2C_TARGET)
|
||||
.target_register = mcux_flexcomm_target_register,
|
||||
.target_unregister = mcux_flexcomm_target_unregister,
|
||||
|
|
@ -531,6 +626,14 @@ static DEVICE_API(i2c, mcux_flexcomm_driver_api) = {
|
|||
#endif
|
||||
};
|
||||
|
||||
#if CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY
|
||||
#define I2C_MCUX_FLEXCOMM_SCL_INIT(n) .scl = GPIO_DT_SPEC_INST_GET_OR(n, scl_gpios, {0}),
|
||||
#define I2C_MCUX_FLEXCOMM_SDA_INIT(n) .sda = GPIO_DT_SPEC_INST_GET_OR(n, sda_gpios, {0}),
|
||||
#else
|
||||
#define I2C_MCUX_FLEXCOMM_SCL_INIT(n)
|
||||
#define I2C_MCUX_FLEXCOMM_SDA_INIT(n)
|
||||
#endif /* CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY */
|
||||
|
||||
#define I2C_MCUX_FLEXCOMM_DEVICE(id) \
|
||||
PINCTRL_DT_INST_DEFINE(id); \
|
||||
static void mcux_flexcomm_config_func_##id(const struct device *dev); \
|
||||
|
|
@ -542,6 +645,8 @@ static DEVICE_API(i2c, mcux_flexcomm_driver_api) = {
|
|||
.irq_config_func = mcux_flexcomm_config_func_##id, \
|
||||
.bitrate = DT_INST_PROP(id, clock_frequency), \
|
||||
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \
|
||||
I2C_MCUX_FLEXCOMM_SCL_INIT(id) \
|
||||
I2C_MCUX_FLEXCOMM_SDA_INIT(id) \
|
||||
.reset = RESET_DT_SPEC_INST_GET(id), \
|
||||
}; \
|
||||
static struct mcux_flexcomm_data mcux_flexcomm_data_##id; \
|
||||
|
|
|
|||
|
|
@ -6,3 +6,16 @@ description: LPC I2C node
|
|||
compatible: "nxp,lpc-i2c"
|
||||
|
||||
include: [i2c-controller.yaml, "nxp,lpc-flexcomm.yaml"]
|
||||
|
||||
properties:
|
||||
scl-gpios:
|
||||
type: phandle-array
|
||||
description: |
|
||||
GPIO to which the I2C SCL signal is routed. This is only needed for I2C bus recovery
|
||||
support.
|
||||
|
||||
sda-gpios:
|
||||
type: phandle-array
|
||||
description: |
|
||||
GPIO to which the I2C SDA signal is routed. This is only needed for I2C bus recovery
|
||||
support.
|
||||
|
|
|
|||
Loading…
Reference in a new issue