From 5962cf8fafdfe98138fd69beb4d0b5d2a7af5732 Mon Sep 17 00:00:00 2001
From: Benjamin Larsson <benjamin@southpole.se>
Date: Thu, 20 Nov 2014 00:50:02 +0100
Subject: [PATCH] rtl28xxu: implement i2c transfer retry logic
Cc: Linux Media Mailing List <linux-media@vger.kernel.org>
This is needed for Astrometa hardware. Retry counts up to 6 has been
observered before the i2c transfer succeded.
Signed-off-by: Benjamin Larsson <benjamin@southpole.se>
---
drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
@@ -185,6 +185,8 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
struct dvb_usb_device *d = i2c_get_adapdata(adap);
struct rtl28xxu_priv *priv = d->priv;
struct rtl28xxu_req req;
+ u8 rb_buf[2];
+ int i, retry_cnt;
/*
* It is not known which are real I2C bus xfer limits, but testing
@@ -273,6 +275,33 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
req.size = msg[0].len-1;
req.data = &msg[0].buf[1];
ret = rtl28xxu_ctrl_msg(d, &req);
+
+ /* Astrometa hardware needs a retry for some failed transfers.
+ * Just send one byte at the time.
+ * Retry max 10 times for each transfer.
+ */
+ if (ret) {
+ req.size = 1;
+ req.data = rb_buf;
+
+ dev_dbg(&d->udev->dev, "%s: transfer of %d bytes failed\n", __func__, msg[0].len-1);
+ rb_buf[0] = msg[0].buf[0];
+
+ for (i=0 ; i<msg[0].len-1 ; i++) {
+ retry_cnt = 0;
+ req.value = ((msg[0].buf[0]+i) << 8) | (msg[0].addr << 1);
+ rb_buf[0] = msg[0].buf[i+1];
+
+ do {
+ dev_dbg(&d->udev->dev, "%s: byte: %d retry: %d\n", __func__, i, retry_cnt);
+ ret = rtl28xxu_ctrl_msg(d, &req);
+ retry_cnt++;
+ if (retry_cnt > 10)
+ goto err_mutex_unlock;
+
+ } while (ret);
+ }
+ }
} else {
/* method 3 - new I2C */
req.value = (msg[0].addr << 1);
--
1.9.1