]> err.no Git - linux-2.6/blobdiff - drivers/media/video/tuner-simple.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux...
[linux-2.6] / drivers / media / video / tuner-simple.c
index b6587300bb8f479a84302ffbb7e3b029f816e1e1..be8d903171b7dce5f3ace750c63177a86d107284 100644 (file)
@@ -17,10 +17,22 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
+#define TUNER_SIMPLE_MAX 64
+static unsigned int simple_devcount;
+
 static int offset;
 module_param(offset, int, 0664);
 MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner");
 
+static unsigned int atv_input[TUNER_SIMPLE_MAX] = \
+                       { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
+static unsigned int dtv_input[TUNER_SIMPLE_MAX] = \
+                       { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
+module_param_array(atv_input, int, NULL, 0644);
+module_param_array(dtv_input, int, NULL, 0644);
+MODULE_PARM_DESC(atv_input, "specify atv rf input, 0 for autoselect");
+MODULE_PARM_DESC(dtv_input, "specify dtv rf input, 0 for autoselect");
+
 /* ---------------------------------------------------------------------- */
 
 /* tv standard selection for Temic 4046 FM5
@@ -92,6 +104,7 @@ static DEFINE_MUTEX(tuner_simple_list_mutex);
 static LIST_HEAD(hybrid_tuner_instance_list);
 
 struct tuner_simple_priv {
+       unsigned int nr;
        u16 last_div;
 
        struct tuner_i2c_props i2c_props;
@@ -268,6 +281,37 @@ static int simple_config_lookup(struct dvb_frontend *fe,
 
 /* ---------------------------------------------------------------------- */
 
+static void simple_set_rf_input(struct dvb_frontend *fe,
+                               u8 *config, u8 *cb, unsigned int rf)
+{
+       struct tuner_simple_priv *priv = fe->tuner_priv;
+
+       switch (priv->type) {
+       case TUNER_PHILIPS_TUV1236D:
+               switch (rf) {
+               case 1:
+                       *cb |= 0x08;
+                       break;
+               default:
+                       *cb &= ~0x08;
+                       break;
+               }
+               break;
+       case TUNER_PHILIPS_FCV1236D:
+               switch (rf) {
+               case 1:
+                       *cb |= 0x01;
+                       break;
+               default:
+                       *cb &= ~0x01;
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+}
+
 static int simple_std_setup(struct dvb_frontend *fe,
                            struct analog_parameters *params,
                            u8 *config, u8 *cb)
@@ -325,7 +369,7 @@ static int simple_std_setup(struct dvb_frontend *fe,
                }
                break;
 
-       case TUNER_PHILIPS_ATSC:
+       case TUNER_PHILIPS_FCV1236D:
                /* 0x00 -> ATSC antenna input 1 */
                /* 0x01 -> ATSC antenna input 2 */
                /* 0x02 -> NTSC antenna input 1 */
@@ -333,7 +377,6 @@ static int simple_std_setup(struct dvb_frontend *fe,
                *cb &= ~0x03;
                if (!(params->std & V4L2_STD_ATSC))
                        *cb |= 2;
-               /* FIXME: input */
                break;
 
        case TUNER_MICROTUNE_4042FI5:
@@ -365,10 +408,11 @@ static int simple_std_setup(struct dvb_frontend *fe,
                        tuner_warn("i2c i/o error: rc == %d "
                                   "(should be 2)\n", rc);
                priv->i2c_props.addr = tuneraddr;
-               /* FIXME: input */
                break;
        }
        }
+       if (atv_input[priv->nr])
+               simple_set_rf_input(fe, config, cb, atv_input[priv->nr]);
 
        return 0;
 }
@@ -725,14 +769,45 @@ static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
                    params->frequency >= 158870000)
                        buf[3] |= 0x08;
                break;
+       case TUNER_PHILIPS_TD1316:
+               /* determine band */
+               buf[3] |= (params->frequency < 161000000) ? 1 :
+                         (params->frequency < 444000000) ? 2 : 4;
+
+               /* setup PLL filter */
+               if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+                       buf[3] |= 1 << 3;
+               break;
+       case TUNER_PHILIPS_TUV1236D:
+       case TUNER_PHILIPS_FCV1236D:
+       {
+               unsigned int new_rf;
+
+               if (dtv_input[priv->nr])
+                       new_rf = dtv_input[priv->nr];
+               else
+                       switch (params->u.vsb.modulation) {
+                       case QAM_64:
+                       case QAM_256:
+                               new_rf = 1;
+                               break;
+                       case VSB_8:
+                       default:
+                               new_rf = 0;
+                               break;
+                       }
+               simple_set_rf_input(fe, &buf[2], &buf[3], new_rf);
+               break;
+       }
        default:
                break;
        }
 }
 
-static int simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
+static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
                                const struct dvb_frontend_parameters *params)
 {
+       /* This function returns the tuned frequency on success, 0 on error */
        struct tuner_simple_priv *priv = fe->tuner_priv;
        struct tunertype *tun = priv->tun;
        static struct tuner_params *t_params;
@@ -743,7 +818,7 @@ static int simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
        t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL);
        ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb);
        if (ret < 0)
-               return ret;
+               return 0; /* failure */
 
        div = ((frequency + t_params->iffreq) * 62500 + offset +
               tun->stepsize/2) / tun->stepsize;
@@ -767,17 +842,14 @@ static int simple_dvb_calc_regs(struct dvb_frontend *fe,
                                u8 *buf, int buf_len)
 {
        struct tuner_simple_priv *priv = fe->tuner_priv;
-       int ret;
        u32 frequency;
 
        if (buf_len < 5)
                return -EINVAL;
 
-       ret = simple_dvb_configure(fe, buf+1, params);
-       if (ret < 0)
-               return ret;
-       else
-               frequency = ret;
+       frequency = simple_dvb_configure(fe, buf+1, params);
+       if (frequency == 0)
+               return -EINVAL;
 
        buf[0] = priv->i2c_props.addr;
 
@@ -927,10 +999,32 @@ struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
 
        if (type >= tuner_count) {
                printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n",
-                      __FUNCTION__, type, tuner_count-1);
+                      __func__, type, tuner_count-1);
                return NULL;
        }
 
+       /* If i2c_adap is set, check that the tuner is at the correct address.
+        * Otherwise, if i2c_adap is NULL, the tuner will be programmed directly
+        * by the digital demod via calc_regs.
+        */
+       if (i2c_adap != NULL) {
+               u8 b[1];
+               struct i2c_msg msg = {
+                       .addr = i2c_addr, .flags = I2C_M_RD,
+                       .buf = b, .len = 1,
+               };
+
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 1);
+
+               if (1 != i2c_transfer(i2c_adap, &msg, 1))
+                       tuner_warn("unable to probe %s, proceeding anyway.",
+                                  tuners[type].name);
+
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+       }
+
        mutex_lock(&tuner_simple_list_mutex);
 
        instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv,
@@ -947,6 +1041,7 @@ struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
 
                priv->type = type;
                priv->tun  = &tuners[type];
+               priv->nr   = simple_devcount++;
                break;
        default:
                fe->tuner_priv = priv;
@@ -960,6 +1055,24 @@ struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
 
        tuner_info("type set to %d (%s)\n", type, priv->tun->name);
 
+       if ((debug) || ((atv_input[priv->nr] > 0) ||
+                       (dtv_input[priv->nr] > 0))) {
+               if (0 == atv_input[priv->nr])
+                       tuner_info("tuner %d atv rf input will be "
+                                  "autoselected\n", priv->nr);
+               else
+                       tuner_info("tuner %d atv rf input will be "
+                                  "set to input %d (insmod option)\n",
+                                  priv->nr, atv_input[priv->nr]);
+               if (0 == dtv_input[priv->nr])
+                       tuner_info("tuner %d dtv rf input will be "
+                                  "autoselected\n", priv->nr);
+               else
+                       tuner_info("tuner %d dtv rf input will be "
+                                  "set to input %d (insmod option)\n",
+                                  priv->nr, dtv_input[priv->nr]);
+       }
+
        strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name,
                sizeof(fe->ops.tuner_ops.info.name));