Re: [PATCH v2] i2c: cadence: Add standard bus recovery support

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

 





On 7/4/22 07:54, Shubhrajyoti Datta wrote:
From: Robert Hancock <robert.hancock@xxxxxxxxxx>

Hook up the standard GPIO/pinctrl-based recovery support..
In the discurssion

typo

https://patchwork.ozlabs.org/project/linux-i2c/patch/20211129090116.16628-1-shubhrajyoti.datta@xxxxxxxxxx/

recovery should be done at the beginning of the transaction.
Here we are doing the recovery at the beginning on a timeout.

Signed-off-by: Robert Hancock <robert.hancock@xxxxxxxxxx>
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@xxxxxxx>
---
v2:
Updated the busbusy check on a timeout

  drivers/i2c/busses/i2c-cadence.c | 13 ++++++++++++-
  1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index b4c1ad19cdae..cf15eca1f9e4 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -10,6 +10,7 @@
  #include <linux/i2c.h>
  #include <linux/interrupt.h>
  #include <linux/io.h>
+#include <linux/iopoll.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
  #include <linux/of.h>
@@ -125,6 +126,8 @@
  #define CDNS_I2C_DIVB_MAX	64
#define CDNS_I2C_TIMEOUT_MAX 0xFF
+#define CDNS_I2C_POLL_US	100000
+#define CDNS_I2C_TIMEOUT_US	500000
#define CDNS_I2C_BROKEN_HOLD_BIT BIT(0) @@ -179,6 +182,7 @@ enum cdns_i2c_slave_state {
   * @clk_rate_change_nb:	Notifier block for clock rate changes
   * @quirks:		flag for broken hold bit usage in r1p10
   * @ctrl_reg:		Cached value of the control register.
+ * @rinfo:		Structure holding recovery information.
   * @ctrl_reg_diva_divb: value of fields DIV_A and DIV_B from CR register
   * @slave:		Registered slave instance.
   * @dev_mode:		I2C operating role(master/slave).
@@ -204,6 +208,7 @@ struct cdns_i2c {
  	struct notifier_block clk_rate_change_nb;
  	u32 quirks;
  	u32 ctrl_reg;
+	struct i2c_bus_recovery_info rinfo;
  #if IS_ENABLED(CONFIG_I2C_SLAVE)
  	u16 ctrl_reg_diva_divb;
  	struct i2c_client *slave;
@@ -796,6 +801,7 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
  	/* Wait for the signal of completion */
  	time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout);
  	if (time_left == 0) {
+		i2c_recover_bus(adap);
  		cdns_i2c_master_reset(adap);
  		dev_err(id->adap.dev.parent,
  				"timeout waiting on completion\n");
@@ -852,8 +858,12 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
  #endif
/* Check if the bus is free */
-	if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA) {
+	ret = readl_poll_timeout(id->membase + CDNS_I2C_SR_OFFSET, reg,
+				 !(reg & CDNS_I2C_SR_BA),
+				 CDNS_I2C_POLL_US, CDNS_I2C_TIMEOUT_US);
+	if (ret) {
  		ret = -EAGAIN;
+		i2c_recover_bus(adap);
  		goto out;
  	}
@@ -1278,6 +1288,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
  	id->adap.retries = 3;		/* Default retry value. */
  	id->adap.algo_data = id;
  	id->adap.dev.parent = &pdev->dev;
+	id->adap.bus_recovery_info = &id->rinfo;
  	init_completion(&id->xfer_done);
  	snprintf(id->adap.name, sizeof(id->adap.name),
  		 "Cadence I2C at %08lx", (unsigned long)r_mem->start);

I have no problem with it. I expect you have tested it on the real HW.

Acked-by: Michal Simek <michal.simek@xxxxxxx>

Thanks,
Michal




[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