i2c: rcar: improve bus busy detection
authorWolfram Sang <wsa+renesas@sang-engineering.com>
Sat, 29 Aug 2020 20:38:09 +0000 (22:38 +0200)
committerWolfram Sang <wsa@kernel.org>
Fri, 18 Sep 2020 21:02:02 +0000 (23:02 +0200)
I2C doesn't define a timeout for bus busy, so an arbitrary value like
LOOP_TIMEOUT is not a good idea. Let's use the timeout value in struct
adapter which is meant for such cases and is user-configurable (via
IOCTL). To reduce the load, wait 10us instead of 1us which is good
enough for the slow frequencies used by I2C. Finally, use the
poll_timeout helper instead of open coding it.

Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Signed-off-by: Wolfram Sang <wsa@kernel.org>
drivers/i2c/busses/i2c-rcar.c

index 9e883474db8ceb3894c3fd789d4671e3379e5439..c5ba018d74a7a7497d2f501cee733c89a60f000b 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/i2c.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -221,18 +222,18 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv)
 
 static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
 {
-       int i;
+       int ret;
+       u32 val;
 
-       for (i = 0; i < LOOP_TIMEOUT; i++) {
-               /* make sure that bus is not busy */
-               if (!(rcar_i2c_read(priv, ICMCR) & FSDA))
-                       return 0;
-               udelay(1);
+       ret = readl_poll_timeout(priv->io + ICMCR, val, !(val & FSDA), 10,
+                                priv->adap.timeout);
+       if (ret) {
+               /* Waiting did not help, try to recover */
+               priv->recovery_icmcr = MDBS | OBPC | FSDA | FSCL;
+               ret = i2c_recover_bus(&priv->adap);
        }
 
-       /* Waiting did not help, try to recover */
-       priv->recovery_icmcr = MDBS | OBPC | FSDA | FSCL;
-       return i2c_recover_bus(&priv->adap);
+       return ret;
 }
 
 static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv)