diff options
author | Michael Krufky <mkrufky@linuxtv.org> | 2007-10-22 08:56:38 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-01-25 16:01:06 -0500 |
commit | 5bea1cd3871351d70cc7624af138f8aa68b7be77 (patch) | |
tree | 77db506f3fb668e33e091aaa1cda2cf09da85085 /drivers/media/video/tda8290.c | |
parent | ce1f8bdb0cbe9c5f57cf0256ef75fce06152547f (diff) |
V4L/DVB (6435): tda8290: add support for NXP TDA18271 tuner and TDA8295 analog demod
Add basic support for NXP TDA8295 analog demod and TDA18271 tuner silicon.
TDA8295 + TDA8275a not yet tested.
TDA8290 + TDA18271 not yet supported.
Digital mode of TDA18271 not yet tested & needs more work.
Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
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 | 319 |
1 files changed, 313 insertions, 6 deletions
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 5d30cbcd7361..a38ed9db6403 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c | |||
@@ -25,8 +25,9 @@ | |||
25 | #include <linux/videodev.h> | 25 | #include <linux/videodev.h> |
26 | #include "tda8290.h" | 26 | #include "tda8290.h" |
27 | #include "tda827x.h" | 27 | #include "tda827x.h" |
28 | #include "tda18271.h" | ||
28 | 29 | ||
29 | static int tuner_debug = 0; | 30 | static int tuner_debug; |
30 | module_param_named(debug, tuner_debug, int, 0644); | 31 | module_param_named(debug, tuner_debug, int, 0644); |
31 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | 32 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); |
32 | 33 | ||
@@ -65,6 +66,34 @@ static void tda8290_i2c_bridge(struct tuner *t, int close) | |||
65 | } | 66 | } |
66 | } | 67 | } |
67 | 68 | ||
69 | static void tda8295_i2c_bridge(struct tuner *t, int close) | ||
70 | { | ||
71 | struct tda8290_priv *priv = t->priv; | ||
72 | |||
73 | unsigned char enable[2] = { 0x45, 0xc1 }; | ||
74 | unsigned char disable[2] = { 0x46, 0x00 }; | ||
75 | unsigned char buf[3] = { 0x45, 0x01, 0x00 }; | ||
76 | unsigned char *msg; | ||
77 | if (close) { | ||
78 | msg = enable; | ||
79 | tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); | ||
80 | /* let the bridge stabilize */ | ||
81 | msleep(20); | ||
82 | } else { | ||
83 | msg = disable; | ||
84 | tuner_i2c_xfer_send(&priv->i2c_props, msg, 1); | ||
85 | tuner_i2c_xfer_recv(&priv->i2c_props, &msg[1], 1); | ||
86 | |||
87 | buf[2] = msg[1]; | ||
88 | buf[2] &= ~0x04; | ||
89 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 3); | ||
90 | msleep(5); | ||
91 | |||
92 | msg[1] |= 0x04; | ||
93 | tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); | ||
94 | } | ||
95 | } | ||
96 | |||
68 | /*---------------------------------------------------------------------*/ | 97 | /*---------------------------------------------------------------------*/ |
69 | 98 | ||
70 | static void set_audio(struct tuner *t) | 99 | static void set_audio(struct tuner *t) |
@@ -233,6 +262,153 @@ static void tda8290_set_freq(struct tuner *t, unsigned int freq) | |||
233 | 262 | ||
234 | /*---------------------------------------------------------------------*/ | 263 | /*---------------------------------------------------------------------*/ |
235 | 264 | ||
265 | static void tda8295_power(struct tuner *t, int enable) | ||
266 | { | ||
267 | struct tda8290_priv *priv = t->priv; | ||
268 | unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */ | ||
269 | |||
270 | tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); | ||
271 | tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); | ||
272 | |||
273 | if (enable) | ||
274 | buf[1] = 0x01; | ||
275 | else | ||
276 | buf[1] = 0x03; | ||
277 | |||
278 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); | ||
279 | } | ||
280 | |||
281 | static void tda8295_set_easy_mode(struct tuner *t, int enable) | ||
282 | { | ||
283 | struct tda8290_priv *priv = t->priv; | ||
284 | unsigned char buf[] = { 0x01, 0x00 }; | ||
285 | |||
286 | tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); | ||
287 | tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); | ||
288 | |||
289 | if (enable) | ||
290 | buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */ | ||
291 | else | ||
292 | buf[1] = 0x00; /* reset active bit */ | ||
293 | |||
294 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); | ||
295 | } | ||
296 | |||
297 | static void tda8295_set_video_std(struct tuner *t) | ||
298 | { | ||
299 | struct tda8290_priv *priv = t->priv; | ||
300 | unsigned char buf[] = { 0x00, priv->tda8290_easy_mode }; | ||
301 | |||
302 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); | ||
303 | |||
304 | tda8295_set_easy_mode(t, 1); | ||
305 | msleep(20); | ||
306 | tda8295_set_easy_mode(t, 0); | ||
307 | } | ||
308 | |||
309 | /*---------------------------------------------------------------------*/ | ||
310 | |||
311 | static void tda8295_agc1_out(struct tuner *t, int enable) | ||
312 | { | ||
313 | struct tda8290_priv *priv = t->priv; | ||
314 | unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */ | ||
315 | |||
316 | tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); | ||
317 | tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); | ||
318 | |||
319 | if (enable) | ||
320 | buf[1] &= ~0x40; | ||
321 | else | ||
322 | buf[1] |= 0x40; | ||
323 | |||
324 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); | ||
325 | } | ||
326 | |||
327 | static void tda8295_agc2_out(struct tuner *t, int enable) | ||
328 | { | ||
329 | struct tda8290_priv *priv = t->priv; | ||
330 | unsigned char set_gpio_cf[] = { 0x44, 0x00 }; | ||
331 | unsigned char set_gpio_val[] = { 0x46, 0x00 }; | ||
332 | |||
333 | tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_cf[0], 1); | ||
334 | tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_cf[1], 1); | ||
335 | tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_val[0], 1); | ||
336 | tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_val[1], 1); | ||
337 | |||
338 | set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */ | ||
339 | |||
340 | if (enable) { | ||
341 | set_gpio_cf[1] |= 0x01; /* config GPIO_0 as Open Drain Out */ | ||
342 | set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */ | ||
343 | } | ||
344 | tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2); | ||
345 | tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2); | ||
346 | } | ||
347 | |||
348 | static int tda8295_has_signal(struct tuner *t) | ||
349 | { | ||
350 | struct tda8290_priv *priv = t->priv; | ||
351 | |||
352 | unsigned char hvpll_stat = 0x26; | ||
353 | unsigned char ret; | ||
354 | |||
355 | tuner_i2c_xfer_send(&priv->i2c_props, &hvpll_stat, 1); | ||
356 | tuner_i2c_xfer_recv(&priv->i2c_props, &ret, 1); | ||
357 | return (ret & 0x01) ? 65535 : 0; | ||
358 | } | ||
359 | |||
360 | /*---------------------------------------------------------------------*/ | ||
361 | |||
362 | static void tda8295_set_freq(struct tuner *t, unsigned int freq) | ||
363 | { | ||
364 | struct tda8290_priv *priv = t->priv; | ||
365 | u16 ifc; | ||
366 | |||
367 | unsigned char blanking_mode[] = { 0x1d, 0x00 }; | ||
368 | |||
369 | struct analog_parameters params = { | ||
370 | .frequency = freq, | ||
371 | .mode = t->mode, | ||
372 | .audmode = t->audmode, | ||
373 | .std = t->std | ||
374 | }; | ||
375 | |||
376 | set_audio(t); | ||
377 | |||
378 | ifc = priv->cfg.sgIF; /* FIXME */ | ||
379 | |||
380 | tuner_dbg("%s: ifc = %u, freq = %d\n", __FUNCTION__, ifc, freq); | ||
381 | |||
382 | tda8295_power(t, 1); | ||
383 | tda8295_agc1_out(t, 1); | ||
384 | |||
385 | tuner_i2c_xfer_send(&priv->i2c_props, &blanking_mode[0], 1); | ||
386 | tuner_i2c_xfer_recv(&priv->i2c_props, &blanking_mode[1], 1); | ||
387 | |||
388 | tda8295_set_video_std(t); | ||
389 | |||
390 | blanking_mode[1] = 0x03; | ||
391 | tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2); | ||
392 | msleep(20); | ||
393 | |||
394 | tda8295_i2c_bridge(t, 1); | ||
395 | |||
396 | if (t->fe.ops.tuner_ops.set_analog_params) | ||
397 | t->fe.ops.tuner_ops.set_analog_params(&t->fe, ¶ms); | ||
398 | |||
399 | if (priv->cfg.agcf) | ||
400 | priv->cfg.agcf(&t->fe); | ||
401 | |||
402 | if (tda8295_has_signal(t)) | ||
403 | tuner_dbg("tda8295 is locked\n"); | ||
404 | else | ||
405 | tuner_dbg("tda8295 not locked, no signal?\n"); | ||
406 | |||
407 | tda8295_i2c_bridge(t, 0); | ||
408 | } | ||
409 | |||
410 | /*---------------------------------------------------------------------*/ | ||
411 | |||
236 | static int tda8290_has_signal(struct tuner *t) | 412 | static int tda8290_has_signal(struct tuner *t) |
237 | { | 413 | { |
238 | struct tda8290_priv *priv = t->priv; | 414 | struct tda8290_priv *priv = t->priv; |
@@ -264,6 +440,13 @@ static void tda8290_standby(struct tuner *t) | |||
264 | tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); | 440 | tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); |
265 | } | 441 | } |
266 | 442 | ||
443 | static void tda8295_standby(struct tuner *t) | ||
444 | { | ||
445 | tda8295_agc1_out(t, 0); /* Put AGC in tri-state */ | ||
446 | |||
447 | tda8295_power(t, 0); | ||
448 | } | ||
449 | |||
267 | static void tda8290_init_if(struct tuner *t) | 450 | static void tda8290_init_if(struct tuner *t) |
268 | { | 451 | { |
269 | struct tda8290_priv *priv = t->priv; | 452 | struct tda8290_priv *priv = t->priv; |
@@ -279,6 +462,35 @@ static void tda8290_init_if(struct tuner *t) | |||
279 | tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); | 462 | tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); |
280 | } | 463 | } |
281 | 464 | ||
465 | static void tda8295_init_if(struct tuner *t) | ||
466 | { | ||
467 | struct tda8290_priv *priv = t->priv; | ||
468 | |||
469 | static unsigned char set_adc_ctl[] = { 0x33, 0x14 }; | ||
470 | static unsigned char set_adc_ctl2[] = { 0x34, 0x00 }; | ||
471 | static unsigned char set_pll_reg6[] = { 0x3e, 0x63 }; | ||
472 | static unsigned char set_pll_reg0[] = { 0x38, 0x23 }; | ||
473 | static unsigned char set_pll_reg7[] = { 0x3f, 0x01 }; | ||
474 | static unsigned char set_pll_reg10[] = { 0x42, 0x61 }; | ||
475 | static unsigned char set_gpio_reg0[] = { 0x44, 0x0b }; | ||
476 | |||
477 | tda8295_power(t, 1); | ||
478 | |||
479 | tda8295_set_easy_mode(t, 0); | ||
480 | tda8295_set_video_std(t); | ||
481 | |||
482 | tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2); | ||
483 | tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2); | ||
484 | tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2); | ||
485 | tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2); | ||
486 | tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2); | ||
487 | tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2); | ||
488 | tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2); | ||
489 | |||
490 | tda8295_agc1_out(t, 0); | ||
491 | tda8295_agc2_out(t, 0); | ||
492 | } | ||
493 | |||
282 | static void tda8290_init_tuner(struct tuner *t) | 494 | static void tda8290_init_tuner(struct tuner *t) |
283 | { | 495 | { |
284 | struct tda8290_priv *priv = t->priv; | 496 | struct tda8290_priv *priv = t->priv; |
@@ -298,7 +510,7 @@ static void tda8290_init_tuner(struct tuner *t) | |||
298 | 510 | ||
299 | /*---------------------------------------------------------------------*/ | 511 | /*---------------------------------------------------------------------*/ |
300 | 512 | ||
301 | static void tda8290_release(struct tuner *t) | 513 | static void tda829x_release(struct tuner *t) |
302 | { | 514 | { |
303 | if (t->fe.ops.tuner_ops.release) | 515 | if (t->fe.ops.tuner_ops.release) |
304 | t->fe.ops.tuner_ops.release(&t->fe); | 516 | t->fe.ops.tuner_ops.release(&t->fe); |
@@ -312,7 +524,15 @@ static struct tuner_operations tda8290_tuner_ops = { | |||
312 | .set_radio_freq = tda8290_set_freq, | 524 | .set_radio_freq = tda8290_set_freq, |
313 | .has_signal = tda8290_has_signal, | 525 | .has_signal = tda8290_has_signal, |
314 | .standby = tda8290_standby, | 526 | .standby = tda8290_standby, |
315 | .release = tda8290_release, | 527 | .release = tda829x_release, |
528 | }; | ||
529 | |||
530 | static struct tuner_operations tda8295_tuner_ops = { | ||
531 | .set_tv_freq = tda8295_set_freq, | ||
532 | .set_radio_freq = tda8295_set_freq, | ||
533 | .has_signal = tda8295_has_signal, | ||
534 | .standby = tda8295_standby, | ||
535 | .release = tda829x_release, | ||
316 | }; | 536 | }; |
317 | 537 | ||
318 | int tda8290_attach(struct tuner *t) | 538 | int tda8290_attach(struct tuner *t) |
@@ -403,6 +623,95 @@ int tda8290_attach(struct tuner *t) | |||
403 | tda8290_init_if(t); | 623 | tda8290_init_if(t); |
404 | return 0; | 624 | return 0; |
405 | } | 625 | } |
626 | EXPORT_SYMBOL_GPL(tda8290_attach); | ||
627 | |||
628 | int tda8295_attach(struct tuner *t) | ||
629 | { | ||
630 | struct tda8290_priv *priv = NULL; | ||
631 | u8 data; | ||
632 | int i, ret, tuners_found; | ||
633 | u32 tuner_addrs; | ||
634 | struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; | ||
635 | |||
636 | priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); | ||
637 | if (priv == NULL) | ||
638 | return -ENOMEM; | ||
639 | t->priv = priv; | ||
640 | |||
641 | priv->i2c_props.addr = t->i2c.addr; | ||
642 | priv->i2c_props.adap = t->i2c.adapter; | ||
643 | |||
644 | tda8295_i2c_bridge(t, 1); | ||
645 | /* probe for tuner chip */ | ||
646 | tuners_found = 0; | ||
647 | tuner_addrs = 0; | ||
648 | for (i = 0x60; i <= 0x63; i++) { | ||
649 | msg.addr = i; | ||
650 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
651 | if (ret == 1) { | ||
652 | tuners_found++; | ||
653 | tuner_addrs = (tuner_addrs << 8) + i; | ||
654 | } | ||
655 | } | ||
656 | /* if there is more than one tuner, we expect the right one is | ||
657 | behind the bridge and we choose the highest address that doesn't | ||
658 | give a response now | ||
659 | */ | ||
660 | tda8295_i2c_bridge(t, 0); | ||
661 | if (tuners_found > 1) | ||
662 | for (i = 0; i < tuners_found; i++) { | ||
663 | msg.addr = tuner_addrs & 0xff; | ||
664 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
665 | if (ret == 1) | ||
666 | tuner_addrs = tuner_addrs >> 8; | ||
667 | else | ||
668 | break; | ||
669 | } | ||
670 | if (tuner_addrs == 0) { | ||
671 | tuner_addrs = 0x60; | ||
672 | tuner_info("could not clearly identify tuner address, " | ||
673 | "defaulting to %x\n", tuner_addrs); | ||
674 | } else { | ||
675 | tuner_addrs = tuner_addrs & 0xff; | ||
676 | tuner_info("setting tuner address to %x\n", tuner_addrs); | ||
677 | } | ||
678 | priv->tda827x_addr = tuner_addrs; | ||
679 | msg.addr = tuner_addrs; | ||
680 | |||
681 | tda8295_i2c_bridge(t, 1); | ||
682 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
683 | tda8295_i2c_bridge(t, 0); | ||
684 | if (ret != 1) | ||
685 | tuner_warn("TDA827x access failed!\n"); | ||
686 | if ((data & 0x3c) == 0) { | ||
687 | strlcpy(t->i2c.name, "tda8295+18271", sizeof(t->i2c.name)); | ||
688 | tda18271_attach(&t->fe, priv->tda827x_addr, | ||
689 | priv->i2c_props.adap); | ||
690 | priv->tda827x_ver = 4; | ||
691 | } else { | ||
692 | strlcpy(t->i2c.name, "tda8295+75a", sizeof(t->i2c.name)); | ||
693 | tda827x_attach(&t->fe, priv->tda827x_addr, | ||
694 | priv->i2c_props.adap, &priv->cfg); | ||
695 | |||
696 | /* FIXME: tda827x module doesn't probe the tuner until | ||
697 | * tda827x_initial_sleep is called | ||
698 | */ | ||
699 | if (t->fe.ops.tuner_ops.sleep) | ||
700 | t->fe.ops.tuner_ops.sleep(&t->fe); | ||
701 | priv->tda827x_ver = 2; | ||
702 | } | ||
703 | priv->tda827x_ver |= 1; /* signifies 8295 vs 8290 */ | ||
704 | tuner_info("type set to %s\n", t->i2c.name); | ||
705 | |||
706 | memcpy(&t->ops, &tda8295_tuner_ops, sizeof(struct tuner_operations)); | ||
707 | |||
708 | priv->cfg.tda827x_lpsel = 0; | ||
709 | t->mode = V4L2_TUNER_ANALOG_TV; | ||
710 | |||
711 | tda8295_init_if(t); | ||
712 | return 0; | ||
713 | } | ||
714 | EXPORT_SYMBOL_GPL(tda8295_attach); | ||
406 | 715 | ||
407 | int tda8290_probe(struct tuner *t) | 716 | int tda8290_probe(struct tuner *t) |
408 | { | 717 | { |
@@ -434,12 +743,10 @@ int tda8290_probe(struct tuner *t) | |||
434 | tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); | 743 | tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); |
435 | return -1; | 744 | return -1; |
436 | } | 745 | } |
437 | |||
438 | EXPORT_SYMBOL_GPL(tda8290_probe); | 746 | EXPORT_SYMBOL_GPL(tda8290_probe); |
439 | EXPORT_SYMBOL_GPL(tda8290_attach); | ||
440 | 747 | ||
441 | MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver"); | 748 | MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver"); |
442 | MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann"); | 749 | MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); |
443 | MODULE_LICENSE("GPL"); | 750 | MODULE_LICENSE("GPL"); |
444 | 751 | ||
445 | /* | 752 | /* |