diff options
author | Michael Krufky <mkrufky@linuxtv.org> | 2007-10-27 02:00:57 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-01-25 19:01:30 -0200 |
commit | 8c125f2ceb3ec1ba01e96fffd8558ef163b40fe8 (patch) | |
tree | 04ba00ab3874035ec554fcd1a5b5812f42463082 /drivers/media/video/tda8290.c | |
parent | 393bf5573269979aa3fb55d1bdd0db4fcb288f99 (diff) |
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>
Diffstat (limited to 'drivers/media/video/tda8290.c')
-rw-r--r-- | drivers/media/video/tda8290.c | 257 |
1 files changed, 124 insertions, 133 deletions
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 5975c548b8a..ed22be0f594 100644 --- a/drivers/media/video/tda8290.c +++ b/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"); |