All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] rv8803: workaround i2c HW issue
@ 2016-03-21 14:58 ` Alexandre Belloni
  0 siblings, 0 replies; 2+ messages in thread
From: Alexandre Belloni @ 2016-03-21 14:58 UTC (permalink / raw)
  To: rtc-linux; +Cc: Alessandro Zummo, linux-kernel, Alexandre Belloni

The rv8803 has a 60µs window where it will not answer on the i2c bus.
It also means there will be no ack for the communication. Make sure
communication is tried multiple times when this happens (the i2c subsystem
mandates -ENXIO is that case but the number of retries is host specific).
The critical parts are the probe function and the alarm callback so make
sure we handle the failure there.

Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
 drivers/rtc/rtc-rv8803.c | 28 ++++++++++++++++++++++------
 1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c
index 7155c0816aa6..82ab41074156 100644
--- a/drivers/rtc/rtc-rv8803.c
+++ b/drivers/rtc/rtc-rv8803.c
@@ -61,11 +61,14 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id)
 	struct i2c_client *client = dev_id;
 	struct rv8803_data *rv8803 = i2c_get_clientdata(client);
 	unsigned long events = 0;
-	int flags;
+	int flags, try = 0;
 
 	spin_lock(&rv8803->flags_lock);
 
-	flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
+	do {
+		flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
+		try++;
+	} while ((flags == -ENXIO) && (try < 3));
 	if (flags <= 0) {
 		spin_unlock(&rv8803->flags_lock);
 		return IRQ_NONE;
@@ -428,7 +431,7 @@ static int rv8803_probe(struct i2c_client *client,
 {
 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
 	struct rv8803_data *rv8803;
-	int err, flags;
+	int err, flags, try = 0;
 
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
 				     I2C_FUNC_SMBUS_I2C_BLOCK)) {
@@ -444,7 +447,16 @@ static int rv8803_probe(struct i2c_client *client,
 	rv8803->client = client;
 	i2c_set_clientdata(client, rv8803);
 
-	flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
+	/* 
+	 * There is a 60µs window where the RTC may not reply on the i2c bus in
+	 * that case, the transfer is not ACKed. In that case, ensure there are
+	 * multiple attempts.
+	 */
+	do {
+		flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
+		try++;
+	} while ((flags == -ENXIO) && (try < 3));
+
 	if (flags < 0)
 		return flags;
 
@@ -479,8 +491,12 @@ static int rv8803_probe(struct i2c_client *client,
 		return PTR_ERR(rv8803->rtc);
 	}
 
-	err = i2c_smbus_write_byte_data(rv8803->client, RV8803_EXT,
-					RV8803_EXT_WADA);
+	try = 0;
+	do {
+		err = i2c_smbus_write_byte_data(rv8803->client, RV8803_EXT,
+						RV8803_EXT_WADA);
+		try++;
+	} while ((err == -ENXIO) && (try < 3));
 	if (err)
 		return err;
 
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [rtc-linux] [PATCH] rv8803: workaround i2c HW issue
@ 2016-03-21 14:58 ` Alexandre Belloni
  0 siblings, 0 replies; 2+ messages in thread
From: Alexandre Belloni @ 2016-03-21 14:58 UTC (permalink / raw)
  To: rtc-linux; +Cc: Alessandro Zummo, linux-kernel, Alexandre Belloni

The rv8803 has a 60=C2=B5s window where it will not answer on the i2c bus.
It also means there will be no ack for the communication. Make sure
communication is tried multiple times when this happens (the i2c subsystem
mandates -ENXIO is that case but the number of retries is host specific).
The critical parts are the probe function and the alarm callback so make
sure we handle the failure there.

Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
 drivers/rtc/rtc-rv8803.c | 28 ++++++++++++++++++++++------
 1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c
index 7155c0816aa6..82ab41074156 100644
--- a/drivers/rtc/rtc-rv8803.c
+++ b/drivers/rtc/rtc-rv8803.c
@@ -61,11 +61,14 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev=
_id)
 	struct i2c_client *client =3D dev_id;
 	struct rv8803_data *rv8803 =3D i2c_get_clientdata(client);
 	unsigned long events =3D 0;
-	int flags;
+	int flags, try =3D 0;
=20
 	spin_lock(&rv8803->flags_lock);
=20
-	flags =3D i2c_smbus_read_byte_data(client, RV8803_FLAG);
+	do {
+		flags =3D i2c_smbus_read_byte_data(client, RV8803_FLAG);
+		try++;
+	} while ((flags =3D=3D -ENXIO) && (try < 3));
 	if (flags <=3D 0) {
 		spin_unlock(&rv8803->flags_lock);
 		return IRQ_NONE;
@@ -428,7 +431,7 @@ static int rv8803_probe(struct i2c_client *client,
 {
 	struct i2c_adapter *adapter =3D to_i2c_adapter(client->dev.parent);
 	struct rv8803_data *rv8803;
-	int err, flags;
+	int err, flags, try =3D 0;
=20
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
 				     I2C_FUNC_SMBUS_I2C_BLOCK)) {
@@ -444,7 +447,16 @@ static int rv8803_probe(struct i2c_client *client,
 	rv8803->client =3D client;
 	i2c_set_clientdata(client, rv8803);
=20
-	flags =3D i2c_smbus_read_byte_data(client, RV8803_FLAG);
+	/*=20
+	 * There is a 60=C2=B5s window where the RTC may not reply on the i2c bus=
 in
+	 * that case, the transfer is not ACKed. In that case, ensure there are
+	 * multiple attempts.
+	 */
+	do {
+		flags =3D i2c_smbus_read_byte_data(client, RV8803_FLAG);
+		try++;
+	} while ((flags =3D=3D -ENXIO) && (try < 3));
+
 	if (flags < 0)
 		return flags;
=20
@@ -479,8 +491,12 @@ static int rv8803_probe(struct i2c_client *client,
 		return PTR_ERR(rv8803->rtc);
 	}
=20
-	err =3D i2c_smbus_write_byte_data(rv8803->client, RV8803_EXT,
-					RV8803_EXT_WADA);
+	try =3D 0;
+	do {
+		err =3D i2c_smbus_write_byte_data(rv8803->client, RV8803_EXT,
+						RV8803_EXT_WADA);
+		try++;
+	} while ((err =3D=3D -ENXIO) && (try < 3));
 	if (err)
 		return err;
=20
--=20
2.7.0

--=20
--=20
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
---=20
You received this message because you are subscribed to the Google Groups "=
rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to rtc-linux+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2016-03-21 14:58 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-21 14:58 [PATCH] rv8803: workaround i2c HW issue Alexandre Belloni
2016-03-21 14:58 ` [rtc-linux] " Alexandre Belloni

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.