aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/common/tuners
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/common/tuners')
-rw-r--r--drivers/media/common/tuners/mt2060.c38
-rw-r--r--drivers/media/common/tuners/mxl5005s.c10
-rw-r--r--drivers/media/common/tuners/mxl5007t.c1
-rw-r--r--drivers/media/common/tuners/tda18271-fe.c1
-rw-r--r--drivers/media/common/tuners/tda827x.c12
-rw-r--r--drivers/media/common/tuners/tda827x.h1
-rw-r--r--drivers/media/common/tuners/tda8290.c4
-rw-r--r--drivers/media/common/tuners/tda8290.h1
-rw-r--r--drivers/media/common/tuners/tda9887.c1
-rw-r--r--drivers/media/common/tuners/tuner-simple.c5
-rw-r--r--drivers/media/common/tuners/tuner-types.c55
-rw-r--r--drivers/media/common/tuners/tuner-xc2028.c74
-rw-r--r--drivers/media/common/tuners/tuner-xc2028.h10
-rw-r--r--drivers/media/common/tuners/xc5000.c180
-rw-r--r--drivers/media/common/tuners/xc5000.h16
-rw-r--r--drivers/media/common/tuners/xc5000_priv.h37
16 files changed, 280 insertions, 166 deletions
diff --git a/drivers/media/common/tuners/mt2060.c b/drivers/media/common/tuners/mt2060.c
index 1305b0e63ce..12206d75dd4 100644
--- a/drivers/media/common/tuners/mt2060.c
+++ b/drivers/media/common/tuners/mt2060.c
@@ -170,6 +170,9 @@ static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
b[0] = REG_LO1B1;
b[1] = 0xFF;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
mt2060_writeregs(priv,b,2);
freq = params->frequency / 1000; // Hz -> kHz
@@ -233,6 +236,9 @@ static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
i++;
} while (i<10);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
return ret;
}
@@ -296,13 +302,35 @@ static int mt2060_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
static int mt2060_init(struct dvb_frontend *fe)
{
struct mt2060_priv *priv = fe->tuner_priv;
- return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x33);
+ int ret;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+ ret = mt2060_writereg(priv, REG_VGAG,
+ (priv->cfg->clock_out << 6) | 0x33);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+ return ret;
}
static int mt2060_sleep(struct dvb_frontend *fe)
{
struct mt2060_priv *priv = fe->tuner_priv;
- return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30);
+ int ret;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+ ret = mt2060_writereg(priv, REG_VGAG,
+ (priv->cfg->clock_out << 6) | 0x30);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+ return ret;
}
static int mt2060_release(struct dvb_frontend *fe)
@@ -344,6 +372,9 @@ struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter
priv->i2c = i2c;
priv->if1_freq = if1;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) {
kfree(priv);
return NULL;
@@ -360,6 +391,9 @@ struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter
mt2060_calibrate(priv);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
return fe;
}
EXPORT_SYMBOL(mt2060_attach);
diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c
index 227642b044a..a8878244bb3 100644
--- a/drivers/media/common/tuners/mxl5005s.c
+++ b/drivers/media/common/tuners/mxl5005s.c
@@ -3481,7 +3481,9 @@ static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum,
}
ctrlVal = 0;
for (k = 0; k < state->MXL_Ctrl[i].size; k++)
- ctrlVal += state->MXL_Ctrl[i].val[k] * (1 << k);
+ ctrlVal += state->
+ MXL_Ctrl[i].val[k] *
+ (1 << k);
} else
return -1;
}
@@ -3581,7 +3583,7 @@ static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit,
static u32 MXL_Ceiling(u32 value, u32 resolution)
{
- return (value/resolution + (value % resolution > 0 ? 1 : 0));
+ return value / resolution + (value % resolution > 0 ? 1 : 0);
}
/* Retrieve the Initialzation Registers */
@@ -3910,7 +3912,10 @@ static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable,
static int mxl5005s_init(struct dvb_frontend *fe)
{
+ struct mxl5005s_state *state = fe->tuner_priv;
+
dprintk(1, "%s()\n", __func__);
+ state->current_mode = MXL_QAM;
return mxl5005s_reconfigure(fe, MXL_QAM, MXL5005S_BANDWIDTH_6MHZ);
}
@@ -4092,7 +4097,6 @@ struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
state->frontend = fe;
state->config = config;
state->i2c = i2c;
- state->current_mode = MXL_QAM;
printk(KERN_INFO "MXL5005S: Attached at address 0x%02x\n",
config->i2c_address);
diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/common/tuners/mxl5007t.c
index cb25e43502f..64379f2bf23 100644
--- a/drivers/media/common/tuners/mxl5007t.c
+++ b/drivers/media/common/tuners/mxl5007t.c
@@ -979,7 +979,6 @@ struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
switch (instance) {
case 0:
goto fail;
- break;
case 1:
/* new tuner instance */
state->config = cfg;
diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c
index 93063c6fbbf..1b48b5d0bf1 100644
--- a/drivers/media/common/tuners/tda18271-fe.c
+++ b/drivers/media/common/tuners/tda18271-fe.c
@@ -1155,7 +1155,6 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
switch (instance) {
case 0:
goto fail;
- break;
case 1:
/* new tuner instance */
priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
diff --git a/drivers/media/common/tuners/tda827x.c b/drivers/media/common/tuners/tda827x.c
index 8555d9cf905..4a74f65e759 100644
--- a/drivers/media/common/tuners/tda827x.c
+++ b/drivers/media/common/tuners/tda827x.c
@@ -447,17 +447,19 @@ static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
else
arg = 0;
}
- if (priv->cfg->tuner_callback)
- priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
- gp_func, arg);
+ if (fe->callback)
+ fe->callback(priv->i2c_adap->algo_data,
+ DVB_FRONTEND_COMPONENT_TUNER,
+ gp_func, arg);
buf[1] = high ? 0 : 1;
if (priv->cfg->config == 2)
buf[1] = high ? 1 : 0;
i2c_transfer(priv->i2c_adap, &msg, 1);
break;
case 3: /* switch with GPIO of saa713x */
- if (priv->cfg->tuner_callback)
- priv->cfg->tuner_callback(priv->i2c_adap->algo_data, 0, high);
+ if (fe->callback)
+ fe->callback(priv->i2c_adap->algo_data,
+ DVB_FRONTEND_COMPONENT_TUNER, 0, high);
break;
}
}
diff --git a/drivers/media/common/tuners/tda827x.h b/drivers/media/common/tuners/tda827x.h
index 7850a9a1dc8..7d72ce0a0c2 100644
--- a/drivers/media/common/tuners/tda827x.h
+++ b/drivers/media/common/tuners/tda827x.h
@@ -36,7 +36,6 @@ struct tda827x_config
/* interface to tda829x driver */
unsigned int config;
int switch_addr;
- int (*tuner_callback) (void *dev, int command, int arg);
void (*agcf)(struct dvb_frontend *fe);
};
diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/common/tuners/tda8290.c
index 91204d3f282..c112bdd4e0f 100644
--- a/drivers/media/common/tuners/tda8290.c
+++ b/drivers/media/common/tuners/tda8290.c
@@ -672,10 +672,8 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
priv->i2c_props.addr = i2c_addr;
priv->i2c_props.adap = i2c_adap;
priv->i2c_props.name = "tda829x";
- if (cfg) {
+ if (cfg)
priv->cfg.config = cfg->lna_cfg;
- priv->cfg.tuner_callback = cfg->tuner_callback;
- }
if (tda8290_probe(&priv->i2c_props) == 0) {
priv->ver = TDA8290;
diff --git a/drivers/media/common/tuners/tda8290.h b/drivers/media/common/tuners/tda8290.h
index aa074f3f0c0..7e288b26fcc 100644
--- a/drivers/media/common/tuners/tda8290.h
+++ b/drivers/media/common/tuners/tda8290.h
@@ -22,7 +22,6 @@
struct tda829x_config {
unsigned int lna_cfg;
- int (*tuner_callback) (void *dev, int command, int arg);
unsigned int probe_tuner:1;
#define TDA829X_PROBE_TUNER 0
diff --git a/drivers/media/common/tuners/tda9887.c b/drivers/media/common/tuners/tda9887.c
index 72abf0b7348..ff1788cc5d4 100644
--- a/drivers/media/common/tuners/tda9887.c
+++ b/drivers/media/common/tuners/tda9887.c
@@ -686,7 +686,6 @@ struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
case 0:
mutex_unlock(&tda9887_list_mutex);
return NULL;
- break;
case 1:
fe->analog_demod_priv = priv;
priv->mode = T_STANDBY;
diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c
index aa773a658a2..fb3f3b3adab 100644
--- a/drivers/media/common/tuners/tuner-simple.c
+++ b/drivers/media/common/tuners/tuner-simple.c
@@ -142,6 +142,7 @@ static inline int tuner_stereo(const int type, const int status)
case TUNER_PHILIPS_FM1236_MK3:
case TUNER_PHILIPS_FM1256_IH3:
case TUNER_LG_NTSC_TAPE:
+ case TUNER_TCL_MF02GIP_5N:
return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
default:
return status & TUNER_STEREO;
@@ -492,8 +493,10 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
case TUNER_PHILIPS_FM1216ME_MK3:
case TUNER_PHILIPS_FM1236_MK3:
case TUNER_PHILIPS_FMD1216ME_MK3:
+ case TUNER_PHILIPS_FMD1216MEX_MK3:
case TUNER_LG_NTSC_TAPE:
case TUNER_PHILIPS_FM1256_IH3:
+ case TUNER_TCL_MF02GIP_5N:
buffer[3] = 0x19;
break;
case TUNER_TNF_5335MF:
@@ -765,6 +768,7 @@ static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
switch (priv->type) {
case TUNER_PHILIPS_FMD1216ME_MK3:
+ case TUNER_PHILIPS_FMD1216MEX_MK3:
if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
params->frequency >= 158870000)
buf[3] |= 0x08;
@@ -1038,7 +1042,6 @@ struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
case 0:
mutex_unlock(&tuner_simple_list_mutex);
return NULL;
- break;
case 1:
fe->tuner_priv = priv;
diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c
index 10dddca8b5d..7c0bc064c00 100644
--- a/drivers/media/common/tuners/tuner-types.c
+++ b/drivers/media/common/tuners/tuner-types.c
@@ -946,7 +946,7 @@ static struct tuner_params tuner_tena_9533_di_params[] = {
},
};
-/* ------------ TUNER_PHILIPS_FMD1216ME_MK3 - Philips PAL ------------ */
+/* ------------ TUNER_PHILIPS_FMD1216ME(X)_MK3 - Philips PAL ------------ */
static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = {
{ 16 * 160.00 /*MHz*/, 0x86, 0x51, },
@@ -984,6 +984,27 @@ static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = {
},
};
+static struct tuner_params tuner_philips_fmd1216mex_mk3_params[] = {
+ {
+ .type = TUNER_PARAM_TYPE_PAL,
+ .ranges = tuner_philips_fmd1216me_mk3_pal_ranges,
+ .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges),
+ .has_tda9887 = 1,
+ .port1_active = 1,
+ .port2_active = 1,
+ .port2_fm_high_sensitivity = 1,
+ .port2_invert_for_secam_lc = 1,
+ .port1_set_for_fm_mono = 1,
+ .radio_if = 1,
+ .fm_gain_normal = 1,
+ },
+ {
+ .type = TUNER_PARAM_TYPE_DIGITAL,
+ .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges,
+ .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges),
+ .iffreq = 16 * 36.125, /*MHz*/
+ },
+};
/* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */
@@ -1216,6 +1237,23 @@ static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = {
},
};
+/* ------------ TUNER_TCL_MF02GIP-5N-E - TCL MF02GIP-5N ------------ */
+
+static struct tuner_range tuner_tcl_mf02gip_5n_ntsc_ranges[] = {
+ { 16 * 172.00 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 448.00 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x04, },
+};
+
+static struct tuner_params tuner_tcl_mf02gip_5n_params[] = {
+ {
+ .type = TUNER_PARAM_TYPE_NTSC,
+ .ranges = tuner_tcl_mf02gip_5n_ntsc_ranges,
+ .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_ntsc_ranges),
+ .cb_first_if_lower_freq = 1,
+ },
+};
+
/* --------------------------------------------------------------------- */
struct tunertype tuners[] = {
@@ -1641,6 +1679,21 @@ struct tunertype tuners[] = {
.name = "Xceive 5000 tuner",
/* see xc5000.c for details */
},
+ [TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */
+ .name = "TCL tuner MF02GIP-5N-E",
+ .params = tuner_tcl_mf02gip_5n_params,
+ .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params),
+ },
+ [TUNER_PHILIPS_FMD1216MEX_MK3] = { /* Philips PAL */
+ .name = "Philips FMD1216MEX MK3 Hybrid Tuner",
+ .params = tuner_philips_fmd1216mex_mk3_params,
+ .count = ARRAY_SIZE(tuner_philips_fmd1216mex_mk3_params),
+ .min = 16 * 50.87,
+ .max = 16 * 858.00,
+ .stepsize = 166667,
+ .initdata = tua603x_agc112,
+ .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
+ },
};
EXPORT_SYMBOL(tuners);
diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c
index 4dd1d2421cc..b65e6803e6c 100644
--- a/drivers/media/common/tuners/tuner-xc2028.c
+++ b/drivers/media/common/tuners/tuner-xc2028.c
@@ -71,9 +71,6 @@ struct firmware_properties {
struct xc2028_data {
struct list_head hybrid_tuner_instance_list;
struct tuner_i2c_props i2c_props;
- int (*tuner_callback) (void *dev,
- int command, int arg);
- void *video_dev;
__u32 frequency;
struct firmware_description *firm;
@@ -492,6 +489,23 @@ ret:
return i;
}
+static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg)
+{
+ struct xc2028_data *priv = fe->tuner_priv;
+
+ /* analog side (tuner-core) uses i2c_adap->algo_data.
+ * digital side is not guaranteed to have algo_data defined.
+ *
+ * digital side will always have fe->dvb defined.
+ * analog side (tuner-core) doesn't (yet) define fe->dvb.
+ */
+
+ return (!fe->callback) ? -EINVAL :
+ fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+ fe->dvb->priv : priv->i2c_props.adap->algo_data,
+ DVB_FRONTEND_COMPONENT_TUNER, cmd, arg);
+}
+
static int load_firmware(struct dvb_frontend *fe, unsigned int type,
v4l2_std_id *id)
{
@@ -530,8 +544,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
if (!size) {
/* Special callback command received */
- rc = priv->tuner_callback(priv->video_dev,
- XC2028_TUNER_RESET, 0);
+ rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
if (rc < 0) {
tuner_err("Error at RESET code %d\n",
(*p) & 0x7f);
@@ -542,8 +555,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
if (size >= 0xff00) {
switch (size) {
case 0xff00:
- rc = priv->tuner_callback(priv->video_dev,
- XC2028_RESET_CLK, 0);
+ rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0);
if (rc < 0) {
tuner_err("Error at RESET code %d\n",
(*p) & 0x7f);
@@ -715,8 +727,7 @@ retry:
memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
/* Reset is needed before loading firmware */
- rc = priv->tuner_callback(priv->video_dev,
- XC2028_TUNER_RESET, 0);
+ rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
if (rc < 0)
goto fail;
@@ -933,7 +944,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
The reset CLK is needed only with tm6000.
Driver should work fine even if this fails.
*/
- priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
+ do_tuner_callback(fe, XC2028_RESET_CLK, 1);
msleep(10);
@@ -1002,11 +1013,6 @@ static int xc2028_set_params(struct dvb_frontend *fe,
tuner_dbg("%s called\n", __func__);
- if (priv->ctrl.d2633)
- type |= D2633;
- else
- type |= D2620;
-
switch(fe->ops.info.type) {
case FE_OFDM:
bw = p->u.ofdm.bandwidth;
@@ -1021,10 +1027,8 @@ static int xc2028_set_params(struct dvb_frontend *fe,
break;
case FE_ATSC:
bw = BANDWIDTH_6_MHZ;
- /* The only ATSC firmware (at least on v2.7) is D2633,
- so overrides ctrl->d2633 */
- type |= ATSC| D2633;
- type &= ~D2620;
+ /* The only ATSC firmware (at least on v2.7) is D2633 */
+ type |= ATSC | D2633;
break;
/* DVB-S is not supported */
default:
@@ -1057,6 +1061,28 @@ static int xc2028_set_params(struct dvb_frontend *fe,
tuner_err("error: bandwidth not supported.\n");
};
+ /*
+ Selects between D2633 or D2620 firmware.
+ It doesn't make sense for ATSC, since it should be D2633 on all cases
+ */
+ if (fe->ops.info.type != FE_ATSC) {
+ switch (priv->ctrl.type) {
+ case XC2028_D2633:
+ type |= D2633;
+ break;
+ case XC2028_D2620:
+ type |= D2620;
+ break;
+ case XC2028_AUTO:
+ default:
+ /* Zarlink seems to need D2633 */
+ if (priv->ctrl.demod == XC3028_FE_ZARLINK456)
+ type |= D2633;
+ else
+ type |= D2620;
+ }
+ }
+
/* All S-code tables need a 200kHz shift */
if (priv->ctrl.demod)
demod = priv->ctrl.demod + 200;
@@ -1177,20 +1203,10 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
break;
case 1:
/* new tuner instance */
- priv->tuner_callback = cfg->callback;
priv->ctrl.max_len = 13;
mutex_init(&priv->lock);
- /* analog side (tuner-core) uses i2c_adap->algo_data.
- * digital side is not guaranteed to have algo_data defined.
- *
- * digital side will always have fe->dvb defined.
- * analog side (tuner-core) doesn't (yet) define fe->dvb.
- */
- priv->video_dev = ((fe->dvb) && (fe->dvb->priv)) ?
- fe->dvb->priv : cfg->i2c_adap->algo_data;
-
fe->tuner_priv = priv;
break;
case 2:
diff --git a/drivers/media/common/tuners/tuner-xc2028.h b/drivers/media/common/tuners/tuner-xc2028.h
index 2c5b6282b56..19de7928a74 100644
--- a/drivers/media/common/tuners/tuner-xc2028.h
+++ b/drivers/media/common/tuners/tuner-xc2028.h
@@ -24,24 +24,28 @@
#define XC3028_FE_ZARLINK456 4560
#define XC3028_FE_CHINA 5200
+enum firmware_type {
+ XC2028_AUTO = 0, /* By default, auto-detects */
+ XC2028_D2633,
+ XC2028_D2620,
+};
+
struct xc2028_ctrl {
char *fname;
int max_len;
unsigned int scode_table;
unsigned int mts :1;
- unsigned int d2633 :1;
unsigned int input1:1;
unsigned int vhfbw7:1;
unsigned int uhfbw8:1;
unsigned int demod;
+ enum firmware_type type:2;
};
struct xc2028_config {
struct i2c_adapter *i2c_adap;
u8 i2c_addr;
- void *video_dev;
struct xc2028_ctrl *ctrl;
- int (*callback) (void *dev, int command, int arg);
};
/* xc2028 commands for callback */
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index dcddfa803a7..e12d13e0cbe 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -30,7 +30,7 @@
#include "dvb_frontend.h"
#include "xc5000.h"
-#include "xc5000_priv.h"
+#include "tuner-i2c.h"
static int debug;
module_param(debug, int, 0644);
@@ -40,12 +40,26 @@ static int xc5000_load_fw_on_attach;
module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644);
MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
-#define dprintk(level,fmt, arg...) if (debug >= level) \
+static DEFINE_MUTEX(xc5000_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
+#define dprintk(level, fmt, arg...) if (debug >= level) \
printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
#define XC5000_DEFAULT_FIRMWARE_SIZE 12332
+struct xc5000_priv {
+ struct tuner_i2c_props i2c_props;
+ struct list_head hybrid_tuner_instance_list;
+
+ u32 if_khz;
+ u32 freq_hz;
+ u32 bandwidth;
+ u8 video_standard;
+ u8 rf_mode;
+};
+
/* Misc Defines */
#define MAX_TV_STANDARD 23
#define XC_MAX_I2C_WRITE_LENGTH 64
@@ -124,11 +138,11 @@ MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
immediately the length of the following transaction.
*/
-typedef struct {
+struct XC_TV_STANDARD {
char *Name;
u16 AudioMode;
u16 VideoMode;
-} XC_TV_STANDARD;
+};
/* Tuner standards */
#define MN_NTSC_PAL_BTSC 0
@@ -155,7 +169,7 @@ typedef struct {
#define FM_Radio_INPUT2 21
#define FM_Radio_INPUT1 22
-static XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
+static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
{"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
{"M/N-NTSC/PAL-A2", 0x0600, 0x8020},
{"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020},
@@ -169,7 +183,7 @@ static XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
{"D/K-PAL-NICAM", 0x0E80, 0x8009},
{"D/K-PAL-MONO", 0x1478, 0x8009},
{"D/K-SECAM-A2 DK1", 0x1200, 0x8009},
- {"D/K-SECAM-A2 L/DK3",0x0E00, 0x8009},
+ {"D/K-SECAM-A2 L/DK3", 0x0E00, 0x8009},
{"D/K-SECAM-A2 MONO", 0x1478, 0x8009},
{"L-SECAM-NICAM", 0x8E82, 0x0009},
{"L'-SECAM-NICAM", 0x8E82, 0x4009},
@@ -216,9 +230,12 @@ static void xc5000_TunerReset(struct dvb_frontend *fe)
dprintk(1, "%s()\n", __func__);
- if (priv->cfg->tuner_callback) {
- ret = priv->cfg->tuner_callback(priv->devptr,
- XC5000_TUNER_RESET, 0);
+ if (fe->callback) {
+ ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+ fe->dvb->priv :
+ priv->i2c_props.adap->algo_data,
+ DVB_FRONTEND_COMPONENT_TUNER,
+ XC5000_TUNER_RESET, 0);
if (ret)
printk(KERN_ERR "xc5000: reset failed\n");
} else
@@ -290,9 +307,10 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
unsigned int len, pos, index;
u8 buf[XC_MAX_I2C_WRITE_LENGTH];
- index=0;
- while ((i2c_sequence[index]!=0xFF) || (i2c_sequence[index+1]!=0xFF)) {
- len = i2c_sequence[index]* 256 + i2c_sequence[index+1];
+ index = 0;
+ while ((i2c_sequence[index] != 0xFF) ||
+ (i2c_sequence[index + 1] != 0xFF)) {
+ len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
if (len == 0x0000) {
/* RESET command */
result = xc_reset(fe);
@@ -312,15 +330,17 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
buf[1] = i2c_sequence[index + 1];
pos = 2;
while (pos < len) {
- if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) {
- nbytes_to_send = XC_MAX_I2C_WRITE_LENGTH;
- } else {
+ if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2)
+ nbytes_to_send =
+ XC_MAX_I2C_WRITE_LENGTH;
+ else
nbytes_to_send = (len - pos + 2);
+ for (i = 2; i < nbytes_to_send; i++) {
+ buf[i] = i2c_sequence[index + pos +
+ i - 2];
}
- for (i=2; i<nbytes_to_send; i++) {
- buf[i] = i2c_sequence[index + pos + i - 2];
- }
- result = xc_send_i2c_data(priv, buf, nbytes_to_send);
+ result = xc_send_i2c_data(priv, buf,
+ nbytes_to_send);
if (result != XC_RESULT_SUCCESS)
return result;
@@ -369,8 +389,7 @@ static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
- if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE))
- {
+ if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) {
rf_mode = XC_RF_MODE_CABLE;
printk(KERN_ERR
"%s(), Invalid mode, defaulting to CABLE",
@@ -509,13 +528,13 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
u8 buf[2] = { reg >> 8, reg & 0xff };
u8 bval[2] = { 0, 0 };
struct i2c_msg msg[2] = {
- { .addr = priv->cfg->i2c_address,
+ { .addr = priv->i2c_props.addr,
.flags = 0, .buf = &buf[0], .len = 2 },
- { .addr = priv->cfg->i2c_address,
+ { .addr = priv->i2c_props.addr,
.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
};
- if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+ if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
printk(KERN_WARNING "xc5000: I2C read failed\n");
return -EREMOTEIO;
}
@@ -526,10 +545,10 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
{
- struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+ struct i2c_msg msg = { .addr = priv->i2c_props.addr,
.flags = 0, .buf = buf, .len = len };
- if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
(int)len);
return -EREMOTEIO;
@@ -539,17 +558,17 @@ static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
{
- struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+ struct i2c_msg msg = { .addr = priv->i2c_props.addr,
.flags = I2C_M_RD, .buf = buf, .len = len };
- if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
- printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len);
+ if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
+ printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", (int)len);
return -EREMOTEIO;
}
return 0;
}
-static int xc5000_fwupload(struct dvb_frontend* fe)
+static int xc5000_fwupload(struct dvb_frontend *fe)
{
struct xc5000_priv *priv = fe->tuner_priv;
const struct firmware *fw;
@@ -559,7 +578,8 @@ static int xc5000_fwupload(struct dvb_frontend* fe)
printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
XC5000_DEFAULT_FIRMWARE);
- ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev);
+ ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE,
+ &priv->i2c_props.adap->dev);
if (ret) {
printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
ret = XC_RESULT_RESET_FAILURE;
@@ -575,7 +595,7 @@ static int xc5000_fwupload(struct dvb_frontend* fe)
ret = XC_RESULT_RESET_FAILURE;
} else {
printk(KERN_INFO "xc5000: firmware upload\n");
- ret = xc_load_i2c_sequence(fe, fw->data );
+ ret = xc_load_i2c_sequence(fe, fw->data);
}
out:
@@ -634,7 +654,7 @@ static int xc5000_set_params(struct dvb_frontend *fe,
dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
- switch(params->u.vsb.modulation) {
+ switch (params->u.vsb.modulation) {
case VSB_8:
case VSB_16:
dprintk(1, "%s() VSB modulation\n", __func__);
@@ -675,10 +695,10 @@ static int xc5000_set_params(struct dvb_frontend *fe,
return -EREMOTEIO;
}
- ret = xc_set_IF_frequency(priv, priv->cfg->if_khz);
+ ret = xc_set_IF_frequency(priv, priv->if_khz);
if (ret != XC_RESULT_SUCCESS) {
printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
- priv->cfg->if_khz);
+ priv->if_khz);
return -EIO;
}
@@ -731,42 +751,42 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe,
/* FIX ME: Some video standards may have several possible audio
standards. We simply default to one of them here.
*/
- if(params->std & V4L2_STD_MN) {
+ if (params->std & V4L2_STD_MN) {
/* default to BTSC audio standard */
priv->video_standard = MN_NTSC_PAL_BTSC;
goto tune_channel;
}
- if(params->std & V4L2_STD_PAL_BG) {
+ if (params->std & V4L2_STD_PAL_BG) {
/* default to NICAM audio standard */
priv->video_standard = BG_PAL_NICAM;
goto tune_channel;
}
- if(params->std & V4L2_STD_PAL_I) {
+ if (params->std & V4L2_STD_PAL_I) {
/* default to NICAM audio standard */
priv->video_standard = I_PAL_NICAM;
goto tune_channel;
}
- if(params->std & V4L2_STD_PAL_DK) {
+ if (params->std & V4L2_STD_PAL_DK) {
/* default to NICAM audio standard */
priv->video_standard = DK_PAL_NICAM;
goto tune_channel;
}
- if(params->std & V4L2_STD_SECAM_DK) {
+ if (params->std & V4L2_STD_SECAM_DK) {
/* default to A2 DK1 audio standard */
priv->video_standard = DK_SECAM_A2DK1;
goto tune_channel;
}
- if(params->std & V4L2_STD_SECAM_L) {
+ if (params->std & V4L2_STD_SECAM_L) {
priv->video_standard = L_SECAM_NICAM;
goto tune_channel;
}
- if(params->std & V4L2_STD_SECAM_LC) {
+ if (params->std & V4L2_STD_SECAM_LC) {
priv->video_standard = LC_SECAM_NICAM;
goto tune_channel;
}
@@ -774,7 +794,7 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe,
tune_channel:
ret = xc_SetSignalSource(priv, priv->rf_mode);
if (ret != XC_RESULT_SUCCESS) {
- printk(KERN_ERR
+ printk(KERN_ERR
"xc5000: xc_SetSignalSource(%d) failed\n",
priv->rf_mode);
return -EREMOTEIO;
@@ -846,7 +866,7 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
* I2C transactions until calibration is complete. This way we
* don't have to rely on clock stretching working.
*/
- xc_wait( 100 );
+ xc_wait(100);
/* Default to "CABLE" mode */
ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
@@ -868,15 +888,13 @@ static int xc5000_sleep(struct dvb_frontend *fe)
*/
ret = xc_shutdown(priv);
- if(ret != XC_RESULT_SUCCESS) {
+ if (ret != XC_RESULT_SUCCESS) {
printk(KERN_ERR
"xc5000: %s() unable to shutdown tuner\n",
__func__);
return -EREMOTEIO;
- }
- else {
+ } else
return XC_RESULT_SUCCESS;
- }
}
static int xc5000_init(struct dvb_frontend *fe)
@@ -897,9 +915,19 @@ static int xc5000_init(struct dvb_frontend *fe)
static int xc5000_release(struct dvb_frontend *fe)
{
+ struct xc5000_priv *priv = fe->tuner_priv;
+
dprintk(1, "%s()\n", __func__);
- kfree(fe->tuner_priv);
+
+ mutex_lock(&xc5000_list_mutex);
+
+ if (priv)
+ hybrid_tuner_release_state(priv);
+
+ mutex_unlock(&xc5000_list_mutex);
+
fe->tuner_priv = NULL;
+
return 0;
}
@@ -924,31 +952,45 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {
struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
- struct xc5000_config *cfg, void *devptr)
+ struct xc5000_config *cfg)
{
struct xc5000_priv *priv = NULL;
+ int instance;
u16 id = 0;
- dprintk(1, "%s()\n", __func__);
+ dprintk(1, "%s(%d-%04x)\n", __func__,
+ i2c ? i2c_adapter_id(i2c) : -1,
+ cfg ? cfg->i2c_address : -1);
- priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL);
- if (priv == NULL)
- return NULL;
+ mutex_lock(&xc5000_list_mutex);
- priv->cfg = cfg;
- priv->bandwidth = BANDWIDTH_6_MHZ;
- priv->i2c = i2c;
- priv->devptr = devptr;
+ instance = hybrid_tuner_request_state(struct xc5000_priv, priv,
+ hybrid_tuner_instance_list,
+ i2c, cfg->i2c_address, "xc5000");
+ switch (instance) {
+ case 0:
+ goto fail;
+ break;
+ case 1:
+ /* new tuner instance */
+ priv->bandwidth = BANDWIDTH_6_MHZ;
+ priv->if_khz = cfg->if_khz;
+
+ fe->tuner_priv = priv;
+ break;
+ default:
+ /* existing tuner instance */
+ fe->tuner_priv = priv;
+ break;
+ }
/* Check if firmware has been loaded. It is possible that another
instance of the driver has loaded the firmware.
*/
- if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) {
- kfree(priv);
- return NULL;
- }
+ if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
+ goto fail;
- switch(id) {
+ switch (id) {
case XC_PRODUCT_ID_FW_LOADED:
printk(KERN_INFO
"xc5000: Successfully identified at address 0x%02x\n",
@@ -967,19 +1009,23 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
printk(KERN_ERR
"xc5000: Device not found at addr 0x%02x (0x%x)\n",
cfg->i2c_address, id);
- kfree(priv);
- return NULL;
+ goto fail;
}
+ mutex_unlock(&xc5000_list_mutex);
+
memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
sizeof(struct dvb_tuner_ops));
- fe->tuner_priv = priv;
-
if (xc5000_load_fw_on_attach)
xc5000_init(fe);
return fe;
+fail:
+ mutex_unlock(&xc5000_list_mutex);
+
+ xc5000_release(fe);
+ return NULL;
}
EXPORT_SYMBOL(xc5000_attach);
diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h
index 5389f740945..f4c146698a0 100644
--- a/drivers/media/common/tuners/xc5000.h
+++ b/drivers/media/common/tuners/xc5000.h
@@ -30,8 +30,6 @@ struct i2c_adapter;
struct xc5000_config {
u8 i2c_address;
u32 if_khz;
-
- int (*tuner_callback) (void *priv, int command, int arg);
};
/* xc5000 callback command */
@@ -47,19 +45,17 @@ struct xc5000_config {
#if defined(CONFIG_MEDIA_TUNER_XC5000) || \
(defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
-extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
+extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
- struct xc5000_config *cfg,
- void *devptr);
+ struct xc5000_config *cfg);
#else
-static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
+static inline struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
- struct xc5000_config *cfg,
- void *devptr)
+ struct xc5000_config *cfg)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-#endif // CONFIG_MEDIA_TUNER_XC5000
+#endif
-#endif // __XC5000_H__
+#endif
diff --git a/drivers/media/common/tuners/xc5000_priv.h b/drivers/media/common/tuners/xc5000_priv.h
deleted file mode 100644
index b2a0074c99c..00000000000
--- a/drivers/media/common/tuners/xc5000_priv.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
- *
- * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef XC5000_PRIV_H
-#define XC5000_PRIV_H
-
-struct xc5000_priv {
- struct xc5000_config *cfg;
- struct i2c_adapter *i2c;
-
- u32 freq_hz;
- u32 bandwidth;
- u8 video_standard;
- u8 rf_mode;
-
- void *devptr;
-};
-
-#endif