V4L/DVB (6593): Fix scode table loading
authorMauro Carvalho Chehab <mchehab@infradead.org>
Thu, 15 Nov 2007 11:43:53 +0000 (08:43 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Fri, 25 Jan 2008 21:02:10 +0000 (19:02 -0200)
Xceive 2028/3028 has a concept of scode/dcode.
Scode is a table of 16 values (each with 12 bytes i2c sequence).
Dcode is the entry of Scode table that should be used, given a certain
frequency.

The idea is that, depending on what frequency is selected, and according with a
country-based (or standard-based?) table, the Xceive should be "hacked" to
fine-tune that specific frequency.

By default, Scode=0 is used, for undefined frequencies. Also, Scode=0 seems to
be the most used value.

This patch adds the capability of selecting a scode. However, extra work will
be needed to allow auto-selecting the proper scode, for a given set of
frequencies.

I'm not sure what would be the proper way for implementing the dcode selection.

Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/tuner-xc2028.c

index ac0c9c3cde983e67f509656200b63c62db9123c0..e046c21be0b9632673754dee66d7cf44497713d4 100644 (file)
@@ -116,6 +116,8 @@ void dump_firm_type(unsigned int type)
 {
         if (type & BASE)
                printk("BASE ");
+        if (type & INIT1)
+               printk("INIT1 ");
         if (type & F8MHZ)
                printk("F8MHZ ");
         if (type & MTS)
@@ -201,7 +203,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
 
        tuner_info("%s called\n", __FUNCTION__);
 
-       tuner_info("Loading firmware %s\n", priv->ctrl.fname);
+       tuner_info("Reading firmware %s\n", priv->ctrl.fname);
        rc = request_firmware(&fw, priv->ctrl.fname, priv->dev);
        if (rc < 0) {
                if (rc == -ENOENT)
@@ -325,12 +327,11 @@ done:
        return rc;
 }
 
-static int load_firmware(struct dvb_frontend *fe, unsigned int type,
-                        v4l2_std_id * id)
+static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
+                        v4l2_std_id *id)
 {
        struct xc2028_data *priv = fe->tuner_priv;
-       int                i, rc;
-       unsigned char      *p, *endp, buf[priv->max_len];
+       int                i;
 
        tuner_info("%s called\n", __FUNCTION__);
 
@@ -339,7 +340,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
                return -EINVAL;
        }
 
-       if ((type == 0) && (*id == 0))
+       if (((type & ~SCODE) == 0) && (*id == 0))
                *id = V4L2_STD_PAL;
 
        /* Seek for exact match */
@@ -356,21 +357,40 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
 
        /*FIXME: Would make sense to seek for type "hint" match ? */
 
-       tuner_info("Can't find firmware for type=%x, id=%lx\n", type,
-                  (long int)*id);
-       return -EINVAL;
+       i = -EINVAL;
+       goto ret;
 
 found:
        *id = priv->firm[i].id;
-       tuner_info("Found firmware for type=%x, id=%lx\n", type, (long int)*id);
 
-       p = priv->firm[i].ptr;
+ret:
+       tuner_info("%s firmware for type=", (i < 0)? "Can't find": "Found");
+       dump_firm_type(type);
+       printk("(%x), id %08lx.\n", type, (unsigned long)*id);
+
+       return i;
+}
+
+static int load_firmware(struct dvb_frontend *fe, unsigned int type,
+                        v4l2_std_id *id)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+       int                pos, rc;
+       unsigned char      *p, *endp, buf[priv->max_len];
+
+       tuner_info("%s called\n", __FUNCTION__);
+
+       pos = seek_firmware(fe, type, id);
+       if (pos < 0)
+               return pos;
+
+       p = priv->firm[pos].ptr;
 
        if (!p) {
                printk(KERN_ERR PREFIX "Firmware pointer were freed!");
                return -EINVAL;
        }
-       endp = p + priv->firm[i].size;
+       endp = p + priv->firm[pos].size;
 
        while (p < endp) {
                __u16 size;
@@ -435,6 +455,42 @@ found:
        return 0;
 }
 
+static int load_scode(struct dvb_frontend *fe, unsigned int type,
+                        v4l2_std_id *id, int scode)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+       int                pos, rc;
+       unsigned char      *p;
+
+       tuner_info("%s called\n", __FUNCTION__);
+
+       pos = seek_firmware(fe, type, id);
+       if (pos < 0)
+               return pos;
+
+       p = priv->firm[pos].ptr;
+
+       if (!p) {
+               printk(KERN_ERR PREFIX "Firmware pointer were freed!");
+               return -EINVAL;
+       }
+
+       if ((priv->firm[pos].size != 12 * 16) || (scode >= 16))
+               return -EINVAL;
+
+       if (priv->version < 0x0202) {
+               send_seq(priv, {0x20, 0x00, 0x00, 0x00});
+       } else {
+               send_seq(priv, {0xa0, 0x00, 0x00, 0x00});
+       }
+
+       i2c_send(rc, priv, p + 12 * scode, 12);
+
+       send_seq(priv, {0x00, 0x8c});
+
+       return 0;
+}
+
 static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
                          v4l2_std_id std, fe_bandwidth_t bandwidth)
 {
@@ -527,8 +583,8 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
        }
 
        /* Load INIT1, if needed */
-       tuner_info("Trying to load init1 firmware\n");
-       type0 = BASE | INIT1 | priv->ctrl.type;
+       tuner_info("Load init1 firmware, if exists\n");
+       type0 = BASE | INIT1;
        if (priv->ctrl.type == XC2028_FIRM_MTS)
                type0 |= MTS;
 
@@ -541,9 +597,9 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
        if (priv->ctrl.type == XC2028_FIRM_MTS)
                type |= MTS;
 
-       tuner_info("firmware standard to load: %08lx\n", (unsigned long)std);
+       tuner_info("Firmware standard to load: %08lx\n", (unsigned long)std);
        if (priv->firm_type & std) {
-               tuner_info("no need to load a std-specific firmware.\n");
+               tuner_info("Std-specific firmware already loaded.\n");
                return 0;
        }
 
@@ -551,11 +607,11 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
        if (rc < 0)
                return rc;
 
-       /* Load SCODE firmware, if needed */
-       tuner_info("Trying to load scode firmware\n");
-       type0 = SCODE | priv->ctrl.type;
-       if (priv->ctrl.type == XC2028_FIRM_MTS)
-               type0 |= MTS;
+       /* Load SCODE firmware, if exists */
+       tuner_info("Trying to load scode 0\n");
+       type |= SCODE;
+
+       rc = load_scode(fe, type, &std, 0);
 
        version = xc2028_get_reg(priv, 0x0004);
        hwmodel = xc2028_get_reg(priv, 0x0008);