[media] au0828: prevent i2c gate from being kept open while in analog mode
authorDevin Heitmueller <dheitmueller@kernellabs.com>
Tue, 7 Aug 2012 01:47:02 +0000 (22:47 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 9 Aug 2012 23:37:56 +0000 (20:37 -0300)
The original implementation of the analog support would use an
i2c_gate_ctrl function when using the digital side of the au8522, but on
the analog side we would always just force the gate open and leave it
open all the time.

This can have adverse effects on the xc5000 given the tuner is receiving
all the spurious i2c traffic (a problem which can be exaggerated due to
bugs in the au0828 i2c hardware implementation).

Rework the existing hack to only open/close the gate when actually
talking to the tuner.

This logic might need to be reworked a bit if anybody ever tries to add
support for a board that has the au0828/au8522 but doesn't have digital
support implemented (because the i2c_gate_ctrl callback is being set in
the DVB attach).  However given how few different models are in
circulation, this can be deferred until such a situation arises (if
ever).

Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/dvb/frontends/au8522_common.c
drivers/media/dvb/frontends/au8522_decoder.c
drivers/media/dvb/frontends/au8522_dig.c
drivers/media/dvb/frontends/au8522_priv.h
drivers/media/video/au0828/au0828-video.c

index 8b4da40192d54c1ab38c507cfb592c6c66215328..3559ff230045450ad885bf8e118aaa27a80c50df 100644 (file)
@@ -99,6 +99,19 @@ int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 }
 EXPORT_SYMBOL(au8522_i2c_gate_ctrl);
 
+int au8522_analog_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct au8522_state *state = fe->demodulator_priv;
+
+       dprintk("%s(%d)\n", __func__, enable);
+
+       if (enable)
+               return au8522_writereg(state, 0x106, 1);
+       else
+               return au8522_writereg(state, 0x106, 0);
+}
+EXPORT_SYMBOL(au8522_analog_i2c_gate_ctrl);
+
 /* Reset the demod hardware and reset all of the configuration registers
    to a default state. */
 int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
index f2e786b606fda5d0d03adc9ad494d34d2c3de1db..5243ba6295cc1aabd93796aa23e90bdb300c59ad 100644 (file)
@@ -659,11 +659,6 @@ static int au8522_s_video_routing(struct v4l2_subdev *sd,
 
        au8522_reset(sd, 0);
 
-       /* Jam open the i2c gate to the tuner.  We do this here to handle the
-          case where the user went into digital mode (causing the gate to be
-          closed), and then came back to analog mode */
-       au8522_writereg(state, 0x106, 1);
-
        if (input == AU8522_COMPOSITE_CH1) {
                au8522_setup_cvbs_mode(state);
        } else if (input == AU8522_SVIDEO_CH13) {
index ee8cf81cf7500bb0308f1119f152c9a26e4148f3..a68974f6d7081f2bc877b43e3c9481d49de45dc9 100644 (file)
@@ -777,6 +777,8 @@ struct dvb_frontend *au8522_attach(const struct au8522_config *config,
               sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
 
+       state->frontend.ops.analog_ops.i2c_gate_ctrl = au8522_analog_i2c_gate_ctrl;
+
        if (au8522_init(&state->frontend) != 0) {
                printk(KERN_ERR "%s: Failed to initialize correctly\n",
                        __func__);
index 9f44a7be3148fc6dff89eb698c4f7b5ed7b3836d..0529699a27bd64188f8c625d245db12278eb95e3 100644 (file)
@@ -82,6 +82,7 @@ int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
                     u8 client_address);
 void au8522_release_state(struct au8522_state *state);
 int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
+int au8522_analog_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
 int au8522_led_ctrl(struct au8522_state *state, int led);
 
 /* REGISTERS */
index f3e6e3f4dfd40da4c0030b41d7b376a71f2cde4d..df9232281d64a4eed52ea490befa926864d7e213 100644 (file)
@@ -1541,6 +1541,9 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 
        dev->ctrl_freq = freq->frequency;
 
+       if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+               dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
+
        if (dev->std_set_in_tuner_core == 0) {
          /* If we've never sent the standard in tuner core, do so now.  We
             don't do this at device probe because we don't want to incur
@@ -1552,6 +1555,9 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 
        v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq);
 
+       if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+               dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+
        au0828_analog_stream_reset(dev);
 
        return 0;