[media] mt2063: Fix analog/digital set params logic
authorMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 21 Jul 2011 18:46:49 +0000 (15:46 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 5 Jan 2012 00:21:34 +0000 (22:21 -0200)
The driver were using a hacky way of setting analog and digital
frequencies. Remove the hack and properly add the tuner logic for
each supported type of standard.

I was tempted to add more standards there, like SECAM and to fix
radio (as stepping seems broken), but I opted to keep it as-is,
as tests would be needed to add additional standards.

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

index 5154b9d08384622e841f6ac130c51f2efddf81ec..4f634ad24e14dc5f41803092435fa4305500b9cd 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/videodev2.h>
 
 #include "mt2063.h"
 
@@ -201,21 +202,6 @@ enum MT2063_Register_Offsets {
        MT2063_REG_END_REGS
 };
 
-enum MTTune_atv_standard {
-       MTTUNEA_UNKNOWN = 0,
-       MTTUNEA_PAL_B,
-       MTTUNEA_PAL_G,
-       MTTUNEA_PAL_I,
-       MTTUNEA_PAL_L,
-       MTTUNEA_PAL_MN,
-       MTTUNEA_PAL_DK,
-       MTTUNEA_DIGITAL,
-       MTTUNEA_FMRADIO,
-       MTTUNEA_DVBC,
-       MTTUNEA_DVBT
-};
-
-
 struct mt2063_state {
        struct i2c_adapter *i2c;
 
@@ -224,7 +210,6 @@ struct mt2063_state {
        struct dvb_frontend *frontend;
        struct tuner_state status;
 
-       enum MTTune_atv_standard tv_type;
        u32 frequency;
        u32 srate;
        u32 bandwidth;
@@ -258,9 +243,11 @@ static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len)
        msg.buf[0] = reg;
        memcpy(msg.buf + 1, data, len);
 
-       fe->ops.i2c_gate_ctrl(fe, 1);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        ret = i2c_transfer(state->i2c, &msg, 1);
-       fe->ops.i2c_gate_ctrl(fe, 0);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
 
        if (ret < 0)
                printk(KERN_ERR "%s error ret=%d\n", __func__, ret);
@@ -297,7 +284,8 @@ static u32 mt2063_read(struct mt2063_state *state,
        struct dvb_frontend *fe = state->frontend;
        u32 i = 0;
 
-       fe->ops.i2c_gate_ctrl(fe, 1);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
 
        for (i = 0; i < cnt; i++) {
                int ret;
@@ -320,7 +308,9 @@ static u32 mt2063_read(struct mt2063_state *state,
                if (ret < 0)
                        break;
        }
-       fe->ops.i2c_gate_ctrl(fe, 0);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+
        return status;
 }
 
@@ -997,7 +987,7 @@ static const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 };
  *
  * This function returns 0, if no lock, 1 if locked and a value < 1 if error
  */
-unsigned int mt2063_lockStatus(struct mt2063_state *state)
+static unsigned int mt2063_lockStatus(struct mt2063_state *state)
 {
        const u32 nMaxWait = 100;       /*  wait a maximum of 100 msec   */
        const u32 nPollRate = 2;        /*  poll status bits every 2 ms */
@@ -1030,7 +1020,6 @@ unsigned int mt2063_lockStatus(struct mt2063_state *state)
         */
        return 0;
 }
-EXPORT_SYMBOL_GPL(mt2063_lockStatus);
 
 /*
  * mt2063_set_dnc_output_enable()
@@ -1922,132 +1911,6 @@ static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in)
        return status;
 }
 
-int mt2063_setTune(struct dvb_frontend *fe, u32 f_in, u32 bw_in,
-                  enum MTTune_atv_standard tv_type)
-{
-       struct mt2063_state *state = fe->tuner_priv;
-       u32 status = 0;
-       s32 pict_car = 0;
-       s32 pict2chanb_vsb = 0;
-       s32 pict2chanb_snd = 0;
-       s32 pict2snd1 = 0;
-       s32 pict2snd2 = 0;
-       s32 ch_bw = 0;
-       s32 if_mid = 0;
-       s32 rcvr_mode = 0;
-
-       switch (tv_type) {
-       case MTTUNEA_PAL_B:{
-                       pict_car = 38900000;
-                       ch_bw = 8000000;
-                       pict2chanb_vsb = -1250000;
-                       pict2snd1 = 5500000;
-                       pict2snd2 = 5742000;
-                       rcvr_mode = 1;
-                       break;
-               }
-       case MTTUNEA_PAL_G:{
-                       pict_car = 38900000;
-                       ch_bw = 7000000;
-                       pict2chanb_vsb = -1250000;
-                       pict2snd1 = 5500000;
-                       pict2snd2 = 0;
-                       rcvr_mode = 1;
-                       break;
-               }
-       case MTTUNEA_PAL_I:{
-                       pict_car = 38900000;
-                       ch_bw = 8000000;
-                       pict2chanb_vsb = -1250000;
-                       pict2snd1 = 6000000;
-                       pict2snd2 = 0;
-                       rcvr_mode = 1;
-                       break;
-               }
-       case MTTUNEA_PAL_L:{
-                       pict_car = 38900000;
-                       ch_bw = 8000000;
-                       pict2chanb_vsb = -1250000;
-                       pict2snd1 = 6500000;
-                       pict2snd2 = 0;
-                       rcvr_mode = 1;
-                       break;
-               }
-       case MTTUNEA_PAL_MN:{
-                       pict_car = 38900000;
-                       ch_bw = 6000000;
-                       pict2chanb_vsb = -1250000;
-                       pict2snd1 = 4500000;
-                       pict2snd2 = 0;
-                       rcvr_mode = 1;
-                       break;
-               }
-       case MTTUNEA_PAL_DK:{
-                       pict_car = 38900000;
-                       ch_bw = 8000000;
-                       pict2chanb_vsb = -1250000;
-                       pict2snd1 = 6500000;
-                       pict2snd2 = 0;
-                       rcvr_mode = 1;
-                       break;
-               }
-       case MTTUNEA_DIGITAL:{
-                       pict_car = 36125000;
-                       ch_bw = 8000000;
-                       pict2chanb_vsb = -(ch_bw / 2);
-                       pict2snd1 = 0;
-                       pict2snd2 = 0;
-                       rcvr_mode = 2;
-                       break;
-               }
-       case MTTUNEA_FMRADIO:{
-                       pict_car = 38900000;
-                       ch_bw = 8000000;
-                       pict2chanb_vsb = -(ch_bw / 2);
-                       pict2snd1 = 0;
-                       pict2snd2 = 0;
-                       rcvr_mode = 4;
-                       break;
-               }
-       case MTTUNEA_DVBC:{
-                       pict_car = 36125000;
-                       ch_bw = 8000000;
-                       pict2chanb_vsb = -(ch_bw / 2);
-                       pict2snd1 = 0;
-                       pict2snd2 = 0;
-                       rcvr_mode = MT2063_CABLE_QAM;
-                       break;
-               }
-       case MTTUNEA_DVBT:{
-                       pict_car = 36125000;
-                       ch_bw = bw_in;
-                       pict2chanb_vsb = -(ch_bw / 2);
-                       pict2snd1 = 0;
-                       pict2snd2 = 0;
-                       rcvr_mode = MT2063_OFFAIR_COFDM;
-                       break;
-               }
-       case MTTUNEA_UNKNOWN:
-               break;
-       default:
-               break;
-       }
-
-       pict2chanb_snd = pict2chanb_vsb - ch_bw;
-       if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
-
-       state->AS_Data.f_LO2_Step = 125000;
-       state->AS_Data.f_out = if_mid;
-       state->AS_Data.f_out_bw = ch_bw + 750000;
-       status = MT2063_SetReceiverMode(state, rcvr_mode);
-       if (status < 0)
-               return status;
-
-       status = MT2063_Tune(state, (f_in + (pict2chanb_vsb + (ch_bw / 2))));
-
-       return status;
-}
-
 static const u8 MT2063B0_defaults[] = {
        /* Reg,  Value */
        0x19, 0x05,
@@ -2300,83 +2163,208 @@ static int mt2063_init(struct dvb_frontend *fe)
        return 0;
 }
 
-static int mt2063_get_status(struct dvb_frontend *fe, u32 * status)
+static int mt2063_get_status(struct dvb_frontend *fe, u32 *tuner_status)
 {
-       int rc = 0;
+       struct mt2063_state *state = fe->tuner_priv;
+       int status;
 
-       /* FIXME: add get tuner lock status */
+       *tuner_status = 0;
+       status = mt2063_lockStatus(state);
+       if (status < 0)
+               return status;
+       if (status)
+           *tuner_status = TUNER_STATUS_LOCKED;
 
-       return rc;
+       return 0;
 }
 
-static int mt2063_get_state(struct dvb_frontend *fe,
-                           enum tuner_param param, struct tuner_state *tunstate)
+static int mt2063_release(struct dvb_frontend *fe)
 {
        struct mt2063_state *state = fe->tuner_priv;
 
-       switch (param) {
-       case DVBFE_TUNER_FREQUENCY:
-               /* get frequency */
-               break;
-       case DVBFE_TUNER_TUNERSTEP:
-               break;
-       case DVBFE_TUNER_IFFREQ:
-               break;
-       case DVBFE_TUNER_BANDWIDTH:
-               /* get bandwidth */
-               break;
-       case DVBFE_TUNER_REFCLOCK:
-               tunstate->refclock = mt2063_lockStatus(state);
+       fe->tuner_priv = NULL;
+       kfree(state);
+
+       return 0;
+}
+
+static int mt2063_set_analog_params(struct dvb_frontend *fe,
+                                   struct analog_parameters *params)
+{
+       struct mt2063_state *state = fe->tuner_priv;
+       s32 pict_car = 0;
+       s32 pict2chanb_vsb = 0;
+       s32 pict2chanb_snd = 0;
+       s32 pict2snd1 = 0;
+       s32 pict2snd2 = 0;
+       s32 ch_bw = 0;
+       s32 if_mid = 0;
+       s32 rcvr_mode = 0;
+       int status;
+
+       switch (params->mode) {
+       case V4L2_TUNER_RADIO:
+               pict_car = 38900000;
+               ch_bw = 8000000;
+               pict2chanb_vsb = -(ch_bw / 2);
+               pict2snd1 = 0;
+               pict2snd2 = 0;
+               rcvr_mode = MT2063_OFFAIR_ANALOG;
                break;
-       default:
+       case V4L2_TUNER_ANALOG_TV:
+               rcvr_mode = MT2063_CABLE_ANALOG;
+               if (params->std & ~V4L2_STD_MN) {
+                       pict_car = 38900000;
+                       ch_bw = 6000000;
+                       pict2chanb_vsb = -1250000;
+                       pict2snd1 = 4500000;
+                       pict2snd2 = 0;
+               } else if (params->std & V4L2_STD_PAL_I) {
+                       pict_car = 38900000;
+                       ch_bw = 8000000;
+                       pict2chanb_vsb = -1250000;
+                       pict2snd1 = 6000000;
+                       pict2snd2 = 0;
+               } else if (params->std & V4L2_STD_PAL_B) {
+                       pict_car = 38900000;
+                       ch_bw = 8000000;
+                       pict2chanb_vsb = -1250000;
+                       pict2snd1 = 5500000;
+                       pict2snd2 = 5742000;
+               } else if (params->std & V4L2_STD_PAL_G) {
+                       pict_car = 38900000;
+                       ch_bw = 7000000;
+                       pict2chanb_vsb = -1250000;
+                       pict2snd1 = 5500000;
+                       pict2snd2 = 0;
+               } else if (params->std & V4L2_STD_PAL_DK) {
+                       pict_car = 38900000;
+                       ch_bw = 8000000;
+                       pict2chanb_vsb = -1250000;
+                       pict2snd1 = 6500000;
+                       pict2snd2 = 0;
+               } else {        /* PAL-L */
+                       pict_car = 38900000;
+                       ch_bw = 8000000;
+                       pict2chanb_vsb = -1250000;
+                       pict2snd1 = 6500000;
+                       pict2snd2 = 0;
+               }
                break;
        }
+       pict2chanb_snd = pict2chanb_vsb - ch_bw;
+       if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
+
+       state->AS_Data.f_LO2_Step = 125000;     /* FIXME: probably 5000 for FM */
+       state->AS_Data.f_out = if_mid;
+       state->AS_Data.f_out_bw = ch_bw + 750000;
+       status = MT2063_SetReceiverMode(state, rcvr_mode);
+       if (status < 0)
+               return status;
+
+       status = MT2063_Tune(state, (params->frequency + (pict2chanb_vsb + (ch_bw / 2))));
+       if (status < 0)
+               return status;
 
-       return (int)tunstate->refclock;
+       state->frequency = params->frequency;
+       return 0;
 }
 
-static int mt2063_set_state(struct dvb_frontend *fe,
-                           enum tuner_param param, struct tuner_state *tunstate)
+/*
+ * As defined on EN 300 429, the DVB-C roll-off factor is 0.15.
+ * So, the amount of the needed bandwith is given by:
+ *     Bw = Symbol_rate * (1 + 0.15)
+ * As such, the maximum symbol rate supported by 6 MHz is given by:
+ *     max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds
+ */
+#define MAX_SYMBOL_RATE_6MHz   5217391
+
+static int mt2063_set_params(struct dvb_frontend *fe,
+                            struct dvb_frontend_parameters *params)
 {
        struct mt2063_state *state = fe->tuner_priv;
-       u32 status = 0;
-
-       switch (param) {
-       case DVBFE_TUNER_FREQUENCY:
-               /* set frequency */
-
-               status =
-                   mt2063_setTune(fe,
-                               tunstate->frequency, tunstate->bandwidth,
-                               state->tv_type);
+       int status;
+       s32 pict_car = 0;
+       s32 pict2chanb_vsb = 0;
+       s32 pict2chanb_snd = 0;
+       s32 pict2snd1 = 0;
+       s32 pict2snd2 = 0;
+       s32 ch_bw = 0;
+       s32 if_mid = 0;
+       s32 rcvr_mode = 0;
 
-               state->frequency = tunstate->frequency;
-               break;
-       case DVBFE_TUNER_TUNERSTEP:
-               break;
-       case DVBFE_TUNER_IFFREQ:
-               break;
-       case DVBFE_TUNER_BANDWIDTH:
-               /* set bandwidth */
-               state->bandwidth = tunstate->bandwidth;
+       switch (fe->ops.info.type) {
+       case FE_OFDM:
+               switch (params->u.ofdm.bandwidth) {
+               case BANDWIDTH_6_MHZ:
+                       ch_bw = 6000000;
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       ch_bw = 7000000;
+                       break;
+               case BANDWIDTH_8_MHZ:
+                       ch_bw = 8000000;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               rcvr_mode = MT2063_OFFAIR_COFDM;
+               pict_car = 36125000;
+               pict2chanb_vsb = -(ch_bw / 2);
+               pict2snd1 = 0;
+               pict2snd2 = 0;
                break;
-       case DVBFE_TUNER_REFCLOCK:
-
+       case FE_QAM:
+               /*
+                * Using a 8MHz bandwidth sometimes fail
+                * with 6MHz-spaced channels, due to inter-carrier
+                * interference. So, it is better to narrow-down the filter
+                */
+               if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz)
+                       ch_bw = 6000000;
+               else
+                       ch_bw = 8000000;
+               rcvr_mode = MT2063_CABLE_QAM;
+               pict_car = 36125000;
+               pict2snd1 = 0;
+               pict2snd2 = 0;
+               pict2chanb_vsb = -(ch_bw / 2);
                break;
        default:
-               break;
+               return -EINVAL;
        }
+       pict2chanb_snd = pict2chanb_vsb - ch_bw;
+       if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
+
+       state->AS_Data.f_LO2_Step = 125000;     /* FIXME: probably 5000 for FM */
+       state->AS_Data.f_out = if_mid;
+       state->AS_Data.f_out_bw = ch_bw + 750000;
+       status = MT2063_SetReceiverMode(state, rcvr_mode);
+       if (status < 0)
+               return status;
+
+       status = MT2063_Tune(state, (params->frequency + (pict2chanb_vsb + (ch_bw / 2))));
+
+       if (status < 0)
+           return status;
 
-       return (int)status;
+       state->frequency = params->frequency;
+       return 0;
 }
 
-static int mt2063_release(struct dvb_frontend *fe)
+static int mt2063_get_frequency(struct dvb_frontend *fe, u32 *freq)
 {
        struct mt2063_state *state = fe->tuner_priv;
 
-       fe->tuner_priv = NULL;
-       kfree(state);
+       *freq = state->frequency;
+       return 0;
+}
+
+static int mt2063_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
+{
+       struct mt2063_state *state = fe->tuner_priv;
 
+       *bw = state->AS_Data.f_out_bw - 750000;
        return 0;
 }
 
@@ -2391,9 +2379,11 @@ static struct dvb_tuner_ops mt2063_ops = {
        .init = mt2063_init,
        .sleep = MT2063_Sleep,
        .get_status = mt2063_get_status,
-       .get_state = mt2063_get_state,
-       .set_state = mt2063_set_state,
-       .release = mt2063_release
+       .set_analog_params = mt2063_set_analog_params,
+       .set_params    = mt2063_set_params,
+       .get_frequency = mt2063_get_frequency,
+       .get_bandwidth = mt2063_get_bandwidth,
+       .release = mt2063_release,
 };
 
 struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
index b2e3abf95ec86299423f369713ffa36f55530873..62d0e8ec4e99723a9a2c6682a200056f9efbab75 100644 (file)
@@ -28,7 +28,6 @@ int mt2063_setTune(struct dvb_frontend *fe, u32 f_in,
                                   enum MTTune_atv_standard tv_type);
 
 /* FIXME: Should use the standard DVB attachment interfaces */
-unsigned int mt2063_lockStatus(struct dvb_frontend *fe);
 unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe);
 unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe);