Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8c125f2c authored by Michael Krufky's avatar Michael Krufky Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (6468): tda8290: auto-detect tda8290 or tda8295



Consolidate tda8290_attach() and tda8295_attach() into a single function,
tda829x_attach(), which will detect chip combinations tda8290 or tda8295 with
tda8275, tda8275a or tda18271.

Signed-off-by: default avatarMichael Krufky <mkrufky@linuxtv.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 393bf557
Loading
Loading
Loading
Loading
+124 −133
Original line number Diff line number Diff line
@@ -41,7 +41,13 @@ struct tda8290_priv {
	unsigned char tda8290_easy_mode;

	unsigned char tda827x_addr;
	unsigned char tda827x_ver;

	unsigned char ver;
#define TDA8290   1
#define TDA8295   2
#define TDA8275   4
#define TDA8275A  8
#define TDA18271 16

	struct tda827x_config cfg;

@@ -136,7 +142,7 @@ static void set_audio(struct dvb_frontend *fe)
		mode = "xx";
	}

	tuner_dbg("setting tda8290 to system %s\n", mode);
	tuner_dbg("setting tda829x to system %s\n", mode);
}

static void tda8290_set_freq(struct dvb_frontend *fe, unsigned int freq)
@@ -429,7 +435,7 @@ static void tda8290_standby(struct dvb_frontend *fe)
	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2};

	tda8290_i2c_bridge(fe, 1);
	if (priv->tda827x_ver != 0)
	if (priv->ver & TDA8275A)
		cb1[1] = 0x90;
	i2c_transfer(priv->i2c_props.adap, &msg, 1);
	tda8290_i2c_bridge(fe, 0);
@@ -498,7 +504,7 @@ static void tda8290_init_tuner(struct dvb_frontend *fe)
					  0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0,
			      .buf=tda8275_init, .len = 14};
	if (priv->tda827x_ver != 0)
	if (priv->ver & TDA8275A)
		msg.buf = tda8275a_init;

	tda8290_i2c_bridge(fe, 1);
@@ -517,44 +523,21 @@ static void tda829x_release(struct dvb_frontend *fe)
	fe->analog_demod_priv = NULL;
}

static struct analog_tuner_ops tda8290_tuner_ops = {
	.set_tv_freq    = tda8290_set_freq,
	.set_radio_freq = tda8290_set_freq,
	.has_signal     = tda8290_has_signal,
	.standby        = tda8290_standby,
	.release        = tda829x_release,
	.i2c_gate_ctrl  = tda8290_i2c_bridge,
};

static struct analog_tuner_ops tda8295_tuner_ops = {
	.set_tv_freq    = tda8295_set_freq,
	.set_radio_freq = tda8295_set_freq,
	.has_signal     = tda8295_has_signal,
	.standby        = tda8295_standby,
	.release        = tda829x_release,
	.i2c_gate_ctrl  = tda8295_i2c_bridge,
};

int tda8290_attach(struct tuner *t)
static int tda829x_find_tuner(struct dvb_frontend *fe)
{
	struct tda8290_priv *priv = NULL;
	u8 data;
	struct tda8290_priv *priv = fe->analog_demod_priv;
	struct analog_tuner_ops *ops = fe->ops.analog_demod_ops;
	struct tuner *t = priv->t;
	int i, ret, tuners_found;
	u32 tuner_addrs;
	u8 data;
	struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 };

	priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
	if (priv == NULL)
		return -ENOMEM;
	t->fe.analog_demod_priv = priv;
	if (NULL == ops)
		return -EINVAL;

	priv->i2c_props.addr     = t->i2c.addr;
	priv->i2c_props.adap     = t->i2c.adapter;
	priv->cfg.config         = &t->config;
	priv->cfg.tuner_callback = t->tuner_callback;
	priv->t = t;
	ops->i2c_gate_ctrl(fe, 1);

	tda8290_i2c_bridge(&t->fe, 1);
	/* probe for tuner chip */
	tuners_found = 0;
	tuner_addrs = 0;
@@ -570,7 +553,9 @@ int tda8290_attach(struct tuner *t)
	   behind the bridge and we choose the highest address that doesn't
	   give a response now
	 */
	tda8290_i2c_bridge(&t->fe, 0);

	ops->i2c_gate_ctrl(fe, 0);

	if (tuners_found > 1)
		for (i = 0; i < tuners_found; i++) {
			msg.addr = tuner_addrs  & 0xff;
@@ -580,10 +565,11 @@ int tda8290_attach(struct tuner *t)
			else
				break;
		}

	if (tuner_addrs == 0) {
		tuner_addrs = 0x61;
		tuner_info("could not clearly identify tuner address, defaulting to %x\n",
			     tuner_addrs);
		tuner_addrs = 0x60;
		tuner_info("could not clearly identify tuner address, "
			   "defaulting to %x\n", tuner_addrs);
	} else {
		tuner_addrs = tuner_addrs & 0xff;
		tuner_info("setting tuner address to %x\n", tuner_addrs);
@@ -591,19 +577,24 @@ int tda8290_attach(struct tuner *t)
	priv->tda827x_addr = tuner_addrs;
	msg.addr = tuner_addrs;

	tda8290_i2c_bridge(&t->fe, 1);

	ops->i2c_gate_ctrl(fe, 1);
	ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
	if( ret != 1)
		tuner_warn("TDA827x access failed!\n");

	if ((data & 0x3c) == 0) {
		strlcpy(t->i2c.name, "tda8290+75", sizeof(t->i2c.name));
		priv->tda827x_ver = 0;
	} else {
		strlcpy(t->i2c.name, "tda8290+75a", sizeof(t->i2c.name));
		priv->tda827x_ver = 2;
	if (ret != 1) {
		tuner_warn("tuner access failed!\n");
		return -EREMOTEIO;
	}

	if (data == 0x83) {
		priv->ver |= TDA18271;
		tda18271_attach(&t->fe, priv->tda827x_addr,
				priv->i2c_props.adap);
	} else {
		if ((data & 0x3c) == 0)
			priv->ver |= TDA8275;
		else
			priv->ver |= TDA8275A;

		tda827x_attach(&t->fe, priv->tda827x_addr,
			       priv->i2c_props.adap, &priv->cfg);

@@ -612,106 +603,106 @@ int tda8290_attach(struct tuner *t)
		 */
		if (t->fe.ops.tuner_ops.sleep)
			t->fe.ops.tuner_ops.sleep(&t->fe);
	}
	ops->i2c_gate_ctrl(fe, 0);

	t->fe.ops.analog_demod_ops = &tda8290_tuner_ops;

	tuner_info("type set to %s\n", t->i2c.name);

	t->mode = V4L2_TUNER_ANALOG_TV;
	switch (priv->ver) {
	case TDA8290 | TDA8275:
		strlcpy(t->i2c.name, "tda8290+75", sizeof(t->i2c.name));
		break;
	case TDA8295 | TDA8275:
		strlcpy(t->i2c.name, "tda8295+75", sizeof(t->i2c.name));
		break;
	case TDA8290 | TDA8275A:
		strlcpy(t->i2c.name, "tda8290+75a", sizeof(t->i2c.name));
		break;
	case TDA8295 | TDA8275A:
		strlcpy(t->i2c.name, "tda8295+75a", sizeof(t->i2c.name));
		break;
	case TDA8290 | TDA18271:
		strlcpy(t->i2c.name, "tda8290+18271", sizeof(t->i2c.name));
		break;
	case TDA8295 | TDA18271:
		strlcpy(t->i2c.name, "tda8295+18271", sizeof(t->i2c.name));
		break;
	default:
		return -EINVAL;
	}

	tda8290_init_tuner(&t->fe);
	tda8290_init_if(&t->fe);
	return 0;
}
EXPORT_SYMBOL_GPL(tda8290_attach);

int tda8295_attach(struct tuner *t)
static struct analog_tuner_ops tda8290_tuner_ops = {
	.set_tv_freq    = tda8290_set_freq,
	.set_radio_freq = tda8290_set_freq,
	.has_signal     = tda8290_has_signal,
	.standby        = tda8290_standby,
	.release        = tda829x_release,
	.i2c_gate_ctrl  = tda8290_i2c_bridge,
};

static struct analog_tuner_ops tda8295_tuner_ops = {
	.set_tv_freq    = tda8295_set_freq,
	.set_radio_freq = tda8295_set_freq,
	.has_signal     = tda8295_has_signal,
	.standby        = tda8295_standby,
	.release        = tda829x_release,
	.i2c_gate_ctrl  = tda8295_i2c_bridge,
};

int tda829x_attach(struct tuner *t)
{
	struct dvb_frontend *fe = &t->fe;
	struct tda8290_priv *priv = NULL;
	u8 data;
	int i, ret, tuners_found;
	u32 tuner_addrs;
	struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 };

	unsigned char tda8290_id[] = { 0x1f, 0x00 };
#define TDA8290_ID 0x89
	unsigned char tda8295_id[] = { 0x2f, 0x00 };
#define TDA8295_ID 0x8a

	priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
	if (priv == NULL)
		return -ENOMEM;
	t->fe.analog_demod_priv = priv;
	fe->analog_demod_priv = priv;

	priv->i2c_props.addr     = t->i2c.addr;
	priv->i2c_props.adap     = t->i2c.adapter;
	priv->cfg.config         = &t->config;
	priv->cfg.tuner_callback = t->tuner_callback;
	priv->t = t;

	tda8295_i2c_bridge(&t->fe, 1);
	/* probe for tuner chip */
	tuners_found = 0;
	tuner_addrs = 0;
	for (i = 0x60; i <= 0x63; i++) {
		msg.addr = i;
		ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
		if (ret == 1) {
			tuners_found++;
			tuner_addrs = (tuner_addrs << 8) + i;
	/* detect tda8290 */
	tuner_i2c_xfer_send(&priv->i2c_props, &tda8290_id[0], 1);
	tuner_i2c_xfer_recv(&priv->i2c_props, &tda8290_id[1], 1);
	if (tda8290_id[1] == TDA8290_ID) {
		priv->ver = TDA8290;
		fe->ops.analog_demod_ops = &tda8290_tuner_ops;
	}

	/* detect tda8295 */
	tuner_i2c_xfer_send(&priv->i2c_props, &tda8295_id[0], 1);
	tuner_i2c_xfer_recv(&priv->i2c_props, &tda8295_id[1], 1);
	if (tda8295_id[1] == TDA8295_ID) {
		priv->ver = TDA8295;
		fe->ops.analog_demod_ops = &tda8295_tuner_ops;
	}
	/* if there is more than one tuner, we expect the right one is
	   behind the bridge and we choose the highest address that doesn't
	   give a response now
	 */
	tda8295_i2c_bridge(&t->fe, 0);
	if (tuners_found > 1)
		for (i = 0; i < tuners_found; i++) {
			msg.addr = tuner_addrs  & 0xff;
			ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
			if (ret == 1)
				tuner_addrs = tuner_addrs >> 8;
			else
				break;
		}
	if (tuner_addrs == 0) {
		tuner_addrs = 0x60;
		tuner_info("could not clearly identify tuner address, "
			   "defaulting to %x\n", tuner_addrs);
	} else {
		tuner_addrs = tuner_addrs & 0xff;
		tuner_info("setting tuner address to %x\n", tuner_addrs);
	}
	priv->tda827x_addr = tuner_addrs;
	msg.addr = tuner_addrs;

	tda8295_i2c_bridge(&t->fe, 1);
	ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
	tda8295_i2c_bridge(&t->fe, 0);
	if (ret != 1)
		tuner_warn("TDA827x access failed!\n");
	if ((data & 0x3c) == 0) {
		strlcpy(t->i2c.name, "tda8295+18271", sizeof(t->i2c.name));
		tda18271_attach(&t->fe, priv->tda827x_addr,
				priv->i2c_props.adap);
		priv->tda827x_ver = 4;
	} else {
		strlcpy(t->i2c.name, "tda8295+75a", sizeof(t->i2c.name));
		tda827x_attach(&t->fe, priv->tda827x_addr,
			       priv->i2c_props.adap, &priv->cfg);
	if (tda829x_find_tuner(fe) < 0)
		return -EINVAL;

		/* FIXME: tda827x module doesn't probe the tuner until
		 * tda827x_initial_sleep is called
		 */
		if (t->fe.ops.tuner_ops.sleep)
			t->fe.ops.tuner_ops.sleep(&t->fe);
		priv->tda827x_ver = 2;
	}
	priv->tda827x_ver |= 1; /* signifies 8295 vs 8290 */
	tuner_info("type set to %s\n", t->i2c.name);
	if (priv->ver & TDA8290) {
		tda8290_init_tuner(fe);
		tda8290_init_if(fe);
	} else if (priv->ver & TDA8295)
		tda8295_init_if(fe);

	t->fe.ops.analog_demod_ops = &tda8295_tuner_ops;
	tuner_info("type set to %s\n", t->i2c.name);

	t->mode = V4L2_TUNER_ANALOG_TV;

	tda8295_init_if(&t->fe);
	return 0;
}
EXPORT_SYMBOL_GPL(tda8295_attach);
EXPORT_SYMBOL_GPL(tda829x_attach);

int tda8290_probe(struct tuner *t)
{
@@ -745,7 +736,7 @@ int tda8290_probe(struct tuner *t)
}
EXPORT_SYMBOL_GPL(tda8290_probe);

MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver");
MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver");
MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky");
MODULE_LICENSE("GPL");

+2 −10
Original line number Diff line number Diff line
@@ -23,8 +23,7 @@
#if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE))
extern int tda8290_probe(struct tuner *t);

extern int tda8290_attach(struct tuner *t);
extern int tda8295_attach(struct tuner *t);
extern int tda829x_attach(struct tuner *t);
#else
static inline int tda8290_probe(struct tuner *t)
{
@@ -32,14 +31,7 @@ static inline int tda8290_probe(struct tuner *t)
	return -EINVAL;
}

static inline int tda8290_attach(struct tuner *t)
{
	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
	       __FUNCTION__);
	return -EINVAL;
}

static inline int tda8295_attach(struct tuner *t)
static inline int tda829x_attach(struct tuner *t)
{
	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
	       __FUNCTION__);
+1 −5
Original line number Diff line number Diff line
@@ -295,13 +295,9 @@ static void set_type(struct i2c_client *c, unsigned int type,
		microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr);
		break;
	case TUNER_PHILIPS_TDA8290:
	{
		tda8290_attach(t);
		break;
	}
	case TUNER_PHILIPS_TDA8295:
	{
		tda8295_attach(t);
		tda829x_attach(t);
		break;
	}
	case TUNER_TEA5767: