]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
[media] mb86a20s: Be sure that device is initialized before starting DVB
authorMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 14 Jan 2011 14:10:05 +0000 (11:10 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Wed, 19 Jan 2011 13:45:25 +0000 (11:45 -0200)
Due to a hard to track bug between tda829x/tda18271/saa7134, tda829x
wants to go to analog mode during DVB initialization, causing some
I2C errors.

The analog failure doesn't cause any harm, as the device were already
properly initialized in analog mode. However, the failure at the digital
mode causes the frontend mb86a20s to not initialize. Fortunately, at
least on my tests, it was possible to detect that the device is a
mb86a20s before the failure.

What happens is that tda8290 is a very bad boy: during DVB setup, it
keeps insisting to call tda18271 analog_set_params, that calls
tune_agc code. The tune_agc code calls saa7134 driver, changing the
value of GPIO 27, switching from digital to analog mode and disabling
the access to mb86a20s, as, on Kworld SBTVD, the same GPIO used
to switch the hardware AGC mode seems to be used to enable the I2C
switch that allows access to the frontend (mb86a20s).

So, a call to analog_set_params ultimately disables the access to
the frontend, and causes a failure at the init frontend logic.

This patch is a workaround for this issue: it simply checks if the
frontend init had any failure. If so, it will init the frontend when
some DTV application will try to set DVB mode.

Even being a hack for Kworld SBTVD to work, and assumning that we could
teach tda8290 to be a good boy, this is actually an improvement at the
frontend driver, as it will be more reliable to initialization failures.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/dvb/frontends/mb86a20s.c

index e06507d2c3b25219175db1c0d00625235a92474a..cc4acd2f920d6e1efd0842dbe49545f8b02ca360 100644 (file)
@@ -43,6 +43,8 @@ struct mb86a20s_state {
        const struct mb86a20s_config *config;
 
        struct dvb_frontend frontend;
+
+       bool need_init;
 };
 
 struct regdata {
@@ -382,23 +384,31 @@ static int mb86a20s_initfe(struct dvb_frontend *fe)
        /* Initialize the frontend */
        rc = mb86a20s_writeregdata(state, mb86a20s_init);
        if (rc < 0)
-               return rc;
+               goto err;
 
        if (!state->config->is_serial) {
                regD5 &= ~1;
 
                rc = mb86a20s_writereg(state, 0x50, 0xd5);
                if (rc < 0)
-                       return rc;
+                       goto err;
                rc = mb86a20s_writereg(state, 0x51, regD5);
                if (rc < 0)
-                       return rc;
+                       goto err;
        }
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
 
-       return 0;
+err:
+       if (rc < 0) {
+               state->need_init = true;
+               printk(KERN_INFO "mb86a20s: Init failed. Will try again later\n");
+       } else {
+               state->need_init = false;
+               dprintk("Initialization succeded.\n");
+       }
+       return rc;
 }
 
 static int mb86a20s_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
@@ -485,8 +495,22 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe,
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
+       dprintk("Calling tuner set parameters\n");
        fe->ops.tuner_ops.set_params(fe, p);
 
+       /*
+        * Make it more reliable: if, for some reason, the initial
+        * device initialization doesn't happen, initialize it when
+        * a SBTVD parameters are adjusted.
+        *
+        * Unfortunately, due to a hard to track bug at tda829x/tda18271,
+        * the agc callback logic is not called during DVB attach time,
+        * causing mb86a20s to not be initialized with Kworld SBTVD.
+        * So, this hack is needed, in order to make Kworld SBTVD to work.
+        */
+       if (state->need_init)
+               mb86a20s_initfe(fe);
+
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0);
        rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception);