summaryrefslogtreecommitdiff
path: root/drivers/media/common/tuners
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2011-07-21 22:46:49 +0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-01-05 04:21:34 +0400
commit99ac54125490f16f7434f82fcb73bbb88290b38e (patch)
tree75d28f81fbe285f8a3d6fd8ee72d6a159a615ab6 /drivers/media/common/tuners
parent6fb167000e6b726bc9f129af08b6aad3ef075da4 (diff)
downloadlinux-99ac54125490f16f7434f82fcb73bbb88290b38e.tar.xz
[media] mt2063: Fix analog/digital set params logic
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>
Diffstat (limited to 'drivers/media/common/tuners')
-rw-r--r--drivers/media/common/tuners/mt2063.c390
-rw-r--r--drivers/media/common/tuners/mt2063.h1
2 files changed, 190 insertions, 201 deletions
diff --git a/drivers/media/common/tuners/mt2063.c b/drivers/media/common/tuners/mt2063.c
index 5154b9d08384..4f634ad24e14 100644
--- a/drivers/media/common/tuners/mt2063.c
+++ b/drivers/media/common/tuners/mt2063.c
@@ -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,
diff --git a/drivers/media/common/tuners/mt2063.h b/drivers/media/common/tuners/mt2063.h
index b2e3abf95ec8..62d0e8ec4e99 100644
--- a/drivers/media/common/tuners/mt2063.h
+++ b/drivers/media/common/tuners/mt2063.h
@@ -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);