diff options
Diffstat (limited to 'drivers/media/common/tuners')
-rw-r--r-- | drivers/media/common/tuners/mt2060.c | 38 | ||||
-rw-r--r-- | drivers/media/common/tuners/mxl5005s.c | 10 | ||||
-rw-r--r-- | drivers/media/common/tuners/mxl5007t.c | 1 | ||||
-rw-r--r-- | drivers/media/common/tuners/tda18271-fe.c | 1 | ||||
-rw-r--r-- | drivers/media/common/tuners/tda827x.c | 12 | ||||
-rw-r--r-- | drivers/media/common/tuners/tda827x.h | 1 | ||||
-rw-r--r-- | drivers/media/common/tuners/tda8290.c | 4 | ||||
-rw-r--r-- | drivers/media/common/tuners/tda8290.h | 1 | ||||
-rw-r--r-- | drivers/media/common/tuners/tda9887.c | 1 | ||||
-rw-r--r-- | drivers/media/common/tuners/tuner-simple.c | 5 | ||||
-rw-r--r-- | drivers/media/common/tuners/tuner-types.c | 55 | ||||
-rw-r--r-- | drivers/media/common/tuners/tuner-xc2028.c | 74 | ||||
-rw-r--r-- | drivers/media/common/tuners/tuner-xc2028.h | 10 | ||||
-rw-r--r-- | drivers/media/common/tuners/xc5000.c | 180 | ||||
-rw-r--r-- | drivers/media/common/tuners/xc5000.h | 16 | ||||
-rw-r--r-- | drivers/media/common/tuners/xc5000_priv.h | 37 |
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 |