From 54f1840ddee9bbdc8dd89fbbfdfa632401244146 Mon Sep 17 00:00:00 2001 From: Jian Zhang Date: Fri, 6 Oct 2023 10:22:33 +0800 Subject: [PATCH 1/5] i2c: aspeed: Fix i2c bus hang in slave read When the `CONFIG_I2C_SLAVE` option is enabled and the device operates as a slave, a situation arises where the master sends a START signal without the accompanying STOP signal. This action results in a persistent I2C bus timeout. The core issue stems from the fact that the i2c controller remains in a slave read state without a timeout mechanism. As a consequence, the bus perpetually experiences timeouts. In this case, the i2c bus will be reset, but the slave_state reset is missing. Fixes: fee465150b45 ("i2c: aspeed: Reset the i2c controller when timeout occurs") Signed-off-by: Jian Zhang Acked-by: Andi Shyti Tested-by: Andrew Jeffery Reviewed-by: Andrew Jeffery Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-aspeed.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 5a416b39b8183..28e2a5fc45282 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -749,6 +749,8 @@ static void __aspeed_i2c_reg_slave(struct aspeed_i2c_bus *bus, u16 slave_addr) func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG); func_ctrl_reg_val |= ASPEED_I2CD_SLAVE_EN; writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG); + + bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE; } static int aspeed_i2c_reg_slave(struct i2c_client *client) @@ -765,7 +767,6 @@ static int aspeed_i2c_reg_slave(struct i2c_client *client) __aspeed_i2c_reg_slave(bus, client->addr); bus->slave = client; - bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE; spin_unlock_irqrestore(&bus->lock, flags); return 0; From 3171d37b58a76e1febbf3f4af2d06234a98cf88b Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 20 Oct 2023 17:30:11 +0200 Subject: [PATCH 2/5] i2c: muxes: i2c-mux-pinctrl: Use of_get_i2c_adapter_by_node() i2c-mux-pinctrl uses the pair of_find_i2c_adapter_by_node() / i2c_put_adapter(). These pair alone is not correct to properly lock the I2C parent adapter. Indeed, i2c_put_adapter() decrements the module refcount while of_find_i2c_adapter_by_node() does not increment it. This leads to an underflow of the parent module refcount. Use the dedicated function, of_get_i2c_adapter_by_node(), to handle correctly the module refcount. Fixes: c4aee3e1b0de ("i2c: mux: pinctrl: remove platform_data") Signed-off-by: Herve Codina Cc: stable@vger.kernel.org Acked-by: Peter Rosin Reviewed-by: Jonathan Cameron Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-pinctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c index 18236b9fa14a9..6ebca7bfd8a26 100644 --- a/drivers/i2c/muxes/i2c-mux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c @@ -62,7 +62,7 @@ static struct i2c_adapter *i2c_mux_pinctrl_parent_adapter(struct device *dev) dev_err(dev, "Cannot parse i2c-parent\n"); return ERR_PTR(-ENODEV); } - parent = of_find_i2c_adapter_by_node(parent_np); + parent = of_get_i2c_adapter_by_node(parent_np); of_node_put(parent_np); if (!parent) return ERR_PTR(-EPROBE_DEFER); From 0fb118de5003028ad092a4e66fc6d07b86c3bc94 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 20 Oct 2023 17:30:12 +0200 Subject: [PATCH 3/5] i2c: muxes: i2c-demux-pinctrl: Use of_get_i2c_adapter_by_node() i2c-demux-pinctrl uses the pair of_find_i2c_adapter_by_node() / i2c_put_adapter(). These pair alone is not correct to properly lock the I2C parent adapter. Indeed, i2c_put_adapter() decrements the module refcount while of_find_i2c_adapter_by_node() does not increment it. This leads to an underflow of the parent module refcount. Use the dedicated function, of_get_i2c_adapter_by_node(), to handle correctly the module refcount. Fixes: 50a5ba876908 ("i2c: mux: demux-pinctrl: add driver") Signed-off-by: Herve Codina Cc: stable@vger.kernel.org Acked-by: Peter Rosin Reviewed-by: Jonathan Cameron Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-demux-pinctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-demux-pinctrl.c index 22f2280eab7f7..9f2e4aa281593 100644 --- a/drivers/i2c/muxes/i2c-demux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c @@ -61,7 +61,7 @@ static int i2c_demux_activate_master(struct i2c_demux_pinctrl_priv *priv, u32 ne if (ret) goto err; - adap = of_find_i2c_adapter_by_node(priv->chan[new_chan].parent_np); + adap = of_get_i2c_adapter_by_node(priv->chan[new_chan].parent_np); if (!adap) { ret = -ENODEV; goto err_with_revert; From 3dc0ec46f6e7511fc4fdf6b6cda439382bc957f1 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 20 Oct 2023 17:30:13 +0200 Subject: [PATCH 4/5] i2c: muxes: i2c-mux-gpmux: Use of_get_i2c_adapter_by_node() i2c-mux-gpmux uses the pair of_find_i2c_adapter_by_node() / i2c_put_adapter(). These pair alone is not correct to properly lock the I2C parent adapter. Indeed, i2c_put_adapter() decrements the module refcount while of_find_i2c_adapter_by_node() does not increment it. This leads to an underflow of the parent module refcount. Use the dedicated function, of_get_i2c_adapter_by_node(), to handle correctly the module refcount. Fixes: ac8498f0ce53 ("i2c: i2c-mux-gpmux: new driver") Signed-off-by: Herve Codina Cc: stable@vger.kernel.org Acked-by: Peter Rosin Reviewed-by: Jonathan Cameron Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-gpmux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/muxes/i2c-mux-gpmux.c b/drivers/i2c/muxes/i2c-mux-gpmux.c index baccf4bfaf028..8305661e12539 100644 --- a/drivers/i2c/muxes/i2c-mux-gpmux.c +++ b/drivers/i2c/muxes/i2c-mux-gpmux.c @@ -52,7 +52,7 @@ static struct i2c_adapter *mux_parent_adapter(struct device *dev) dev_err(dev, "Cannot parse i2c-parent\n"); return ERR_PTR(-ENODEV); } - parent = of_find_i2c_adapter_by_node(parent_np); + parent = of_get_i2c_adapter_by_node(parent_np); of_node_put(parent_np); if (!parent) return ERR_PTR(-EPROBE_DEFER); From c896ff2dd8f30a6b0a922c83a96f6d43f05f0e92 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Tue, 10 Oct 2023 10:44:54 +0200 Subject: [PATCH 5/5] i2c: stm32f7: Fix PEC handling in case of SMBUS transfers In case of SMBUS byte read with PEC enabled, the whole transfer is split into two commands. A first write command, followed by a read command. The write command does not have any PEC byte and a PEC byte is appended at the end of the read command. (cf Read byte protocol with PEC in SMBUS specification) Within the STM32 I2C controller, handling (either sending or receiving) of the PEC byte is done via the PECBYTE bit in register CR2. Currently, the PECBYTE is set at the beginning of a transfer, which lead to sending a PEC byte at the end of the write command (hence losing the real last byte), and also does not check the PEC byte received during the read command. This patch corrects the function stm32f7_i2c_smbus_xfer_msg in order to only set the PECBYTE during the read command. Fixes: 9e48155f6bfe ("i2c: i2c-stm32f7: Add initial SMBus protocols support") Signed-off-by: Alain Volmat Reviewed-by: Pierre-Yves MORDRET Acked-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 579b30581725f..0d3c9a041b561 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -1059,9 +1059,10 @@ static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, /* Configure PEC */ if ((flags & I2C_CLIENT_PEC) && f7_msg->size != I2C_SMBUS_QUICK) { cr1 |= STM32F7_I2C_CR1_PECEN; - cr2 |= STM32F7_I2C_CR2_PECBYTE; - if (!f7_msg->read_write) + if (!f7_msg->read_write) { + cr2 |= STM32F7_I2C_CR2_PECBYTE; f7_msg->count++; + } } else { cr1 &= ~STM32F7_I2C_CR1_PECEN; cr2 &= ~STM32F7_I2C_CR2_PECBYTE; @@ -1149,8 +1150,10 @@ static void stm32f7_i2c_smbus_rep_start(struct stm32f7_i2c_dev *i2c_dev) f7_msg->stop = true; /* Add one byte for PEC if needed */ - if (cr1 & STM32F7_I2C_CR1_PECEN) + if (cr1 & STM32F7_I2C_CR1_PECEN) { + cr2 |= STM32F7_I2C_CR2_PECBYTE; f7_msg->count++; + } /* Set number of bytes to be transferred */ cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK);