[PATCH] i2c: mux: pca954x: use relaxed locking of the top i2c adapter during mux-locked muxing

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



With an i2c device behind a PCA9540 mux having CONFIG_I2C_DEBUG_BUS enabled
connection timeouts caused by a busy i2c bus can be observed:

  i2c i2c-3: master_xfer[0] W, addr=0x57, len=2
  i2c i2c-3: master_xfer[1] R, addr=0x57, len=128
  i2c i2c-2: <i2c_imx_xfer>
  i2c i2c-2: <i2c_imx_start>
  i2c i2c-2: <i2c_imx_bus_busy>
  i2c i2c-2: <i2c_imx_bus_busy> I2C bus is busy
  i2c i2c-2: <i2c_imx_xfer> exit with: error: -110

This happens due to the locking problem described in 6ef91fcca8a8
("i2c: mux: relax locking of the top i2c adapter during mux-locked muxing"):

The cause of the problem is that the mux is a i2c client on the same i2c bus
that it muxes. Transfers to the mux clients will lock the whole i2c bus prior
to attempting to switch the mux to the correct i2c segment.

The mentioned commit introduced a new locking concept as "mux-locked"
muxes so that these muxes lock only the muxes on the parent adapter
instead of the whole i2c bus when there is a transfer to the slave side of
the mux.

Make use of this new locking concept: use the introduced flag I2C_MUX_LOCKED
along with lock-aware i2c_transfer() instead of __i2c_transfer().

Signed-off-by: Bastian Stender <bst@xxxxxxxxxxxxxx>
---
 drivers/i2c/muxes/i2c-mux-pca954x.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 09bafd3e68fa..0ea970eaa324 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -230,7 +230,7 @@ static int pca954x_reg_write(struct i2c_adapter *adap,
 		msg.len = 1;
 		buf[0] = val;
 		msg.buf = buf;
-		ret = __i2c_transfer(adap, &msg, 1);
+		ret = i2c_transfer(adap, &msg, 1);
 
 		if (ret >= 0 && ret != 1)
 			ret = -EREMOTEIO;
@@ -380,8 +380,9 @@ static int pca954x_probe(struct i2c_client *client,
 		return -ENODEV;
 
 	muxc = i2c_mux_alloc(adap, &client->dev,
-			     PCA954X_MAX_NCHANS, sizeof(*data), 0,
-			     pca954x_select_chan, pca954x_deselect_mux);
+			     PCA954X_MAX_NCHANS, sizeof(*data),
+			     I2C_MUX_LOCKED, pca954x_select_chan,
+			     pca954x_deselect_mux);
 	if (!muxc)
 		return -ENOMEM;
 	data = i2c_mux_priv(muxc);
-- 
2.17.0




[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux