V4L/DVB (6988): tda18271: give calibration debug a separate debug mask
[safe/jmp/linux-2.6] / drivers / media / dvb / frontends / tda18271-fe.c
index a02d640..0b41b95 100644 (file)
 
 int tda18271_debug;
 module_param_named(debug, tda18271_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debug level (info=1, map=2, reg=4 (or-able))");
+MODULE_PARM_DESC(debug, "set debug level "
+                "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))");
+
+static LIST_HEAD(tda18271_list);
+static DEFINE_MUTEX(tda18271_list_mutex);
 
 /*---------------------------------------------------------------------*/
 
-static int tda18271_init(struct dvb_frontend *fe)
+static int tda18271_ir_cal_init(struct dvb_frontend *fe)
 {
        struct tda18271_priv *priv = fe->tuner_priv;
        unsigned char *regs = priv->tda18271_regs;
@@ -45,7 +49,8 @@ static int tda18271_init(struct dvb_frontend *fe)
 /* ------------------------------------------------------------------ */
 
 static int tda18271_channel_configuration(struct dvb_frontend *fe,
-                                         u32 ifc, u32 freq, u32 bw, u8 std)
+                                         u32 ifc, u32 freq, u32 bw, u8 std,
+                                         int radio)
 {
        struct tda18271_priv *priv = fe->tuner_priv;
        unsigned char *regs = priv->tda18271_regs;
@@ -72,7 +77,11 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe,
                regs[R_MPD]  |= 0x80; /* IF notch = 1 */
                break;
        }
-       regs[R_EP4]  &= ~0x80; /* FM_RFn: turn this bit on only for fm radio */
+
+       if (radio)
+               regs[R_EP4]  |=  0x80;
+       else
+               regs[R_EP4]  &= ~0x80;
 
        /* update RF_TOP / IF_TOP */
        switch (priv->mode) {
@@ -183,7 +192,7 @@ static int tda18271_read_thermometer(struct dvb_frontend *fe)
 }
 
 static int tda18271_rf_tracking_filters_correction(struct dvb_frontend *fe,
-                                                  u32 freq, int tm_rfcal)
+                                                  u32 freq)
 {
        struct tda18271_priv *priv = fe->tuner_priv;
        struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
@@ -223,7 +232,7 @@ static int tda18271_rf_tracking_filters_correction(struct dvb_frontend *fe,
        tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt);
 
        /* calculate temperature compensation */
-       rfcal_comp = dc_over_dt * (tm_current - tm_rfcal);
+       rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal);
 
        regs[R_EB14] = approx + rfcal_comp;
        tda18271_write_regs(fe, R_EB14, 1);
@@ -450,7 +459,7 @@ static int tda18271_powerscan(struct dvb_frontend *fe,
        } else
                bcal = 0;
 
-       tda_dbg("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n",
+       tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n",
                bcal, *freq_in, *freq_out, freq);
 
        return bcal;
@@ -513,7 +522,7 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
        for (rf = RF1; rf <= RF3; rf++) {
                if (0 == rf_default[rf])
                        return 0;
-               tda_dbg("freq = %d, rf = %d\n", freq, rf);
+               tda_cal("freq = %d, rf = %d\n", freq, rf);
 
                /* look for optimized calibration frequency */
                bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]);
@@ -553,8 +562,7 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
        return 0;
 }
 
-static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe,
-                                        int *tm_rfcal)
+static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe)
 {
        struct tda18271_priv *priv = fe->tuner_priv;
        unsigned int i;
@@ -571,24 +579,21 @@ static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe,
                tda18271_rf_tracking_filters_init(fe, 1000 *
                                                  priv->rf_cal_state[i].rfmax);
 
-       *tm_rfcal = tda18271_read_thermometer(fe);
+       priv->tm_rfcal = tda18271_read_thermometer(fe);
 
        return 0;
 }
 
 /* ------------------------------------------------------------------ */
 
-static int tda18271_init_cal(struct dvb_frontend *fe, int *tm)
+static int tda18271_rf_cal_init(struct dvb_frontend *fe)
 {
        struct tda18271_priv *priv = fe->tuner_priv;
 
        if (priv->cal_initialized)
                return 0;
 
-       /* initialization */
-       tda18271_init(fe);
-
-       tda18271_calc_rf_filter_curve(fe, tm);
+       tda18271_calc_rf_filter_curve(fe);
 
        tda18271_por(fe);
 
@@ -597,18 +602,39 @@ static int tda18271_init_cal(struct dvb_frontend *fe, int *tm)
        return 0;
 }
 
+static int tda18271_init(struct dvb_frontend *fe)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+
+       mutex_lock(&priv->lock);
+
+       /* initialization */
+       tda18271_ir_cal_init(fe);
+
+       if (priv->id == TDA18271HDC2)
+               tda18271_rf_cal_init(fe);
+
+       mutex_unlock(&priv->lock);
+
+       return 0;
+}
+
 static int tda18271c2_tune(struct dvb_frontend *fe,
-                          u32 ifc, u32 freq, u32 bw, u8 std)
+                          u32 ifc, u32 freq, u32 bw, u8 std, int radio)
 {
-       int tm = 0;
+       struct tda18271_priv *priv = fe->tuner_priv;
 
        tda_dbg("freq = %d, ifc = %d\n", freq, ifc);
 
-       tda18271_init_cal(fe, &tm);
+       tda18271_init(fe);
+
+       mutex_lock(&priv->lock);
+
+       tda18271_rf_tracking_filters_correction(fe, freq);
 
-       tda18271_rf_tracking_filters_correction(fe, freq, tm);
+       tda18271_channel_configuration(fe, ifc, freq, bw, std, radio);
 
-       tda18271_channel_configuration(fe, ifc, freq, bw, std);
+       mutex_unlock(&priv->lock);
 
        return 0;
 }
@@ -616,7 +642,7 @@ static int tda18271c2_tune(struct dvb_frontend *fe,
 /* ------------------------------------------------------------------ */
 
 static int tda18271c1_tune(struct dvb_frontend *fe,
-                          u32 ifc, u32 freq, u32 bw, u8 std)
+                          u32 ifc, u32 freq, u32 bw, u8 std, int radio)
 {
        struct tda18271_priv *priv = fe->tuner_priv;
        unsigned char *regs = priv->tda18271_regs;
@@ -624,6 +650,8 @@ static int tda18271c1_tune(struct dvb_frontend *fe,
 
        tda18271_init(fe);
 
+       mutex_lock(&priv->lock);
+
        tda_dbg("freq = %d, ifc = %d\n", freq, ifc);
 
        /* RF tracking filter calibration */
@@ -746,7 +774,10 @@ static int tda18271c1_tune(struct dvb_frontend *fe,
                break;
        }
 
-       regs[R_EP4]  &= ~0x80; /* turn this bit on only for fm */
+       if (radio)
+               regs[R_EP4]  |=  0x80;
+       else
+               regs[R_EP4]  &= ~0x80;
 
        /* image rejection validity */
        tda18271_calc_ir_measure(fe, &freq);
@@ -758,10 +789,28 @@ static int tda18271c1_tune(struct dvb_frontend *fe,
 
        tda18271_write_regs(fe, R_TM, 15);
        msleep(5);
+       mutex_unlock(&priv->lock);
 
        return 0;
 }
 
+static inline int tda18271_tune(struct dvb_frontend *fe,
+                               u32 ifc, u32 freq, u32 bw, u8 std, int radio)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       int ret = -EINVAL;
+
+       switch (priv->id) {
+       case TDA18271HDC1:
+               ret = tda18271c1_tune(fe, ifc, freq, bw, std, radio);
+               break;
+       case TDA18271HDC2:
+               ret = tda18271c2_tune(fe, ifc, freq, bw, std, radio);
+               break;
+       }
+       return ret;
+}
+
 /* ------------------------------------------------------------------ */
 
 static int tda18271_set_params(struct dvb_frontend *fe,
@@ -769,12 +818,11 @@ static int tda18271_set_params(struct dvb_frontend *fe,
 {
        struct tda18271_priv *priv = fe->tuner_priv;
        struct tda18271_std_map *std_map = &priv->std;
+       int ret;
        u8 std;
        u16 sgIF;
        u32 bw, freq = params->frequency;
 
-       BUG_ON(!priv->tune);
-
        priv->mode = TDA18271_DIGITAL;
 
        /* see table 22 */
@@ -825,7 +873,16 @@ static int tda18271_set_params(struct dvb_frontend *fe,
                return -EINVAL;
        }
 
-       return priv->tune(fe, sgIF * 1000, freq, bw, std);
+       ret = tda18271_tune(fe, sgIF * 1000, freq, bw, std, 0);
+
+       if (ret < 0)
+               goto fail;
+
+       priv->frequency = freq;
+       priv->bandwidth = (fe->ops.info.type == FE_OFDM) ?
+               params->u.ofdm.bandwidth : 0;
+fail:
+       return ret;
 }
 
 static int tda18271_set_analog_params(struct dvb_frontend *fe,
@@ -834,15 +891,20 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe,
        struct tda18271_priv *priv = fe->tuner_priv;
        struct tda18271_std_map *std_map = &priv->std;
        char *mode;
+       int ret, radio = 0;
        u8 std;
        u16 sgIF;
        u32 freq = params->frequency * 62500;
 
-       BUG_ON(!priv->tune);
-
        priv->mode = TDA18271_ANALOG;
 
-       if (params->std & V4L2_STD_MN) {
+       if (params->mode == V4L2_TUNER_RADIO) {
+               radio = 1;
+               freq = freq / 1000;
+               std  = std_map->fm_radio.std_bits;
+               sgIF = std_map->fm_radio.if_freq;
+               mode = "fm";
+       } else if (params->std & V4L2_STD_MN) {
                std  = std_map->atv_mn.std_bits;
                sgIF = std_map->atv_mn.if_freq;
                mode = "MN";
@@ -878,13 +940,37 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe,
 
        tda_dbg("setting tda18271 to system %s\n", mode);
 
-       return priv->tune(fe, sgIF * 1000, freq, 0, std);
+       ret = tda18271_tune(fe, sgIF * 1000, freq, 0, std, radio);
+
+       if (ret < 0)
+               goto fail;
+
+       priv->frequency = freq;
+       priv->bandwidth = 0;
+fail:
+       return ret;
 }
 
 static int tda18271_release(struct dvb_frontend *fe)
 {
-       kfree(fe->tuner_priv);
+       struct tda18271_priv *priv = fe->tuner_priv;
+
+       mutex_lock(&tda18271_list_mutex);
+
+       priv->count--;
+
+       if (!priv->count) {
+               tda_dbg("destroying instance @ %d-%04x\n",
+                       i2c_adapter_id(priv->i2c_adap),
+                       priv->i2c_addr);
+               list_del(&priv->tda18271_list);
+
+               kfree(priv);
+       }
+       mutex_unlock(&tda18271_list_mutex);
+
        fe->tuner_priv = NULL;
+
        return 0;
 }
 
@@ -922,6 +1008,7 @@ static int tda18271_dump_std_map(struct dvb_frontend *fe)
        struct tda18271_std_map *std = &priv->std;
 
        tda_dbg("========== STANDARD MAP SETTINGS ==========\n");
+       tda18271_dump_std_item(fm_radio, "fm");
        tda18271_dump_std_item(atv_b,  "pal b");
        tda18271_dump_std_item(atv_dk, "pal dk");
        tda18271_dump_std_item(atv_gh, "pal gh");
@@ -948,6 +1035,7 @@ static int tda18271_update_std_map(struct dvb_frontend *fe,
        if (!map)
                return -EINVAL;
 
+       tda18271_update_std(fm_radio, "fm");
        tda18271_update_std(atv_b,  "atv b");
        tda18271_update_std(atv_dk, "atv dk");
        tda18271_update_std(atv_gh, "atv gh");
@@ -972,18 +1060,18 @@ static int tda18271_get_id(struct dvb_frontend *fe)
        char *name;
        int ret = 0;
 
+       mutex_lock(&priv->lock);
        tda18271_read_regs(fe);
+       mutex_unlock(&priv->lock);
 
        switch (regs[R_ID] & 0x7f) {
        case 3:
                name = "TDA18271HD/C1";
                priv->id = TDA18271HDC1;
-               priv->tune = tda18271c1_tune;
                break;
        case 4:
                name = "TDA18271HD/C2";
                priv->id = TDA18271HDC2;
-               priv->tune = tda18271c2_tune;
                break;
        default:
                name = "Unknown device";
@@ -1018,38 +1106,73 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
                                     struct tda18271_config *cfg)
 {
        struct tda18271_priv *priv = NULL;
+       int state_found = 0;
+
+       mutex_lock(&tda18271_list_mutex);
+
+       list_for_each_entry(priv, &tda18271_list, tda18271_list) {
+               if ((i2c_adapter_id(priv->i2c_adap) == i2c_adapter_id(i2c)) &&
+                   (priv->i2c_addr == addr)) {
+                       tda_dbg("attaching existing tuner @ %d-%04x\n",
+                               i2c_adapter_id(priv->i2c_adap),
+                               priv->i2c_addr);
+                       priv->count++;
+                       fe->tuner_priv = priv;
+                       state_found = 1;
+                       /* allow dvb driver to override i2c gate setting */
+                       if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG))
+                               priv->gate = cfg->gate;
+                       break;
+               }
+       }
+       if (state_found == 0) {
+               tda_dbg("creating new tuner instance @ %d-%04x\n",
+                       i2c_adapter_id(i2c), addr);
+
+               priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL);
+               if (priv == NULL) {
+                       mutex_unlock(&tda18271_list_mutex);
+                       return NULL;
+               }
 
-       priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL);
-       if (priv == NULL)
-               return NULL;
+               priv->i2c_addr = addr;
+               priv->i2c_adap = i2c;
+               priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
+               priv->cal_initialized = false;
+               mutex_init(&priv->lock);
+               priv->count++;
 
-       priv->i2c_addr = addr;
-       priv->i2c_adap = i2c;
-       priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
-       priv->cal_initialized = false;
+               fe->tuner_priv = priv;
 
-       fe->tuner_priv = priv;
+               list_add_tail(&priv->tda18271_list, &tda18271_list);
 
-       if (tda18271_get_id(fe) < 0)
-               goto fail;
+               if (tda18271_get_id(fe) < 0)
+                       goto fail;
 
-       if (tda18271_assign_map_layout(fe) < 0)
-               goto fail;
+               if (tda18271_assign_map_layout(fe) < 0)
+                       goto fail;
 
-       memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops,
-              sizeof(struct dvb_tuner_ops));
+               mutex_lock(&priv->lock);
+               tda18271_init_regs(fe);
+               mutex_unlock(&priv->lock);
+       }
 
        /* override default std map with values in config struct */
        if ((cfg) && (cfg->std_map))
                tda18271_update_std_map(fe, cfg->std_map);
 
+       mutex_unlock(&tda18271_list_mutex);
+
+       memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops,
+              sizeof(struct dvb_tuner_ops));
+
        if (tda18271_debug & DBG_MAP)
                tda18271_dump_std_map(fe);
 
-       tda18271_init_regs(fe);
-
        return fe;
 fail:
+       mutex_unlock(&tda18271_list_mutex);
+
        tda18271_release(fe);
        return NULL;
 }