media: dvb/earth-pt1: fix wrong initialization for demod blocks
authorAkihiro Tsukada <tskd08@gmail.com>
Thu, 10 Jan 2019 09:56:23 +0000 (04:56 -0500)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Mon, 4 Mar 2019 11:17:02 +0000 (06:17 -0500)
earth-pt1 driver was decomposed/restructured by the commit b732539efdba
("media: dvb: earth-pt1: decompose pt1 driver into sub drivers"),
but it introduced a problem regarding concurrent streaming:
Opening a new terrestial stream stops the reception of an existing,
already-opened satellite stream.

The demod IC in earth-pt1 boards contains 2 pairs of terr. and sat. blocks,
supporting 4 concurrent demodulations, and the above problem was because
the config of a terr. block contained whole reset/init of the pair blocks,
thus each open() of a terrestrial frontend wrongly cleared the config of
its peer satellite block of the demod.
This whole/pair reset should be executed earlier and not on each open().

Fixes: b732539efdba ("media: dvb: earth-pt1: decompose pt1 driver into sub drivers")

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/pci/pt1/pt1.c

index f4b8030..393f4c5 100644 (file)
@@ -200,16 +200,10 @@ static const u8 va1j5jf8007t_25mhz_configs[][2] = {
 static int config_demod(struct i2c_client *cl, enum pt1_fe_clk clk)
 {
        int ret;
-       u8 buf[2] = {0x01, 0x80};
        bool is_sat;
        const u8 (*cfg_data)[2];
        int i, len;
 
-       ret = i2c_master_send(cl, buf, 2);
-       if (ret < 0)
-               return ret;
-       usleep_range(30000, 50000);
-
        is_sat = !strncmp(cl->name, TC90522_I2C_DEV_SAT,
                          strlen(TC90522_I2C_DEV_SAT));
        if (is_sat) {
@@ -260,6 +254,46 @@ static int config_demod(struct i2c_client *cl, enum pt1_fe_clk clk)
        return 0;
 }
 
+/*
+ * Init registers for (each pair of) terrestrial/satellite block in demod.
+ * Note that resetting terr. block also resets its peer sat. block as well.
+ * This function must be called before configuring any demod block
+ * (before pt1_wakeup(), fe->ops.init()).
+ */
+static int pt1_demod_block_init(struct pt1 *pt1)
+{
+       struct i2c_client *cl;
+       u8 buf[2] = {0x01, 0x80};
+       int ret;
+       int i;
+
+       /* reset all terr. & sat. pairs first */
+       for (i = 0; i < PT1_NR_ADAPS; i++) {
+               cl = pt1->adaps[i]->demod_i2c_client;
+               if (strncmp(cl->name, TC90522_I2C_DEV_TER,
+                           strlen(TC90522_I2C_DEV_TER)))
+                       continue;
+
+               ret = i2c_master_send(cl, buf, 2);
+               if (ret < 0)
+                       return ret;
+               usleep_range(30000, 50000);
+       }
+
+       for (i = 0; i < PT1_NR_ADAPS; i++) {
+               cl = pt1->adaps[i]->demod_i2c_client;
+               if (strncmp(cl->name, TC90522_I2C_DEV_SAT,
+                           strlen(TC90522_I2C_DEV_SAT)))
+                       continue;
+
+               ret = i2c_master_send(cl, buf, 2);
+               if (ret < 0)
+                       return ret;
+               usleep_range(30000, 50000);
+       }
+       return 0;
+}
+
 static void pt1_write_reg(struct pt1 *pt1, int reg, u32 data)
 {
        writel(data, pt1->regs + reg * 4);
@@ -987,6 +1021,10 @@ static int pt1_init_frontends(struct pt1 *pt1)
                        goto tuner_release;
        }
 
+       ret = pt1_demod_block_init(pt1);
+       if (ret < 0)
+               goto fe_unregister;
+
        return 0;
 
 tuner_release:
@@ -1245,6 +1283,10 @@ static int pt1_resume(struct device *dev)
        pt1_update_power(pt1);
        usleep_range(1000, 2000);
 
+       ret = pt1_demod_block_init(pt1);
+       if (ret < 0)
+               goto resume_err;
+
        for (i = 0; i < PT1_NR_ADAPS; i++)
                dvb_frontend_reinitialise(pt1->adaps[i]->fe);