diff options
Diffstat (limited to 'linux')
-rw-r--r-- | linux/drivers/media/dvb/frontends/tda18271-fe.c | 152 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/tda18271-priv.h | 5 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/tda18271-tables.c | 4 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/tda18271.h | 4 | ||||
-rw-r--r-- | linux/drivers/media/video/tda8290.c | 9 |
5 files changed, 114 insertions, 60 deletions
diff --git a/linux/drivers/media/dvb/frontends/tda18271-fe.c b/linux/drivers/media/dvb/frontends/tda18271-fe.c index 26352716a..f9fd3889d 100644 --- a/linux/drivers/media/dvb/frontends/tda18271-fe.c +++ b/linux/drivers/media/dvb/frontends/tda18271-fe.c @@ -26,7 +26,10 @@ int tda18271_debug; module_param_named(debug, tda18271_debug, int, 0644); MODULE_PARM_DESC(debug, "set debug level " - "(info=1, map=2, reg=4, adv=8 (or-able))"); + "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))"); + +static LIST_HEAD(tda18271_list); +static DEFINE_MUTEX(tda18271_list_mutex); /*---------------------------------------------------------------------*/ @@ -47,7 +50,8 @@ static int tda18271_ir_cal_init(struct dvb_frontend *fe) /* ------------------------------------------------------------------ */ static int tda18271_channel_configuration(struct dvb_frontend *fe, - u32 ifc, u32 freq, u32 bw, u8 std) + u32 ifc, u32 freq, u32 bw, u8 std, + int radio) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; @@ -74,7 +78,11 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe, regs[R_MPD] |= 0x80; /* IF notch = 1 */ break; } - regs[R_EP4] &= ~0x80; /* FM_RFn: turn this bit on only for fm radio */ + + if (radio) + regs[R_EP4] |= 0x80; + else + regs[R_EP4] &= ~0x80; /* update RF_TOP / IF_TOP */ switch (priv->mode) { @@ -475,7 +483,7 @@ static int tda18271_powerscan(struct dvb_frontend *fe, } else bcal = 0; - tda_dbg("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n", + tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n", bcal, *freq_in, *freq_out, freq); return bcal; @@ -538,7 +546,7 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) for (rf = RF1; rf <= RF3; rf++) { if (0 == rf_default[rf]) return 0; - tda_dbg("freq = %d, rf = %d\n", freq, rf); + tda_cal("freq = %d, rf = %d\n", freq, rf); /* look for optimized calibration frequency */ bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]); @@ -636,7 +644,7 @@ static int tda18271_init(struct dvb_frontend *fe) } static int tda18271c2_tune(struct dvb_frontend *fe, - u32 ifc, u32 freq, u32 bw, u8 std) + u32 ifc, u32 freq, u32 bw, u8 std, int radio) { struct tda18271_priv *priv = fe->tuner_priv; @@ -648,7 +656,7 @@ static int tda18271c2_tune(struct dvb_frontend *fe, tda18271_rf_tracking_filters_correction(fe, freq); - tda18271_channel_configuration(fe, ifc, freq, bw, std); + tda18271_channel_configuration(fe, ifc, freq, bw, std, radio); mutex_unlock(&priv->lock); @@ -658,7 +666,7 @@ static int tda18271c2_tune(struct dvb_frontend *fe, /* ------------------------------------------------------------------ */ static int tda18271c1_tune(struct dvb_frontend *fe, - u32 ifc, u32 freq, u32 bw, u8 std) + u32 ifc, u32 freq, u32 bw, u8 std, int radio) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; @@ -667,11 +675,6 @@ static int tda18271c1_tune(struct dvb_frontend *fe, tda18271_init(fe); mutex_lock(&priv->lock); -#if 0 - /* FIXME: FM Radio support */ - if (t->mode == V4L2_TUNER_RADIO) - freq = freq / 1000; -#endif tda_dbg("freq = %d, ifc = %d\n", freq, ifc); @@ -795,7 +798,10 @@ static int tda18271c1_tune(struct dvb_frontend *fe, break; } - regs[R_EP4] &= ~0x80; /* turn this bit on only for fm */ + if (radio) + regs[R_EP4] |= 0x80; + else + regs[R_EP4] &= ~0x80; /* image rejection validity */ tda18271_calc_ir_measure(fe, &freq); @@ -813,17 +819,17 @@ static int tda18271c1_tune(struct dvb_frontend *fe, } static inline int tda18271_tune(struct dvb_frontend *fe, - u32 ifc, u32 freq, u32 bw, u8 std) + u32 ifc, u32 freq, u32 bw, u8 std, int radio) { struct tda18271_priv *priv = fe->tuner_priv; int ret = -EINVAL; switch (priv->id) { case TDA18271HDC1: - ret = tda18271c1_tune(fe, ifc, freq, bw, std); + ret = tda18271c1_tune(fe, ifc, freq, bw, std, radio); break; case TDA18271HDC2: - ret = tda18271c2_tune(fe, ifc, freq, bw, std); + ret = tda18271c2_tune(fe, ifc, freq, bw, std, radio); break; } return ret; @@ -891,7 +897,7 @@ static int tda18271_set_params(struct dvb_frontend *fe, return -EINVAL; } - ret = tda18271_tune(fe, sgIF * 1000, freq, bw, std); + ret = tda18271_tune(fe, sgIF * 1000, freq, bw, std, 0); if (ret < 0) goto fail; @@ -909,14 +915,20 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe, struct tda18271_priv *priv = fe->tuner_priv; struct tda18271_std_map *std_map = &priv->std; char *mode; - int ret; + int ret, radio = 0; u8 std; u16 sgIF; u32 freq = params->frequency * 62500; priv->mode = TDA18271_ANALOG; - if (params->std & V4L2_STD_MN) { + if (params->mode == V4L2_TUNER_RADIO) { + radio = 1; + freq = freq / 1000; + std = std_map->fm_radio.std_bits; + sgIF = std_map->fm_radio.if_freq; + mode = "fm"; + } else if (params->std & V4L2_STD_MN) { std = std_map->atv_mn.std_bits; sgIF = std_map->atv_mn.if_freq; mode = "MN"; @@ -950,13 +962,9 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe, mode = "xx"; } -#if 0 - if (params->mode == V4L2_TUNER_RADIO) - sgIF = std_map->fm_radio.if_freq; -#endif tda_dbg("setting tda18271 to system %s\n", mode); - ret = tda18271_tune(fe, sgIF * 1000, freq, 0, std); + ret = tda18271_tune(fe, sgIF * 1000, freq, 0, std, radio); if (ret < 0) goto fail; @@ -969,8 +977,24 @@ fail: static int tda18271_release(struct dvb_frontend *fe) { - kfree(fe->tuner_priv); + struct tda18271_priv *priv = fe->tuner_priv; + + mutex_lock(&tda18271_list_mutex); + + priv->count--; + + if (!priv->count) { + tda_dbg("destroying instance @ %d-%04x\n", + i2c_adapter_id(priv->i2c_adap), + priv->i2c_addr); + list_del(&priv->tda18271_list); + + kfree(priv); + } + mutex_unlock(&tda18271_list_mutex); + fe->tuner_priv = NULL; + return 0; } @@ -1008,9 +1032,7 @@ static int tda18271_dump_std_map(struct dvb_frontend *fe) struct tda18271_std_map *std = &priv->std; tda_dbg("========== STANDARD MAP SETTINGS ==========\n"); -#if 0 tda18271_dump_std_item(fm_radio, "fm"); -#endif tda18271_dump_std_item(atv_b, "pal b"); tda18271_dump_std_item(atv_dk, "pal dk"); tda18271_dump_std_item(atv_gh, "pal gh"); @@ -1037,9 +1059,7 @@ static int tda18271_update_std_map(struct dvb_frontend *fe, if (!map) return -EINVAL; -#if 0 tda18271_update_std(fm_radio, "fm"); -#endif tda18271_update_std(atv_b, "atv b"); tda18271_update_std(atv_dk, "atv dk"); tda18271_update_std(atv_gh, "atv gh"); @@ -1110,43 +1130,73 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, struct tda18271_config *cfg) { struct tda18271_priv *priv = NULL; + int state_found = 0; + + mutex_lock(&tda18271_list_mutex); + + list_for_each_entry(priv, &tda18271_list, tda18271_list) { + if ((i2c_adapter_id(priv->i2c_adap) == i2c_adapter_id(i2c)) && + (priv->i2c_addr == addr)) { + tda_dbg("attaching existing tuner @ %d-%04x\n", + i2c_adapter_id(priv->i2c_adap), + priv->i2c_addr); + priv->count++; + fe->tuner_priv = priv; + state_found = 1; + /* allow dvb driver to override i2c gate setting */ + if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG)) + priv->gate = cfg->gate; + break; + } + } + if (state_found == 0) { + tda_dbg("creating new tuner instance @ %d-%04x\n", + i2c_adapter_id(i2c), addr); + + priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL); + if (priv == NULL) { + mutex_unlock(&tda18271_list_mutex); + return NULL; + } - priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; + priv->i2c_addr = addr; + priv->i2c_adap = i2c; + priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO; + priv->cal_initialized = false; + mutex_init(&priv->lock); + priv->count++; - priv->i2c_addr = addr; - priv->i2c_adap = i2c; - priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO; - priv->cal_initialized = false; - mutex_init(&priv->lock); + fe->tuner_priv = priv; - fe->tuner_priv = priv; + list_add_tail(&priv->tda18271_list, &tda18271_list); - if (tda18271_get_id(fe) < 0) - goto fail; + if (tda18271_get_id(fe) < 0) + goto fail; - if (tda18271_assign_map_layout(fe) < 0) - goto fail; + if (tda18271_assign_map_layout(fe) < 0) + goto fail; - memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, - sizeof(struct dvb_tuner_ops)); + mutex_lock(&priv->lock); + tda18271_init_regs(fe); + mutex_unlock(&priv->lock); + } /* override default std map with values in config struct */ if ((cfg) && (cfg->std_map)) tda18271_update_std_map(fe, cfg->std_map); - if (tda18271_debug & DBG_MAP) - tda18271_dump_std_map(fe); + mutex_unlock(&tda18271_list_mutex); - mutex_lock(&priv->lock); - - tda18271_init_regs(fe); + memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, + sizeof(struct dvb_tuner_ops)); - mutex_unlock(&priv->lock); + if (tda18271_debug & DBG_MAP) + tda18271_dump_std_map(fe); return fe; fail: + mutex_unlock(&tda18271_list_mutex); + tda18271_release(fe); return NULL; } diff --git a/linux/drivers/media/dvb/frontends/tda18271-priv.h b/linux/drivers/media/dvb/frontends/tda18271-priv.h index 5eaa0462b..877509346 100644 --- a/linux/drivers/media/dvb/frontends/tda18271-priv.h +++ b/linux/drivers/media/dvb/frontends/tda18271-priv.h @@ -107,10 +107,13 @@ struct tda18271_priv { struct i2c_adapter *i2c_adap; unsigned char tda18271_regs[TDA18271_NUM_REGS]; + struct list_head tda18271_list; + enum tda18271_mode mode; enum tda18271_i2c_gate gate; enum tda18271_ver id; + unsigned int count; unsigned int tm_rfcal; unsigned int cal_initialized:1; @@ -136,6 +139,7 @@ extern int tda18271_debug; #define DBG_MAP 2 #define DBG_REG 4 #define DBG_ADV 8 +#define DBG_CAL 16 #define tda_printk(kern, fmt, arg...) \ printk(kern "%s: " fmt, __FUNCTION__, ##arg) @@ -150,6 +154,7 @@ extern int tda18271_debug; #define tda_dbg(fmt, arg...) dprintk(KERN_DEBUG, DBG_INFO, fmt, ##arg) #define tda_map(fmt, arg...) dprintk(KERN_DEBUG, DBG_MAP, fmt, ##arg) #define tda_reg(fmt, arg...) dprintk(KERN_DEBUG, DBG_REG, fmt, ##arg) +#define tda_cal(fmt, arg...) dprintk(KERN_DEBUG, DBG_CAL, fmt, ##arg) /*---------------------------------------------------------------------*/ diff --git a/linux/drivers/media/dvb/frontends/tda18271-tables.c b/linux/drivers/media/dvb/frontends/tda18271-tables.c index a39725f7b..e94afcfdc 100644 --- a/linux/drivers/media/dvb/frontends/tda18271-tables.c +++ b/linux/drivers/media/dvb/frontends/tda18271-tables.c @@ -1187,9 +1187,7 @@ fail: /*---------------------------------------------------------------------*/ static struct tda18271_std_map tda18271c1_std_map = { -#if 0 .fm_radio = { .if_freq = 1250, .std_bits = 0x18 }, -#endif .atv_b = { .if_freq = 6750, .std_bits = 0x0e }, .atv_dk = { .if_freq = 7750, .std_bits = 0x0f }, .atv_gh = { .if_freq = 7750, .std_bits = 0x0f }, @@ -1206,9 +1204,7 @@ static struct tda18271_std_map tda18271c1_std_map = { }; static struct tda18271_std_map tda18271c2_std_map = { -#if 0 .fm_radio = { .if_freq = 1250, .std_bits = 0x18 }, -#endif .atv_b = { .if_freq = 6000, .std_bits = 0x0d }, .atv_dk = { .if_freq = 6900, .std_bits = 0x0e }, .atv_gh = { .if_freq = 7100, .std_bits = 0x0e }, diff --git a/linux/drivers/media/dvb/frontends/tda18271.h b/linux/drivers/media/dvb/frontends/tda18271.h index 51bb344c7..24b0e35a2 100644 --- a/linux/drivers/media/dvb/frontends/tda18271.h +++ b/linux/drivers/media/dvb/frontends/tda18271.h @@ -30,9 +30,7 @@ struct tda18271_std_map_item { }; struct tda18271_std_map { -#if 0 - tda18271_std_map_item fm_radio; -#endif + struct tda18271_std_map_item fm_radio; struct tda18271_std_map_item atv_b; struct tda18271_std_map_item atv_dk; struct tda18271_std_map_item atv_gh; diff --git a/linux/drivers/media/video/tda8290.c b/linux/drivers/media/video/tda8290.c index fb95df7d3..31bd84600 100644 --- a/linux/drivers/media/video/tda8290.c +++ b/linux/drivers/media/video/tda8290.c @@ -528,8 +528,13 @@ static void tda8290_init_tuner(struct dvb_frontend *fe) static void tda829x_release(struct dvb_frontend *fe) { - if (fe->ops.tuner_ops.release) - fe->ops.tuner_ops.release(fe); + struct tda8290_priv *priv = fe->analog_demod_priv; + + /* only try to release the tuner if we've + * attached it from within this module */ + if (priv->ver & (TDA18271 | TDA8275 | TDA8275A)) + if (fe->ops.tuner_ops.release) + fe->ops.tuner_ops.release(fe); kfree(fe->analog_demod_priv); fe->analog_demod_priv = NULL; |