diff mbox series

pca954x: Reset if channel select fails

Message ID DB6PR07MB3509F48523F601D4F6429D069DBA2@DB6PR07MB3509.eurprd07.prod.outlook.com
State Superseded
Delegated to: Andi Shyti
Headers show
Series pca954x: Reset if channel select fails | expand

Commit Message

Wojciech Siudy (Nokia) Aug. 9, 2024, 8:17 a.m. UTC
From da1630ee3ed664df8fbd74c4063ab130c4e98c5d Mon Sep 17 00:00:00 2001
From: Wojciech Siudy <wojciech.siudy@nokia.com>
Date: Fri, 9 Aug 2024 09:59:27 +0200
Subject: [PATCH] pca954x: Reset if channel select fails

Channel selection that has timed out is a symptom of mux'es I2C
subsystem failure. Without sending reset pulse the POR of entire
system would be needed to restore the communication.

Signed-off-by: siudy <wojciech.siudy@nokia.com>
---
 drivers/i2c/muxes/i2c-mux-pca954x.c | 30 +++++++++++++++++++++--------
 1 file changed, 22 insertions(+), 8 deletions(-)

Comments

Andi Shyti Aug. 13, 2024, 11:35 p.m. UTC | #1
Hi Wojciech,

On Fri, Aug 09, 2024 at 08:17:52AM GMT, Wojciech Siudy (Nokia) wrote:
> From da1630ee3ed664df8fbd74c4063ab130c4e98c5d Mon Sep 17 00:00:00 2001
> From: Wojciech Siudy <wojciech.siudy@nokia.com>

Nice to see patches from Nokia :-)

> Date: Fri, 9 Aug 2024 09:59:27 +0200
> Subject: [PATCH] pca954x: Reset if channel select fails

please remove the mail header from the commit log.

If you want your name to appear without the "... (Nokia)" part
you can simply add:

From: Wojciech Siudy <wojciech.siudy@nokia.com>

> Channel selection that has timed out is a symptom of mux'es I2C
> subsystem failure. Without sending reset pulse the POR of entire
> system would be needed to restore the communication.
> 
> Signed-off-by: siudy <wojciech.siudy@nokia.com>

siudy?

...

> @@ -329,6 +345,12 @@ static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
>  		ret = pca954x_reg_write(muxc->parent, client, regval);
>  		data->last_chan = ret < 0 ? 0 : regval;
>  	}
> +	if (ret == -ETIMEDOUT && (data->reset_cont || data->reset_gpio)) {
> +		dev_warn(&client->dev, "channel select failed, resetting...\n");
> +		pca954x_reset_assert(data);
> +		udelay(10);

Why 10?

Andi
Wojciech Siudy (Nokia) Aug. 16, 2024, 12:32 p.m. UTC | #2
Hi Andi,

> Nice to see patches from Nokia :-)
I am glad to hear that :-)

> please remove the mail header from the commit log.
OK.

> Why 10?
Well, the datasheet mentions minimal hold time as 4 ns, so 10 us seems to be exaggeration, however when we get under 1 us must keep in mind potential paths capacity and lack of synchronization between mux and CPU clock, so let's stay with 1 us that I will post in next version of the patch.

Regards,
Wojciech
diff mbox series

Patch

diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 6f8401825..0034e663b 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -316,6 +316,22 @@  static u8 pca954x_regval(struct pca954x *data, u8 chan)
 		return 1 << chan;
 }
 
+static void pca954x_reset_deassert(struct pca954x *data)
+{
+	if (data->reset_cont)
+		reset_control_deassert(data->reset_cont);
+	else
+		gpiod_set_value_cansleep(data->reset_gpio, 0);
+}
+
+static void pca954x_reset_assert(struct pca954x *data)
+{
+	if (data->reset_cont)
+		reset_control_assert(data->reset_cont);
+	else
+		gpiod_set_value_cansleep(data->reset_gpio, 1);
+}
+
 static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
 {
 	struct pca954x *data = i2c_mux_priv(muxc);
@@ -329,6 +345,12 @@  static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
 		ret = pca954x_reg_write(muxc->parent, client, regval);
 		data->last_chan = ret < 0 ? 0 : regval;
 	}
+	if (ret == -ETIMEDOUT && (data->reset_cont || data->reset_gpio)) {
+		dev_warn(&client->dev, "channel select failed, resetting...\n");
+		pca954x_reset_assert(data);
+		udelay(10);
+		pca954x_reset_deassert(data);
+	}
 
 	return ret;
 }
@@ -543,14 +565,6 @@  static int pca954x_get_reset(struct device *dev, struct pca954x *data)
 	return 0;
 }
 
-static void pca954x_reset_deassert(struct pca954x *data)
-{
-	if (data->reset_cont)
-		reset_control_deassert(data->reset_cont);
-	else
-		gpiod_set_value_cansleep(data->reset_gpio, 0);
-}
-
 /*
  * I2C init/probing/exit functions
  */