Преглед изворни кода

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: Michael Krufky <mkrufky@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Michael Krufky пре 17 година
родитељ
комит
8c125f2ceb
3 измењених фајлова са 127 додато и 148 уклоњено
  1. 124 133
      drivers/media/video/tda8290.c
  2. 2 10
      drivers/media/video/tda8290.h
  3. 1 5
      drivers/media/video/tuner-core.c

+ 124 - 133
drivers/media/video/tda8290.c

@@ -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,48 +523,25 @@ 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;
-	struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1};
+	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;
-	for (i=0x60; i<= 0x63; i++) {
+	for (i = 0x60; i <= 0x63; i++) {
 		msg.addr = i;
 		ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
 		if (ret == 1) {
@@ -570,20 +553,23 @@ 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);
-	if(tuners_found > 1)
+
+	ops->i2c_gate_ctrl(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)
+			if (ret == 1)
 				tuner_addrs = tuner_addrs >> 8;
 			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,127 +577,132 @@ 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;
 	}
-	tda827x_attach(&t->fe, priv->tda827x_addr,
-		       priv->i2c_props.adap, &priv->cfg);
 
-	/* 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);
+	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;
 
-	t->fe.ops.analog_demod_ops = &tda8290_tuner_ops;
+		tda827x_attach(&t->fe, priv->tda827x_addr,
+			       priv->i2c_props.adap, &priv->cfg);
 
-	tuner_info("type set to %s\n", t->i2c.name);
+		/* 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);
+	}
+	ops->i2c_gate_ctrl(fe, 0);
 
-	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;
 	}
-	/* 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);
+
+	/* 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;
 	}
-	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
drivers/media/video/tda8290.h

@@ -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
drivers/media/video/tuner-core.c

@@ -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: