diff options
author | Michael Krufky <mkrufky@linuxtv.org> | 2007-10-27 01:00:57 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-01-25 16:01:30 -0500 |
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 5975c548b8a6..ed22be0f5941 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c | |||
@@ -41,7 +41,13 @@ struct tda8290_priv { | |||
41 | unsigned char tda8290_easy_mode; | 41 | unsigned char tda8290_easy_mode; |
42 | 42 | ||
43 | unsigned char tda827x_addr; | 43 | unsigned char tda827x_addr; |
44 | unsigned char tda827x_ver; | 44 | |
45 | unsigned char ver; | ||
46 | #define TDA8290 1 | ||
47 | #define TDA8295 2 | ||
48 | #define TDA8275 4 | ||
49 | #define TDA8275A 8 | ||
50 | #define TDA18271 16 | ||
45 | 51 | ||
46 | struct tda827x_config cfg; | 52 | struct tda827x_config cfg; |
47 | 53 | ||
@@ -136,7 +142,7 @@ static void set_audio(struct dvb_frontend *fe) | |||
136 | mode = "xx"; | 142 | mode = "xx"; |
137 | } | 143 | } |
138 | 144 | ||
139 | tuner_dbg("setting tda8290 to system %s\n", mode); | 145 | tuner_dbg("setting tda829x to system %s\n", mode); |
140 | } | 146 | } |
141 | 147 | ||
142 | static void tda8290_set_freq(struct dvb_frontend *fe, unsigned int freq) | 148 | static void tda8290_set_freq(struct dvb_frontend *fe, unsigned int freq) |
@@ -429,7 +435,7 @@ static void tda8290_standby(struct dvb_frontend *fe) | |||
429 | struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; | 435 | struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; |
430 | 436 | ||
431 | tda8290_i2c_bridge(fe, 1); | 437 | tda8290_i2c_bridge(fe, 1); |
432 | if (priv->tda827x_ver != 0) | 438 | if (priv->ver & TDA8275A) |
433 | cb1[1] = 0x90; | 439 | cb1[1] = 0x90; |
434 | i2c_transfer(priv->i2c_props.adap, &msg, 1); | 440 | i2c_transfer(priv->i2c_props.adap, &msg, 1); |
435 | tda8290_i2c_bridge(fe, 0); | 441 | tda8290_i2c_bridge(fe, 0); |
@@ -498,7 +504,7 @@ static void tda8290_init_tuner(struct dvb_frontend *fe) | |||
498 | 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b }; | 504 | 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b }; |
499 | struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, | 505 | struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, |
500 | .buf=tda8275_init, .len = 14}; | 506 | .buf=tda8275_init, .len = 14}; |
501 | if (priv->tda827x_ver != 0) | 507 | if (priv->ver & TDA8275A) |
502 | msg.buf = tda8275a_init; | 508 | msg.buf = tda8275a_init; |
503 | 509 | ||
504 | tda8290_i2c_bridge(fe, 1); | 510 | tda8290_i2c_bridge(fe, 1); |
@@ -517,48 +523,25 @@ static void tda829x_release(struct dvb_frontend *fe) | |||
517 | fe->analog_demod_priv = NULL; | 523 | fe->analog_demod_priv = NULL; |
518 | } | 524 | } |
519 | 525 | ||
520 | static struct analog_tuner_ops tda8290_tuner_ops = { | 526 | static int tda829x_find_tuner(struct dvb_frontend *fe) |
521 | .set_tv_freq = tda8290_set_freq, | ||
522 | .set_radio_freq = tda8290_set_freq, | ||
523 | .has_signal = tda8290_has_signal, | ||
524 | .standby = tda8290_standby, | ||
525 | .release = tda829x_release, | ||
526 | .i2c_gate_ctrl = tda8290_i2c_bridge, | ||
527 | }; | ||
528 | |||
529 | static struct analog_tuner_ops tda8295_tuner_ops = { | ||
530 | .set_tv_freq = tda8295_set_freq, | ||
531 | .set_radio_freq = tda8295_set_freq, | ||
532 | .has_signal = tda8295_has_signal, | ||
533 | .standby = tda8295_standby, | ||
534 | .release = tda829x_release, | ||
535 | .i2c_gate_ctrl = tda8295_i2c_bridge, | ||
536 | }; | ||
537 | |||
538 | int tda8290_attach(struct tuner *t) | ||
539 | { | 527 | { |
540 | struct tda8290_priv *priv = NULL; | 528 | struct tda8290_priv *priv = fe->analog_demod_priv; |
541 | u8 data; | 529 | struct analog_tuner_ops *ops = fe->ops.analog_demod_ops; |
530 | struct tuner *t = priv->t; | ||
542 | int i, ret, tuners_found; | 531 | int i, ret, tuners_found; |
543 | u32 tuner_addrs; | 532 | u32 tuner_addrs; |
544 | struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1}; | 533 | u8 data; |
534 | struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; | ||
545 | 535 | ||
546 | priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); | 536 | if (NULL == ops) |
547 | if (priv == NULL) | 537 | return -EINVAL; |
548 | return -ENOMEM; | ||
549 | t->fe.analog_demod_priv = priv; | ||
550 | 538 | ||
551 | priv->i2c_props.addr = t->i2c.addr; | 539 | ops->i2c_gate_ctrl(fe, 1); |
552 | priv->i2c_props.adap = t->i2c.adapter; | ||
553 | priv->cfg.config = &t->config; | ||
554 | priv->cfg.tuner_callback = t->tuner_callback; | ||
555 | priv->t = t; | ||
556 | 540 | ||
557 | tda8290_i2c_bridge(&t->fe, 1); | ||
558 | /* probe for tuner chip */ | 541 | /* probe for tuner chip */ |
559 | tuners_found = 0; | 542 | tuners_found = 0; |
560 | tuner_addrs = 0; | 543 | tuner_addrs = 0; |
561 | for (i=0x60; i<= 0x63; i++) { | 544 | for (i = 0x60; i <= 0x63; i++) { |
562 | msg.addr = i; | 545 | msg.addr = i; |
563 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | 546 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); |
564 | if (ret == 1) { | 547 | if (ret == 1) { |
@@ -570,20 +553,23 @@ int tda8290_attach(struct tuner *t) | |||
570 | behind the bridge and we choose the highest address that doesn't | 553 | behind the bridge and we choose the highest address that doesn't |
571 | give a response now | 554 | give a response now |
572 | */ | 555 | */ |
573 | tda8290_i2c_bridge(&t->fe, 0); | 556 | |
574 | if(tuners_found > 1) | 557 | ops->i2c_gate_ctrl(fe, 0); |
558 | |||
559 | if (tuners_found > 1) | ||
575 | for (i = 0; i < tuners_found; i++) { | 560 | for (i = 0; i < tuners_found; i++) { |
576 | msg.addr = tuner_addrs & 0xff; | 561 | msg.addr = tuner_addrs & 0xff; |
577 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | 562 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); |
578 | if(ret == 1) | 563 | if (ret == 1) |
579 | tuner_addrs = tuner_addrs >> 8; | 564 | tuner_addrs = tuner_addrs >> 8; |
580 | else | 565 | else |
581 | break; | 566 | break; |
582 | } | 567 | } |
568 | |||
583 | if (tuner_addrs == 0) { | 569 | if (tuner_addrs == 0) { |
584 | tuner_addrs = 0x61; | 570 | tuner_addrs = 0x60; |
585 | tuner_info("could not clearly identify tuner address, defaulting to %x\n", | 571 | tuner_info("could not clearly identify tuner address, " |
586 | tuner_addrs); | 572 | "defaulting to %x\n", tuner_addrs); |
587 | } else { | 573 | } else { |
588 | tuner_addrs = tuner_addrs & 0xff; | 574 | tuner_addrs = tuner_addrs & 0xff; |
589 | tuner_info("setting tuner address to %x\n", tuner_addrs); | 575 | tuner_info("setting tuner address to %x\n", tuner_addrs); |
@@ -591,127 +577,132 @@ int tda8290_attach(struct tuner *t) | |||
591 | priv->tda827x_addr = tuner_addrs; | 577 | priv->tda827x_addr = tuner_addrs; |
592 | msg.addr = tuner_addrs; | 578 | msg.addr = tuner_addrs; |
593 | 579 | ||
594 | tda8290_i2c_bridge(&t->fe, 1); | 580 | ops->i2c_gate_ctrl(fe, 1); |
595 | |||
596 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | 581 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); |
597 | if( ret != 1) | ||
598 | tuner_warn("TDA827x access failed!\n"); | ||
599 | 582 | ||
600 | if ((data & 0x3c) == 0) { | 583 | if (ret != 1) { |
601 | strlcpy(t->i2c.name, "tda8290+75", sizeof(t->i2c.name)); | 584 | tuner_warn("tuner access failed!\n"); |
602 | priv->tda827x_ver = 0; | 585 | return -EREMOTEIO; |
603 | } else { | ||
604 | strlcpy(t->i2c.name, "tda8290+75a", sizeof(t->i2c.name)); | ||
605 | priv->tda827x_ver = 2; | ||
606 | } | 586 | } |
607 | tda827x_attach(&t->fe, priv->tda827x_addr, | ||
608 | priv->i2c_props.adap, &priv->cfg); | ||
609 | 587 | ||
610 | /* FIXME: tda827x module doesn't probe the tuner until | 588 | if (data == 0x83) { |
611 | * tda827x_initial_sleep is called | 589 | priv->ver |= TDA18271; |
612 | */ | 590 | tda18271_attach(&t->fe, priv->tda827x_addr, |
613 | if (t->fe.ops.tuner_ops.sleep) | 591 | priv->i2c_props.adap); |
614 | t->fe.ops.tuner_ops.sleep(&t->fe); | 592 | } else { |
593 | if ((data & 0x3c) == 0) | ||
594 | priv->ver |= TDA8275; | ||
595 | else | ||
596 | priv->ver |= TDA8275A; | ||
615 | 597 | ||
616 | t->fe.ops.analog_demod_ops = &tda8290_tuner_ops; | 598 | tda827x_attach(&t->fe, priv->tda827x_addr, |
599 | priv->i2c_props.adap, &priv->cfg); | ||
617 | 600 | ||
618 | tuner_info("type set to %s\n", t->i2c.name); | 601 | /* FIXME: tda827x module doesn't probe the tuner until |
602 | * tda827x_initial_sleep is called | ||
603 | */ | ||
604 | if (t->fe.ops.tuner_ops.sleep) | ||
605 | t->fe.ops.tuner_ops.sleep(&t->fe); | ||
606 | } | ||
607 | ops->i2c_gate_ctrl(fe, 0); | ||
619 | 608 | ||
620 | t->mode = V4L2_TUNER_ANALOG_TV; | 609 | switch (priv->ver) { |
610 | case TDA8290 | TDA8275: | ||
611 | strlcpy(t->i2c.name, "tda8290+75", sizeof(t->i2c.name)); | ||
612 | break; | ||
613 | case TDA8295 | TDA8275: | ||
614 | strlcpy(t->i2c.name, "tda8295+75", sizeof(t->i2c.name)); | ||
615 | break; | ||
616 | case TDA8290 | TDA8275A: | ||
617 | strlcpy(t->i2c.name, "tda8290+75a", sizeof(t->i2c.name)); | ||
618 | break; | ||
619 | case TDA8295 | TDA8275A: | ||
620 | strlcpy(t->i2c.name, "tda8295+75a", sizeof(t->i2c.name)); | ||
621 | break; | ||
622 | case TDA8290 | TDA18271: | ||
623 | strlcpy(t->i2c.name, "tda8290+18271", sizeof(t->i2c.name)); | ||
624 | break; | ||
625 | case TDA8295 | TDA18271: | ||
626 | strlcpy(t->i2c.name, "tda8295+18271", sizeof(t->i2c.name)); | ||
627 | break; | ||
628 | default: | ||
629 | return -EINVAL; | ||
630 | } | ||
621 | 631 | ||
622 | tda8290_init_tuner(&t->fe); | ||
623 | tda8290_init_if(&t->fe); | ||
624 | return 0; | 632 | return 0; |
625 | } | 633 | } |
626 | EXPORT_SYMBOL_GPL(tda8290_attach); | ||
627 | 634 | ||
628 | int tda8295_attach(struct tuner *t) | 635 | static struct analog_tuner_ops tda8290_tuner_ops = { |
636 | .set_tv_freq = tda8290_set_freq, | ||
637 | .set_radio_freq = tda8290_set_freq, | ||
638 | .has_signal = tda8290_has_signal, | ||
639 | .standby = tda8290_standby, | ||
640 | .release = tda829x_release, | ||
641 | .i2c_gate_ctrl = tda8290_i2c_bridge, | ||
642 | }; | ||
643 | |||
644 | static struct analog_tuner_ops tda8295_tuner_ops = { | ||
645 | .set_tv_freq = tda8295_set_freq, | ||
646 | .set_radio_freq = tda8295_set_freq, | ||
647 | .has_signal = tda8295_has_signal, | ||
648 | .standby = tda8295_standby, | ||
649 | .release = tda829x_release, | ||
650 | .i2c_gate_ctrl = tda8295_i2c_bridge, | ||
651 | }; | ||
652 | |||
653 | int tda829x_attach(struct tuner *t) | ||
629 | { | 654 | { |
655 | struct dvb_frontend *fe = &t->fe; | ||
630 | struct tda8290_priv *priv = NULL; | 656 | struct tda8290_priv *priv = NULL; |
631 | u8 data; | 657 | |
632 | int i, ret, tuners_found; | 658 | unsigned char tda8290_id[] = { 0x1f, 0x00 }; |
633 | u32 tuner_addrs; | 659 | #define TDA8290_ID 0x89 |
634 | struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; | 660 | unsigned char tda8295_id[] = { 0x2f, 0x00 }; |
661 | #define TDA8295_ID 0x8a | ||
635 | 662 | ||
636 | priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); | 663 | priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); |
637 | if (priv == NULL) | 664 | if (priv == NULL) |
638 | return -ENOMEM; | 665 | return -ENOMEM; |
639 | t->fe.analog_demod_priv = priv; | 666 | fe->analog_demod_priv = priv; |
640 | 667 | ||
641 | priv->i2c_props.addr = t->i2c.addr; | 668 | priv->i2c_props.addr = t->i2c.addr; |
642 | priv->i2c_props.adap = t->i2c.adapter; | 669 | priv->i2c_props.adap = t->i2c.adapter; |
670 | priv->cfg.config = &t->config; | ||
671 | priv->cfg.tuner_callback = t->tuner_callback; | ||
643 | priv->t = t; | 672 | priv->t = t; |
644 | 673 | ||
645 | tda8295_i2c_bridge(&t->fe, 1); | 674 | /* detect tda8290 */ |
646 | /* probe for tuner chip */ | 675 | tuner_i2c_xfer_send(&priv->i2c_props, &tda8290_id[0], 1); |
647 | tuners_found = 0; | 676 | tuner_i2c_xfer_recv(&priv->i2c_props, &tda8290_id[1], 1); |
648 | tuner_addrs = 0; | 677 | if (tda8290_id[1] == TDA8290_ID) { |
649 | for (i = 0x60; i <= 0x63; i++) { | 678 | priv->ver = TDA8290; |
650 | msg.addr = i; | 679 | fe->ops.analog_demod_ops = &tda8290_tuner_ops; |
651 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
652 | if (ret == 1) { | ||
653 | tuners_found++; | ||
654 | tuner_addrs = (tuner_addrs << 8) + i; | ||
655 | } | ||
656 | } | 680 | } |
657 | /* if there is more than one tuner, we expect the right one is | 681 | |
658 | behind the bridge and we choose the highest address that doesn't | 682 | /* detect tda8295 */ |
659 | give a response now | 683 | tuner_i2c_xfer_send(&priv->i2c_props, &tda8295_id[0], 1); |
660 | */ | 684 | tuner_i2c_xfer_recv(&priv->i2c_props, &tda8295_id[1], 1); |
661 | tda8295_i2c_bridge(&t->fe, 0); | 685 | if (tda8295_id[1] == TDA8295_ID) { |
662 | if (tuners_found > 1) | 686 | priv->ver = TDA8295; |
663 | for (i = 0; i < tuners_found; i++) { | 687 | fe->ops.analog_demod_ops = &tda8295_tuner_ops; |
664 | msg.addr = tuner_addrs & 0xff; | ||
665 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
666 | if (ret == 1) | ||
667 | tuner_addrs = tuner_addrs >> 8; | ||
668 | else | ||
669 | break; | ||
670 | } | ||
671 | if (tuner_addrs == 0) { | ||
672 | tuner_addrs = 0x60; | ||
673 | tuner_info("could not clearly identify tuner address, " | ||
674 | "defaulting to %x\n", tuner_addrs); | ||
675 | } else { | ||
676 | tuner_addrs = tuner_addrs & 0xff; | ||
677 | tuner_info("setting tuner address to %x\n", tuner_addrs); | ||
678 | } | 688 | } |
679 | priv->tda827x_addr = tuner_addrs; | ||
680 | msg.addr = tuner_addrs; | ||
681 | 689 | ||
682 | tda8295_i2c_bridge(&t->fe, 1); | 690 | if (tda829x_find_tuner(fe) < 0) |
683 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | 691 | return -EINVAL; |
684 | tda8295_i2c_bridge(&t->fe, 0); | ||
685 | if (ret != 1) | ||
686 | tuner_warn("TDA827x access failed!\n"); | ||
687 | if ((data & 0x3c) == 0) { | ||
688 | strlcpy(t->i2c.name, "tda8295+18271", sizeof(t->i2c.name)); | ||
689 | tda18271_attach(&t->fe, priv->tda827x_addr, | ||
690 | priv->i2c_props.adap); | ||
691 | priv->tda827x_ver = 4; | ||
692 | } else { | ||
693 | strlcpy(t->i2c.name, "tda8295+75a", sizeof(t->i2c.name)); | ||
694 | tda827x_attach(&t->fe, priv->tda827x_addr, | ||
695 | priv->i2c_props.adap, &priv->cfg); | ||
696 | 692 | ||
697 | /* FIXME: tda827x module doesn't probe the tuner until | 693 | if (priv->ver & TDA8290) { |
698 | * tda827x_initial_sleep is called | 694 | tda8290_init_tuner(fe); |
699 | */ | 695 | tda8290_init_if(fe); |
700 | if (t->fe.ops.tuner_ops.sleep) | 696 | } else if (priv->ver & TDA8295) |
701 | t->fe.ops.tuner_ops.sleep(&t->fe); | 697 | tda8295_init_if(fe); |
702 | priv->tda827x_ver = 2; | ||
703 | } | ||
704 | priv->tda827x_ver |= 1; /* signifies 8295 vs 8290 */ | ||
705 | tuner_info("type set to %s\n", t->i2c.name); | ||
706 | 698 | ||
707 | t->fe.ops.analog_demod_ops = &tda8295_tuner_ops; | 699 | tuner_info("type set to %s\n", t->i2c.name); |
708 | 700 | ||
709 | t->mode = V4L2_TUNER_ANALOG_TV; | 701 | t->mode = V4L2_TUNER_ANALOG_TV; |
710 | 702 | ||
711 | tda8295_init_if(&t->fe); | ||
712 | return 0; | 703 | return 0; |
713 | } | 704 | } |
714 | EXPORT_SYMBOL_GPL(tda8295_attach); | 705 | EXPORT_SYMBOL_GPL(tda829x_attach); |
715 | 706 | ||
716 | int tda8290_probe(struct tuner *t) | 707 | int tda8290_probe(struct tuner *t) |
717 | { | 708 | { |
@@ -745,7 +736,7 @@ int tda8290_probe(struct tuner *t) | |||
745 | } | 736 | } |
746 | EXPORT_SYMBOL_GPL(tda8290_probe); | 737 | EXPORT_SYMBOL_GPL(tda8290_probe); |
747 | 738 | ||
748 | MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver"); | 739 | MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver"); |
749 | MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); | 740 | MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); |
750 | MODULE_LICENSE("GPL"); | 741 | MODULE_LICENSE("GPL"); |
751 | 742 | ||