Commit 6ef91fcca8a8 ("i2c: mux: relax locking of the top i2c adapter during mux-locked muxing") introduced a new locking concept "mux-locked", so that these muxes lock only the muxes on the parent adapter instead of the whole i2c bus. In case the dt property "mux-locked" is present make use of this concept. This makes interaction between i2c devices behind the mux and devices directly on the bus possible - at least in simple cases. It might not work properly for complex i2c topologies. If the dt property is not present use the parent-locked concept as before. Signed-off-by: Bastian Stender <bst@xxxxxxxxxxxxxx> --- Changes since implicit v1 ("i2c: mux: pca954x: use relaxed locking of the top i2c adapter during mux-locked muxing"): - fix unlocked SMBus access - make mux-locked optional via dt --- drivers/i2c/muxes/i2c-mux-pca954x.c | 32 +++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 09bafd3e68fa..dfa9e8d350c7 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -219,6 +219,7 @@ MODULE_DEVICE_TABLE(of, pca954x_of_match); static int pca954x_reg_write(struct i2c_adapter *adap, struct i2c_client *client, u8 val) { + struct i2c_mux_core *muxc = i2c_get_clientdata(client); int ret = -ENODEV; if (adap->algo->master_xfer) { @@ -230,16 +231,26 @@ static int pca954x_reg_write(struct i2c_adapter *adap, msg.len = 1; buf[0] = val; msg.buf = buf; - ret = __i2c_transfer(adap, &msg, 1); + + if (muxc->mux_locked) + ret = i2c_transfer(adap, &msg, 1); + else + ret = __i2c_transfer(adap, &msg, 1); if (ret >= 0 && ret != 1) ret = -EREMOTEIO; } else { union i2c_smbus_data data; - ret = adap->algo->smbus_xfer(adap, client->addr, + if (muxc->mux_locked) + ret = i2c_smbus_xfer(adap, client->addr, client->flags, I2C_SMBUS_WRITE, val, I2C_SMBUS_BYTE, &data); + else + ret = adap->algo->smbus_xfer(adap, client->addr, + client->flags, + I2C_SMBUS_WRITE, val, + I2C_SMBUS_BYTE, &data); } return ret; @@ -371,7 +382,9 @@ static int pca954x_probe(struct i2c_client *client, bool idle_disconnect_dt; struct gpio_desc *gpio; int num, force, class; + bool mux_locked; struct i2c_mux_core *muxc; + u32 mux_alloc_flags; struct pca954x *data; const struct of_device_id *match; int ret; @@ -379,9 +392,13 @@ static int pca954x_probe(struct i2c_client *client, if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) return -ENODEV; + mux_locked = of_property_read_bool(of_node, "mux-locked"); + + mux_alloc_flags = mux_locked ? I2C_MUX_LOCKED : 0; muxc = i2c_mux_alloc(adap, &client->dev, - PCA954X_MAX_NCHANS, sizeof(*data), 0, - pca954x_select_chan, pca954x_deselect_mux); + PCA954X_MAX_NCHANS, sizeof(*data), + mux_alloc_flags, pca954x_select_chan, + pca954x_deselect_mux); if (!muxc) return -ENOMEM; data = i2c_mux_priv(muxc); @@ -389,6 +406,8 @@ static int pca954x_probe(struct i2c_client *client, i2c_set_clientdata(client, muxc); data->client = client; + muxc->mux_locked = mux_locked; + /* Get the mux out of reset if a reset GPIO is specified. */ gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(gpio)) @@ -470,8 +489,9 @@ static int pca954x_probe(struct i2c_client *client, } dev_info(&client->dev, - "registered %d multiplexed busses for I2C %s %s\n", - num, data->chip->muxtype == pca954x_ismux + "registered %d multiplexed busses for %s-locked I2C %s %s\n", + num, muxc->mux_locked ? "mux" : "parent", + data->chip->muxtype == pca954x_ismux ? "mux" : "switch", client->name); return 0; -- 2.17.0