[media] af9015: fix i2c failures for dual-tuner devices
authorGordon Hecker <ghecker@gmx.de>
Wed, 14 Mar 2012 13:27:30 +0000 (10:27 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 19 Mar 2012 22:40:58 +0000 (19:40 -0300)
The i2c failures were caused by enabling both i2c gates
at the same time while putting the tuners asleep.

This patch removes the init() and sleep() callbacks from the tuner,
to prevent frontend.c from calling
  i2c_gate_ctrl
  tuner init / sleep
  i2c_gate_ctrl
without holding the lock.
tuner init() and sleep() are instead called in frontend init() and
sleep().

Signed-off-by: Gordon Hecker <ghecker@gmx.de>
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/af9015.h

index 282a43d648df1817ec0d86ef4adf995706af52cf..9307b4ca4b779a10b79d885122d83ae43996087c 100644 (file)
@@ -1141,7 +1141,18 @@ static int af9015_af9013_init(struct dvb_frontend *fe)
                return -EAGAIN;
 
        ret = priv->init[adap->id](fe);
+       if (ret)
+               goto err_unlock;
+
+       if (priv->tuner_ops_init[adap->id]) {
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 1);
+               ret = priv->tuner_ops_init[adap->id](fe);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+       }
 
+err_unlock:
        mutex_unlock(&adap->dev->usb_mutex);
 
        return ret;
@@ -1157,8 +1168,19 @@ static int af9015_af9013_sleep(struct dvb_frontend *fe)
        if (mutex_lock_interruptible(&adap->dev->usb_mutex))
                return -EAGAIN;
 
+       if (priv->tuner_ops_sleep[adap->id]) {
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 1);
+               ret = priv->tuner_ops_sleep[adap->id](fe);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+               if (ret)
+                       goto err_unlock;
+       }
+
        ret = priv->sleep[adap->id](fe);
 
+err_unlock:
        mutex_unlock(&adap->dev->usb_mutex);
 
        return ret;
@@ -1283,6 +1305,7 @@ static struct mxl5007t_config af9015_mxl5007t_config = {
 static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
 {
        int ret;
+       struct af9015_state *state = adap->dev->priv;
        deb_info("%s:\n", __func__);
 
        switch (af9015_af9013_config[adap->id].tuner) {
@@ -1340,6 +1363,14 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
                err("Unknown tuner id:%d",
                        af9015_af9013_config[adap->id].tuner);
        }
+
+       state->tuner_ops_sleep[adap->id] =
+                               adap->fe_adap[0].fe->ops.tuner_ops.sleep;
+       adap->fe_adap[0].fe->ops.tuner_ops.sleep = 0;
+
+       state->tuner_ops_init[adap->id] =
+                               adap->fe_adap[0].fe->ops.tuner_ops.init;
+       adap->fe_adap[0].fe->ops.tuner_ops.init = 0;
        return ret;
 }
 
index f619063fa72f6a03f663da283ce91d1e7d3b6623..ee2ec5b8d5707b857240985361e557f7a49475ba 100644 (file)
@@ -108,6 +108,8 @@ struct af9015_state {
        int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status);
        int (*init[2]) (struct dvb_frontend *fe);
        int (*sleep[2]) (struct dvb_frontend *fe);
+       int (*tuner_ops_init[2]) (struct dvb_frontend *fe);
+       int (*tuner_ops_sleep[2]) (struct dvb_frontend *fe);
 };
 
 struct af9015_config {