media: dvb-frontends/tc90522: extend i2c algo to support some devices
authorAkihiro Tsukada <tskd08@gmail.com>
Thu, 29 Aug 2019 08:38:21 +0000 (05:38 -0300)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Mon, 7 Oct 2019 10:50:41 +0000 (07:50 -0300)
This demod implements an i2c adapter for attached tuner
and relays i2c messages from users (dvb adapters / bridge chips).
Some of them, such as Friio dvb card using gl861,
require each pair of i2c messages for one read to be issued as
two separate transactions.
This patch adds a configuration option to enable this split.

Signed-off-by: Akihiro Tsukada <tskd08@gmail.com>
Signed-off-by: Sean Young <sean@mess.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
drivers/media/dvb-frontends/tc90522.c
drivers/media/dvb-frontends/tc90522.h

index 849d63dbc279b86602bfc35700b4b6dbfa1aed52..e83836b29715ce29f48796c15439a137d3b15fb3 100644 (file)
@@ -685,10 +685,33 @@ tc90522_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                p += new_msgs[j].len;
        }
 
-       if (i < num)
+       if (i < num) {
                ret = -ENOMEM;
-       else
+       } else if (!state->cfg.split_tuner_read_i2c || rd_num == 0) {
                ret = i2c_transfer(state->i2c_client->adapter, new_msgs, j);
+       } else {
+               /*
+                * Split transactions at each I2C_M_RD message.
+                * Some of the parent device require this,
+                * such as Friio (see. dvb-usb-gl861).
+                */
+               int from, to;
+
+               ret = 0;
+               from = 0;
+               do {
+                       int r;
+
+                       to = from + 1;
+                       while (to < j && !(new_msgs[to].flags & I2C_M_RD))
+                               to++;
+                       r = i2c_transfer(state->i2c_client->adapter,
+                                        &new_msgs[from], to - from);
+                       ret = (r <= 0) ? r : ret + r;
+                       from = to;
+               } while (from < j && ret > 0);
+       }
+
        if (ret >= 0 && ret < j)
                ret = -EIO;
        kfree(new_msgs);
index ac0e2ab51924e31e4a81ca4138ee50c61c7194ee..07e3813bf59022d69dec24956d9fbddb21b8dc56 100644 (file)
@@ -28,6 +28,9 @@ struct tc90522_config {
 
        /* [OUT] tuner I2C adapter returned by driver */
        struct i2c_adapter *tuner_i2c;
+
+       /* [IN] use two separate I2C transactions for one tuner read */
+       bool split_tuner_read_i2c;
 };
 
 #endif /* TC90522_H */