OSDN Git Service

V4L/DVB (9775): tda8290: fix FM radio
authorMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 8 Dec 2008 13:36:57 +0000 (10:36 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 30 Dec 2008 11:38:19 +0000 (09:38 -0200)
tda8290 were using some random video standard for FM. This results on random
errors. Instead, program tda8290 in expert mode, using a configuration near the
one specified on NXP datasheet for tda8295 (available on their site).

Also, properly display that the device is on radio mode.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/common/tuners/tda8290.c

index c112bdd..0ee79fd 100644 (file)
@@ -32,6 +32,9 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
+static int deemphasis_50;
+MODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis");
+
 /* ---------------------------------------------------------------------- */
 
 struct tda8290_priv {
@@ -139,9 +142,34 @@ static void set_audio(struct dvb_frontend *fe,
                mode = "xx";
        }
 
-       tuner_dbg("setting tda829x to system %s\n", mode);
+       if (params->mode == V4L2_TUNER_RADIO) {
+               priv->tda8290_easy_mode = 0x01;         /* Start with MN values */
+               tuner_dbg("setting to radio FM\n");
+       } else {
+               tuner_dbg("setting tda829x to system %s\n", mode);
+       }
 }
 
+struct {
+       unsigned char seq[2];
+} fm_mode[] = {
+       { { 0x01, 0x81} },      /* Put device into expert mode */
+       { { 0x03, 0x48} },      /* Disable NOTCH and VIDEO filters */
+       { { 0x04, 0x04} },      /* Disable color carrier filter (SSIF) */
+       { { 0x05, 0x04} },      /* ADC headroom */
+       { { 0x06, 0x10} },      /* group delay flat */
+
+       { { 0x07, 0x00} },      /* use the same radio DTO values as a tda8295 */
+       { { 0x08, 0x00} },
+       { { 0x09, 0x80} },
+       { { 0x0a, 0xda} },
+       { { 0x0b, 0x4b} },
+       { { 0x0c, 0x68} },
+
+       { { 0x0d, 0x00} },      /* PLL off, no video carrier detect */
+       { { 0x14, 0x00} },      /* disable auto mute if no video */
+};
+
 static void tda8290_set_params(struct dvb_frontend *fe,
                               struct analog_parameters *params)
 {
@@ -178,15 +206,30 @@ static void tda8290_set_params(struct dvb_frontend *fe,
        tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
        msleep(1);
 
-       expert_mode[1] = priv->tda8290_easy_mode + 0x80;
-       tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
-       tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
-       tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
-       if (priv->tda8290_easy_mode & 0x60)
-               tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
-       else
-               tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
-       tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
+       if (params->mode == V4L2_TUNER_RADIO) {
+               int i;
+               unsigned char deemphasis[]  = { 0x13, 1 };
+
+               /* FIXME: allow using a different deemphasis */
+
+               if (deemphasis_50)
+                       deemphasis[1] = 2;
+
+               for (i = 0; i < ARRAY_SIZE(fm_mode); i++)
+                       tuner_i2c_xfer_send(&priv->i2c_props, fm_mode[i].seq, 2);
+
+               tuner_i2c_xfer_send(&priv->i2c_props, deemphasis, 2);
+       } else {
+               expert_mode[1] = priv->tda8290_easy_mode + 0x80;
+               tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
+               tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
+               tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
+               if (priv->tda8290_easy_mode & 0x60)
+                       tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
+               else
+                       tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
+               tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
+       }
 
        tda8290_i2c_bridge(fe, 1);