drivers: i2c: tca954x: add support for idle disconnect
Add support for an optional "idle disconnect" feature in the TCA954x I2C multiplexer. When enabled via the `i2c-mux-idle-disconnect` device tree property, the driver will disconnect all channels after each transfer. This helps avoid address conflicts when multiple multiplexers are present on the same I2C bus. Even if the I2C transfer fails, the driver will still attempt to disconnect the channels to ensure the bus is left in a consistent state. If the disconnect operation itself fails, its error code will be returned unless the transfer already failed with a different error. This implementation is inspired by the Linux kernel driver for PCA954x I2C multiplexers. Special thanks to Ofir Shemesh for valuable suggestion. Signed-off-by: Hank Wang <wanghanchi2000@gmail.com>
This commit is contained in:
parent
2dbc10ab6b
commit
e11634e733
2 changed files with 18 additions and 1 deletions
|
@ -18,6 +18,7 @@ struct tca954x_root_config {
|
|||
struct i2c_dt_spec i2c;
|
||||
uint8_t nchans;
|
||||
const struct gpio_dt_spec reset_gpios;
|
||||
bool idle_disconnect;
|
||||
};
|
||||
|
||||
struct tca954x_root_data {
|
||||
|
@ -82,7 +83,7 @@ static int tca954x_transfer(const struct device *dev,
|
|||
const struct tca954x_root_config *config =
|
||||
get_root_config_from_channel(dev);
|
||||
const struct tca954x_channel_config *down_cfg = dev->config;
|
||||
int res;
|
||||
int res, disconnect_res;
|
||||
|
||||
res = k_mutex_lock(&data->lock, K_MSEC(5000));
|
||||
if (res != 0) {
|
||||
|
@ -96,6 +97,14 @@ static int tca954x_transfer(const struct device *dev,
|
|||
|
||||
res = i2c_transfer(config->i2c.bus, msgs, num_msgs, addr);
|
||||
|
||||
if (config->idle_disconnect) {
|
||||
/* Always attempt to disconnect, even if i2c_transfer fails */
|
||||
disconnect_res = tca954x_set_channel(down_cfg->root, 0);
|
||||
if (disconnect_res != 0 && res == 0) {
|
||||
res = disconnect_res;
|
||||
}
|
||||
}
|
||||
|
||||
end_trans:
|
||||
k_mutex_unlock(&data->lock);
|
||||
return res;
|
||||
|
@ -186,6 +195,7 @@ BUILD_ASSERT(CONFIG_I2C_TCA954X_CHANNEL_INIT_PRIO > CONFIG_I2C_TCA954X_ROOT_INIT
|
|||
.nchans = ch, \
|
||||
.reset_gpios = GPIO_DT_SPEC_GET_OR( \
|
||||
DT_INST(inst, ti_tca##n##a), reset_gpios, {0}), \
|
||||
.idle_disconnect = DT_INST_PROP(inst, i2c_mux_idle_disconnect), \
|
||||
}; \
|
||||
static struct tca954x_root_data tca##n##a_data_##inst = { \
|
||||
.lock = Z_MUTEX_INITIALIZER(tca##n##a_data_##inst.lock), \
|
||||
|
|
|
@ -52,6 +52,13 @@ properties:
|
|||
description: |
|
||||
GPIO connected to the controller RESET pin. This pin is active-low.
|
||||
|
||||
i2c-mux-idle-disconnect:
|
||||
type: boolean
|
||||
description: |
|
||||
Forces mux to disconnect all children in idle state. This is
|
||||
necessary for example, if there are several multiplexers on the bus and
|
||||
the devices behind them use same I2C addresses.
|
||||
|
||||
child-binding:
|
||||
description: TCA954x I2C switch channel node
|
||||
include: [i2c-controller.yaml]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue