diff options
author | Michael Krufky <mkrufky@linuxtv.org> | 2008-01-27 18:59:09 -0500 |
---|---|---|
committer | Michael Krufky <mkrufky@linuxtv.org> | 2008-01-27 18:59:09 -0500 |
commit | d7a21fddc3715e75592fc3bbca4b9f41d5d6c3df (patch) | |
tree | 3e654426b410fcc76777f4ab7d91e6cd0b14ab5f | |
parent | fafbcd8e6db5d009c92e1ae5b117301ab2c1f03c (diff) | |
download | mediapointer-dvb-s2-d7a21fddc3715e75592fc3bbca4b9f41d5d6c3df.tar.gz mediapointer-dvb-s2-d7a21fddc3715e75592fc3bbca4b9f41d5d6c3df.tar.bz2 |
tuner-simple: add basic support for digital tuning of hybrid devices
From: Michael Krufky <mkrufky@linuxtv.org>
Add entry points used for digital tuning via the dvb_frontend.
Share state data between multiple instances of the driver for hybrid
tuners.
Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
-rw-r--r-- | linux/drivers/media/video/tuner-simple.c | 164 | ||||
-rw-r--r-- | linux/include/media/tuner-types.h | 29 |
2 files changed, 165 insertions, 28 deletions
diff --git a/linux/drivers/media/video/tuner-simple.c b/linux/drivers/media/video/tuner-simple.c index 496424fc4..5c82e73c6 100644 --- a/linux/drivers/media/video/tuner-simple.c +++ b/linux/drivers/media/video/tuner-simple.c @@ -96,14 +96,20 @@ MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner"); #define TUNER_PLL_LOCKED 0x40 #define TUNER_STEREO_MK3 0x04 +static DEFINE_MUTEX(tuner_simple_list_mutex); +static LIST_HEAD(hybrid_tuner_instance_list); + struct tuner_simple_priv { u16 last_div; + struct tuner_i2c_props i2c_props; + struct list_head hybrid_tuner_instance_list; unsigned int type; struct tunertype *tun; u32 frequency; + u32 bandwidth; }; /* ---------------------------------------------------------------------- */ @@ -202,6 +208,9 @@ static inline char *tuner_param_name(enum param_type type) case TUNER_PARAM_TYPE_NTSC: name = "ntsc"; break; + case TUNER_PARAM_TYPE_DIGITAL: + name = "digital"; + break; default: name = "unknown"; break; @@ -714,14 +723,118 @@ static int simple_set_params(struct dvb_frontend *fe, priv->frequency = params->frequency * 62500; break; } + priv->bandwidth = 0; return ret; } +static int simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + struct tunertype *tun = priv->tun; + static struct tuner_params *t_params; + u8 config, cb; + u32 div; + int ret, frequency = params->frequency / 62500; + + t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL); + ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb); + if (ret < 0) + return ret; + + div = ((frequency + t_params->iffreq) * 62500 + offset + + tun->stepsize/2) / tun->stepsize; + + buf[0] = div >> 8; + buf[1] = div & 0xff; + buf[2] = config; + buf[3] = cb; + + tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", + tun->name, div, buf[0], buf[1], buf[2], buf[3]); + + /* calculate the frequency we set it to */ + return (div * tun->stepsize) - t_params->iffreq; +} + +static int simple_dvb_calc_regs(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params, + u8 *buf, int buf_len) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int ret; + u32 frequency; + + if (buf_len < 5) + return -EINVAL; + + ret = simple_dvb_configure(fe, buf+1, params); + if (ret < 0) + return ret; + else + frequency = ret; + + buf[0] = priv->i2c_props.addr; + + priv->frequency = frequency; + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? + params->u.ofdm.bandwidth : 0; + + return 5; +} + +static int simple_dvb_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + u32 prev_freq, prev_bw; + int ret; + u8 buf[5]; + + if (priv->i2c_props.adap == NULL) + return -EINVAL; + + prev_freq = priv->frequency; + prev_bw = priv->bandwidth; + + ret = simple_dvb_calc_regs(fe, params, buf, 5); + if (ret != 5) + goto fail; + + /* put analog demod in standby when tuning digital */ + if (fe->ops.analog_ops.standby) + fe->ops.analog_ops.standby(fe); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + /* buf[0] contains the i2c address, but * + * we already have it in i2c_props.addr */ + ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4); + if (ret != 4) + goto fail; + + return 0; +fail: + /* calc_regs sets frequency and bandwidth. if we failed, unset them */ + priv->frequency = prev_freq; + priv->bandwidth = prev_bw; + + return ret; +} static int simple_release(struct dvb_frontend *fe) { - kfree(fe->tuner_priv); + struct tuner_simple_priv *priv = fe->tuner_priv; + + mutex_lock(&tuner_simple_list_mutex); + + if (priv) + hybrid_tuner_release_state(priv); + + mutex_unlock(&tuner_simple_list_mutex); + fe->tuner_priv = NULL; return 0; @@ -734,6 +847,13 @@ static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } +static int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + static struct dvb_tuner_ops simple_tuner_ops = { #if 0 .info = { @@ -744,8 +864,11 @@ static struct dvb_tuner_ops simple_tuner_ops = { }, #endif .set_analog_params = simple_set_params, + .set_params = simple_dvb_set_params, + .calc_regs = simple_dvb_calc_regs, .release = simple_release, .get_frequency = simple_get_frequency, + .get_bandwidth = simple_get_bandwidth, .get_status = simple_get_status, .get_rf_strength = simple_get_rf_strength, }; @@ -756,6 +879,7 @@ struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, unsigned int type) { struct tuner_simple_priv *priv = NULL; + int instance; if (type >= tuner_count) { printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n", @@ -763,22 +887,42 @@ struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, return NULL; } - priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL); - if (priv == NULL) + mutex_lock(&tuner_simple_list_mutex); + + instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv, + hybrid_tuner_instance_list, + i2c_adap, i2c_addr, + "tuner-simple"); + switch (instance) { + case 0: + mutex_unlock(&tuner_simple_list_mutex); return NULL; - fe->tuner_priv = priv; + break; + case 1: + fe->tuner_priv = priv; - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; - priv->i2c_props.name = "tuner-simple"; + priv->type = type; + priv->tun = &tuners[type]; + break; + default: + fe->tuner_priv = priv; +#if 0 + /* caller didn't pass in a configuration last time + * use current configuration, instead */ + if (!priv->tun) { + priv->type = type; + priv->tun = &tuners[type]; + } +#endif + break; + } - priv->type = type; - priv->tun = &tuners[type]; + mutex_unlock(&tuner_simple_list_mutex); memcpy(&fe->ops.tuner_ops, &simple_tuner_ops, sizeof(struct dvb_tuner_ops)); - tuner_info("type set to %d (%s)\n", priv->type, priv->tun->name); + tuner_info("type set to %d (%s)\n", type, priv->tun->name); strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name, sizeof(fe->ops.tuner_ops.info.name)); diff --git a/linux/include/media/tuner-types.h b/linux/include/media/tuner-types.h index 9c88381cc..e0d817786 100644 --- a/linux/include/media/tuner-types.h +++ b/linux/include/media/tuner-types.h @@ -6,17 +6,11 @@ #define __TUNER_TYPES_H__ enum param_type { - TUNER_PARAM_TYPE_RADIO, \ - TUNER_PARAM_TYPE_PAL, \ - TUNER_PARAM_TYPE_SECAM, \ - TUNER_PARAM_TYPE_NTSC -#if 0 /* to be added when we merge dvb-pll */ - TUNER_PARAM_TYPE_ATSC, \ - TUNER_PARAM_TYPE_DVBT, \ - TUNER_PARAM_TYPE_DVBS, \ - TUNER_PARAM_TYPE_DVBC, \ - TUNER_PARAM_TYPE_DVBS2 -#endif + TUNER_PARAM_TYPE_RADIO, + TUNER_PARAM_TYPE_PAL, + TUNER_PARAM_TYPE_SECAM, + TUNER_PARAM_TYPE_NTSC, + TUNER_PARAM_TYPE_DIGITAL, }; struct tuner_range { @@ -112,13 +106,8 @@ struct tuner_params { the SECAM-L/L' standards. Range: -16:+15 */ signed int default_top_secam_high:5; -#if 0 /* to be used when we merge dvb-pll */ - u32 min; - u32 max; - - u32 offset - u32 stepsize - + u16 iffreq; +#if 0 void (*setbw)(u8 *buf, u32 freq, int bandwidth); #endif @@ -130,6 +119,10 @@ struct tunertype { char *name; unsigned int count; struct tuner_params *params; + + u16 min; + u16 max; + u16 stepsize; }; extern struct tunertype tuners[]; |