CHROMIUM: i2c: core: add retries when probing devices

I2C device may be sleeping while being probed. This may lead to the
first read being unsuccessful. Some devices are known to wake at the
first clock of such read, so retry probing several times.
Add more debug so that dmesg contains more explicit messages on how
many retries have been actually performed.

BUG=b:197877804
TEST=Build and upload the kernel to a chromebook device. Make sure it
works.

Signed-off-by: Angela Czubak <acz@semihalf.com>
Change-Id: I0efd32a8b8de3015f9e10bccfa6e5533f7db5776
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/3172565
Reviewed-by: Radoslaw Biernacki <biernacki@google.com>
Commit-Queue: Radoslaw Biernacki <biernacki@google.com>
Tested-by: Radoslaw Biernacki <biernacki@google.com>
diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c
index 6847948..30e30e9 100644
--- a/drivers/i2c/i2c-core-acpi.c
+++ b/drivers/i2c/i2c-core-acpi.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
@@ -184,8 +185,22 @@
 
 	if (!acpi_dev_get_property(adev, "linux,probed", ACPI_TYPE_ANY, NULL)) {
 		unsigned short addrs[] = { info->addr, I2C_CLIENT_END };
+		int probe_retries = I2C_PROBE_RETRIES;
 
-		client = i2c_new_probed_device(adapter, info, addrs, NULL);
+		/* The device may be in deep sleep and will actually wake on
+		 * the rising edge of the I2C clock. It may then fail to
+		 * respond, so perform more reads.
+		 */
+		while (probe_retries--) {
+			/* Test address responsiveness */
+			client = i2c_new_probed_device(adapter, info, addrs,
+						       NULL);
+			if (client)
+				break;
+			msleep(I2C_PROBE_DELAY_MS);
+		}
+		dev_dbg(&adapter->dev, "Probe retries left: %d\n",
+			probe_retries);
 	} else {
 		client = i2c_new_device(adapter, info);
 	}
diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c
index c40eeb65..d3637a3 100644
--- a/drivers/i2c/i2c-core-of.c
+++ b/drivers/i2c/i2c-core-of.c
@@ -13,6 +13,7 @@
  */
 
 #include <dt-bindings/i2c/i2c.h>
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
@@ -80,8 +81,23 @@
 	/* Allow device property to enable probing before init */
 	if (of_get_property(node, "linux,probed", NULL)) {
 		unsigned short addrs[] = { info.addr, I2C_CLIENT_END };
+		int probe_retries = I2C_PROBE_RETRIES;
 
-		client = i2c_new_probed_device(adap, &info, addrs, NULL);
+		/* The device may be in deep sleep and will actually wake on
+		 * the rising edge of the I2C clock. It may then fail to
+		 * respond, so perform more reads.
+		 */
+		while (probe_retries--) {
+			/* Test address responsiveness */
+			client = i2c_new_probed_device(adap, &info, addrs,
+						       NULL);
+			if (client)
+				break;
+			msleep(I2C_PROBE_DELAY_MS);
+		}
+		dev_dbg(&adap->dev, "Probe retries left: %d\n",
+			probe_retries);
+
 	} else {
 		client = i2c_new_device(adap, &info);
 	}
diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h
index 37576f5..a18d5a5 100644
--- a/drivers/i2c/i2c-core.h
+++ b/drivers/i2c/i2c-core.h
@@ -14,6 +14,9 @@
 
 #include <linux/rwsem.h>
 
+#define I2C_PROBE_DELAY_MS 30
+#define I2C_PROBE_RETRIES 5
+
 struct i2c_devinfo {
 	struct list_head	list;
 	int			busnum;