[media] ttusb2: add support for the dvb-t part of CT-3650 v3
authorJose Alberto Reguero <jareguero@telefonica.net>
Mon, 8 Aug 2011 10:35:35 +0000 (07:35 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Sat, 27 Aug 2011 14:44:49 +0000 (11:44 -0300)
Signed-off-by: Jose Alberto Reguero <jareguero@telefonica.net>
Reviewed-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/dvb/dvb-usb/ttusb2.c
drivers/media/dvb/frontends/tda10048.c
drivers/media/dvb/frontends/tda10048.h

index c0f5ef56f5e9abd6e008b2d974f88e59ef1a9dfa..bda37ce05627271cec69567a7299d1f1ed8e9ffa 100644 (file)
@@ -30,6 +30,7 @@
 #include "tda826x.h"
 #include "tda10086.h"
 #include "tda1002x.h"
+#include "tda10048.h"
 #include "tda827x.h"
 #include "lnbp21.h"
 
@@ -82,7 +83,7 @@ static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
        static u8 obuf[60], ibuf[60];
-       int i,read;
+       int i, write_read, read;
 
        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
                return -EAGAIN;
@@ -91,28 +92,35 @@ static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
                warn("more than 2 i2c messages at a time is not handled yet. TODO.");
 
        for (i = 0; i < num; i++) {
-               read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
+               write_read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
+               read = msg[i].flags & I2C_M_RD;
 
-               obuf[0] = (msg[i].addr << 1) | read;
-               obuf[1] = msg[i].len;
+               obuf[0] = (msg[i].addr << 1) | (write_read | read);
+               if (read)
+                       obuf[1] = 0;
+               else
+                       obuf[1] = msg[i].len;
 
                /* read request */
-               if (read)
+               if (write_read)
                        obuf[2] = msg[i+1].len;
+               else if (read)
+                       obuf[2] = msg[i].len;
                else
                        obuf[2] = 0;
 
-               memcpy(&obuf[3],msg[i].buf,msg[i].len);
+               memcpy(&obuf[3], msg[i].buf, msg[i].len);
 
                if (ttusb2_msg(d, CMD_I2C_XFER, obuf, msg[i].len+3, ibuf, obuf[2] + 3) < 0) {
                        err("i2c transfer failed.");
                        break;
                }
 
-               if (read) {
-                       memcpy(msg[i+1].buf,&ibuf[3],msg[i+1].len);
+               if (write_read) {
+                       memcpy(msg[i+1].buf, &ibuf[3], msg[i+1].len);
                        i++;
-               }
+               } else if (read)
+                       memcpy(msg[i].buf, &ibuf[3], msg[i].len);
        }
 
        mutex_unlock(&d->i2c_mutex);
@@ -190,6 +198,25 @@ static struct tda10023_config tda10023_config = {
        .deltaf = 0xa511,
 };
 
+static struct tda10048_config tda10048_config = {
+       .demod_address    = 0x10 >> 1,
+       .output_mode      = TDA10048_PARALLEL_OUTPUT,
+       .inversion        = TDA10048_INVERSION_ON,
+       .dtv6_if_freq_khz = TDA10048_IF_4000,
+       .dtv7_if_freq_khz = TDA10048_IF_4500,
+       .dtv8_if_freq_khz = TDA10048_IF_5000,
+       .clk_freq_khz     = TDA10048_CLK_16000,
+       .no_firmware      = 1,
+       .set_pll          = true ,
+       .pll_m            = 5,
+       .pll_n            = 3,
+       .pll_p            = 0,
+};
+
+static struct tda827x_config tda827x_config = {
+       .config = 0,
+};
+
 static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
 {
        if (usb_set_interface(adap->dev->udev,0,3) < 0)
@@ -203,20 +230,56 @@ static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
+static int ttusb2_ct3650_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+       return adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], enable);
+}
+
 static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap)
 {
        if (usb_set_interface(adap->dev->udev, 0, 3) < 0)
                err("set interface to alts=3 failed");
-       if ((adap->fe[0] = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48)) == NULL) {
-               deb_info("TDA10023 attach failed\n");
-               return -ENODEV;
+
+       if (adap->fe[0] == NULL) {
+               /* FE 0 DVB-C */
+               adap->fe[0] = dvb_attach(tda10023_attach,
+                       &tda10023_config, &adap->dev->i2c_adap, 0x48);
+
+               if (adap->fe[0] == NULL) {
+                       deb_info("TDA10023 attach failed\n");
+                       return -ENODEV;
+               }
+       } else {
+               adap->fe[1] = dvb_attach(tda10048_attach,
+                       &tda10048_config, &adap->dev->i2c_adap);
+
+               if (adap->fe[1] == NULL) {
+                       deb_info("TDA10048 attach failed\n");
+                       return -ENODEV;
+               }
+
+               /* tuner is behind TDA10023 I2C-gate */
+               adap->fe[1]->ops.i2c_gate_ctrl = ttusb2_ct3650_i2c_gate_ctrl;
+
        }
+
        return 0;
 }
 
 static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap)
 {
-       if (dvb_attach(tda827x_attach, adap->fe[0], 0x61, &adap->dev->i2c_adap, NULL) == NULL) {
+       struct dvb_frontend *fe;
+
+       /* MFE: select correct FE to attach tuner since that's called twice */
+       if (adap->fe[1] == NULL)
+               fe = adap->fe[0];
+       else
+               fe = adap->fe[1];
+
+       /* attach tuner */
+       if (dvb_attach(tda827x_attach, fe, 0x61, &adap->dev->i2c_adap, &tda827x_config) == NULL) {
                printk(KERN_ERR "%s: No tda827x found!\n", __func__);
                return -ENODEV;
        }
@@ -385,6 +448,7 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
                {
                        .streaming_ctrl   = NULL,
 
+                       .num_frontends    = 2,
                        .frontend_attach  = ttusb2_frontend_tda10023_attach,
                        .tuner_attach = ttusb2_tuner_tda827x_attach,
 
index 93f6a75c238eec25fbe2c8cfb905f08d113d5e2a..7f105946a4342171056e8b774c7032ec4970dedc 100644 (file)
@@ -206,15 +206,16 @@ static struct init_tab {
 static struct pll_tab {
        u32     clk_freq_khz;
        u32     if_freq_khz;
-       u8      m, n, p;
 } pll_tab[] = {
-       { TDA10048_CLK_4000,  TDA10048_IF_36130, 10, 0, 0 },
-       { TDA10048_CLK_16000, TDA10048_IF_3300,  10, 3, 0 },
-       { TDA10048_CLK_16000, TDA10048_IF_3500,  10, 3, 0 },
-       { TDA10048_CLK_16000, TDA10048_IF_3800,  10, 3, 0 },
-       { TDA10048_CLK_16000, TDA10048_IF_4000,  10, 3, 0 },
-       { TDA10048_CLK_16000, TDA10048_IF_4300,  10, 3, 0 },
-       { TDA10048_CLK_16000, TDA10048_IF_36130, 10, 3, 0 },
+       { TDA10048_CLK_4000,  TDA10048_IF_36130 },
+       { TDA10048_CLK_16000, TDA10048_IF_3300 },
+       { TDA10048_CLK_16000, TDA10048_IF_3500 },
+       { TDA10048_CLK_16000, TDA10048_IF_3800 },
+       { TDA10048_CLK_16000, TDA10048_IF_4000 },
+       { TDA10048_CLK_16000, TDA10048_IF_4300 },
+       { TDA10048_CLK_16000, TDA10048_IF_4500 },
+       { TDA10048_CLK_16000, TDA10048_IF_5000 },
+       { TDA10048_CLK_16000, TDA10048_IF_36130 },
 };
 
 static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
@@ -460,9 +461,6 @@ static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw)
 
                        state->freq_if_hz = pll_tab[i].if_freq_khz * 1000;
                        state->xtal_hz = pll_tab[i].clk_freq_khz * 1000;
-                       state->pll_mfactor = pll_tab[i].m;
-                       state->pll_nfactor = pll_tab[i].n;
-                       state->pll_pfactor = pll_tab[i].p;
                        break;
                }
        }
@@ -781,6 +779,10 @@ static int tda10048_init(struct dvb_frontend *fe)
 
        dprintk(1, "%s()\n", __func__);
 
+       /* PLL */
+       init_tab[4].data = (u8)(state->pll_mfactor);
+       init_tab[5].data = (u8)(state->pll_nfactor) | 0x40;
+
        /* Apply register defaults */
        for (i = 0; i < ARRAY_SIZE(init_tab); i++)
                tda10048_writereg(state, init_tab[i].reg, init_tab[i].data);
@@ -1123,7 +1125,7 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
        /* setup the state and clone the config */
        memcpy(&state->config, config, sizeof(*config));
        state->i2c = i2c;
-       state->fwloaded = 0;
+       state->fwloaded = config->no_firmware;
        state->bandwidth = BANDWIDTH_8_MHZ;
 
        /* check if the demod is present */
@@ -1135,6 +1137,17 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
                sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
 
+       /* set pll */
+       if (config->set_pll) {
+               state->pll_mfactor = config->pll_m;
+               state->pll_nfactor = config->pll_n;
+               state->pll_pfactor = config->pll_p;
+       } else {
+               state->pll_mfactor = 10;
+               state->pll_nfactor = 3;
+               state->pll_pfactor = 0;
+       }
+
        /* Establish any defaults the the user didn't pass */
        tda10048_establish_defaults(&state->frontend);
 
index 8828ceaf74bb491dad21c12759d0a1b316ec8a0c..fb2ef5ac948768c7b1fd35bfa8741731d66427b9 100644 (file)
@@ -51,6 +51,7 @@ struct tda10048_config {
 #define TDA10048_IF_4300  4300
 #define TDA10048_IF_4500  4500
 #define TDA10048_IF_4750  4750
+#define TDA10048_IF_5000  5000
 #define TDA10048_IF_36130 36130
        u16 dtv6_if_freq_khz;
        u16 dtv7_if_freq_khz;
@@ -62,6 +63,13 @@ struct tda10048_config {
 
        /* Disable I2C gate access */
        u8 disable_gate_access;
+
+       bool no_firmware;
+
+       bool set_pll;
+       u8 pll_m;
+       u8 pll_p;
+       u8 pll_n;
 };
 
 #if defined(CONFIG_DVB_TDA10048) || \