summaryrefslogtreecommitdiff
path: root/linux/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers')
-rw-r--r--linux/drivers/media/dvb/frontends/tda18271-fe.c152
-rw-r--r--linux/drivers/media/dvb/frontends/tda18271-priv.h5
-rw-r--r--linux/drivers/media/dvb/frontends/tda18271-tables.c4
-rw-r--r--linux/drivers/media/dvb/frontends/tda18271.h4
-rw-r--r--linux/drivers/media/video/tda8290.c9
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;