diff options
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/tuner-xc2028-types.h | 8 | ||||
-rw-r--r-- | drivers/media/video/tuner-xc2028.c | 212 | ||||
-rw-r--r-- | drivers/media/video/tuner-xc2028.h | 1 |
3 files changed, 124 insertions, 97 deletions
diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/video/tuner-xc2028-types.h index a9e2e0562d99..6cee48193c47 100644 --- a/drivers/media/video/tuner-xc2028-types.h +++ b/drivers/media/video/tuner-xc2028-types.h | |||
@@ -8,6 +8,7 @@ | |||
8 | 8 | ||
9 | /* BASE firmware should be loaded before any other firmware */ | 9 | /* BASE firmware should be loaded before any other firmware */ |
10 | #define BASE (1<<0) | 10 | #define BASE (1<<0) |
11 | #define BASE_TYPES (BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1) | ||
11 | 12 | ||
12 | /* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */ | 13 | /* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */ |
13 | #define F8MHZ (1<<1) | 14 | #define F8MHZ (1<<1) |
@@ -37,6 +38,8 @@ | |||
37 | #define DTV78 (1<<8) | 38 | #define DTV78 (1<<8) |
38 | #define DTV8 (1<<9) | 39 | #define DTV8 (1<<9) |
39 | 40 | ||
41 | #define DTV_TYPES (D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC) | ||
42 | |||
40 | /* There's a FM | BASE firmware + FM specific firmware (std=0) */ | 43 | /* There's a FM | BASE firmware + FM specific firmware (std=0) */ |
41 | #define FM (1<<10) | 44 | #define FM (1<<10) |
42 | 45 | ||
@@ -60,6 +63,7 @@ | |||
60 | /* Old firmwares were broken into init0 and init1 */ | 63 | /* Old firmwares were broken into init0 and init1 */ |
61 | #define INIT1 (1<<14) | 64 | #define INIT1 (1<<14) |
62 | 65 | ||
66 | /* SCODE firmware selects particular behaviours */ | ||
63 | #define MONO (1 << 15) | 67 | #define MONO (1 << 15) |
64 | #define ATSC (1 << 16) | 68 | #define ATSC (1 << 16) |
65 | #define IF (1 << 17) | 69 | #define IF (1 << 17) |
@@ -76,6 +80,10 @@ | |||
76 | #define INPUT2 (1 << 28) | 80 | #define INPUT2 (1 << 28) |
77 | #define SCODE (1 << 29) | 81 | #define SCODE (1 << 29) |
78 | 82 | ||
83 | #define SCODE_TYPES (MTS|DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \ | ||
84 | LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794| \ | ||
85 | DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE) | ||
86 | |||
79 | /* Newer types to be moved to videodev2.h */ | 87 | /* Newer types to be moved to videodev2.h */ |
80 | 88 | ||
81 | #define V4L2_STD_SECAM_K3 (0x04000000) | 89 | #define V4L2_STD_SECAM_K3 (0x04000000) |
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index a5efd5f6e57c..8140d8ad0792 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c | |||
@@ -54,6 +54,14 @@ struct firmware_description { | |||
54 | unsigned int size; | 54 | unsigned int size; |
55 | }; | 55 | }; |
56 | 56 | ||
57 | struct firmware_properties { | ||
58 | unsigned int type; | ||
59 | v4l2_std_id id; | ||
60 | v4l2_std_id std_req; | ||
61 | unsigned int scode_table; | ||
62 | int scode_nr; | ||
63 | }; | ||
64 | |||
57 | struct xc2028_data { | 65 | struct xc2028_data { |
58 | struct list_head xc2028_list; | 66 | struct list_head xc2028_list; |
59 | struct tuner_i2c_props i2c_props; | 67 | struct tuner_i2c_props i2c_props; |
@@ -69,14 +77,7 @@ struct xc2028_data { | |||
69 | 77 | ||
70 | struct xc2028_ctrl ctrl; | 78 | struct xc2028_ctrl ctrl; |
71 | 79 | ||
72 | v4l2_std_id firm_type; /* video stds supported | 80 | struct firmware_properties cur_fw; |
73 | by current firmware */ | ||
74 | fe_bandwidth_t bandwidth; /* Firmware bandwidth: | ||
75 | 6M, 7M or 8M */ | ||
76 | int need_load_generic; /* The generic firmware | ||
77 | were loaded? */ | ||
78 | enum tuner_mode mode; | ||
79 | struct i2c_client *i2c_client; | ||
80 | 81 | ||
81 | struct mutex lock; | 82 | struct mutex lock; |
82 | }; | 83 | }; |
@@ -234,7 +235,8 @@ static void free_firmware(struct xc2028_data *priv) | |||
234 | 235 | ||
235 | priv->firm = NULL; | 236 | priv->firm = NULL; |
236 | priv->firm_size = 0; | 237 | priv->firm_size = 0; |
237 | priv->need_load_generic = 1; | 238 | |
239 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); | ||
238 | } | 240 | } |
239 | 241 | ||
240 | static int load_all_firmwares(struct dvb_frontend *fe) | 242 | static int load_all_firmwares(struct dvb_frontend *fe) |
@@ -393,6 +395,13 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, | |||
393 | if (((type & ~SCODE) == 0) && (*id == 0)) | 395 | if (((type & ~SCODE) == 0) && (*id == 0)) |
394 | *id = V4L2_STD_PAL; | 396 | *id = V4L2_STD_PAL; |
395 | 397 | ||
398 | if (type & BASE) | ||
399 | type &= BASE_TYPES; | ||
400 | else if (type & SCODE) | ||
401 | type &= SCODE_TYPES; | ||
402 | else if (type & DTV_TYPES) | ||
403 | type = type & DTV_TYPES; | ||
404 | |||
396 | /* Seek for exact match */ | 405 | /* Seek for exact match */ |
397 | for (i = 0; i < priv->firm_size; i++) { | 406 | for (i = 0; i < priv->firm_size; i++) { |
398 | if ((type == priv->firm[i].type) && (*id == priv->firm[i].id)) | 407 | if ((type == priv->firm[i].type) && (*id == priv->firm[i].id)) |
@@ -598,11 +607,10 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, | |||
598 | v4l2_std_id std, fe_bandwidth_t bandwidth) | 607 | v4l2_std_id std, fe_bandwidth_t bandwidth) |
599 | { | 608 | { |
600 | struct xc2028_data *priv = fe->tuner_priv; | 609 | struct xc2028_data *priv = fe->tuner_priv; |
601 | int rc; | 610 | int rc = 0; |
611 | unsigned int type = 0; | ||
612 | struct firmware_properties new_fw; | ||
602 | u16 version, hwmodel; | 613 | u16 version, hwmodel; |
603 | v4l2_std_id std0 = 0; | ||
604 | unsigned int type0 = 0, type = 0; | ||
605 | int change_digital_bandwidth; | ||
606 | 614 | ||
607 | tuner_dbg("%s called\n", __FUNCTION__); | 615 | tuner_dbg("%s called\n", __FUNCTION__); |
608 | 616 | ||
@@ -617,61 +625,19 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, | |||
617 | return rc; | 625 | return rc; |
618 | } | 626 | } |
619 | 627 | ||
620 | tuner_dbg("I am in mode %u and I should switch to mode %i\n", | 628 | if (priv->ctrl.type == XC2028_FIRM_MTS) |
621 | priv->mode, new_mode); | 629 | type |= MTS; |
622 | 630 | if (bandwidth == BANDWIDTH_7_MHZ || bandwidth == BANDWIDTH_8_MHZ) | |
623 | /* first of all, determine whether we have switched the mode */ | 631 | type |= F8MHZ; |
624 | if (new_mode != priv->mode) { | ||
625 | priv->mode = new_mode; | ||
626 | priv->need_load_generic = 1; | ||
627 | } | ||
628 | |||
629 | change_digital_bandwidth = (priv->mode == T_DIGITAL_TV | ||
630 | && bandwidth != priv->bandwidth) ? 1 : 0; | ||
631 | tuner_dbg("old bandwidth %u, new bandwidth %u\n", priv->bandwidth, | ||
632 | bandwidth); | ||
633 | |||
634 | if (priv->need_load_generic) { | ||
635 | /* Reset is needed before loading firmware */ | ||
636 | rc = priv->tuner_callback(priv->video_dev, | ||
637 | XC2028_TUNER_RESET, 0); | ||
638 | if (rc < 0) | ||
639 | return rc; | ||
640 | |||
641 | type0 = BASE; | ||
642 | |||
643 | if (priv->ctrl.type == XC2028_FIRM_MTS) | ||
644 | type0 |= MTS; | ||
645 | |||
646 | if (bandwidth == BANDWIDTH_7_MHZ || | ||
647 | bandwidth == BANDWIDTH_8_MHZ) | ||
648 | type0 |= F8MHZ; | ||
649 | |||
650 | /* FIXME: How to load FM and FM|INPUT1 firmwares? */ | ||
651 | |||
652 | rc = load_firmware(fe, type0, &std0); | ||
653 | if (rc < 0) { | ||
654 | tuner_err("Error %d while loading generic firmware\n", | ||
655 | rc); | ||
656 | return rc; | ||
657 | } | ||
658 | |||
659 | priv->need_load_generic = 0; | ||
660 | priv->firm_type = 0; | ||
661 | if (priv->mode == T_DIGITAL_TV) | ||
662 | change_digital_bandwidth = 1; | ||
663 | } | ||
664 | 632 | ||
665 | tuner_dbg("I should change bandwidth %u\n", change_digital_bandwidth); | 633 | /* FIXME: How to load FM and FM|INPUT1 firmwares? */ |
666 | 634 | ||
667 | if (change_digital_bandwidth) { | 635 | if (new_mode == T_DIGITAL_TV) { |
668 | if (priv->ctrl.d2633) | 636 | if (priv->ctrl.d2633) |
669 | type |= D2633; | 637 | type |= D2633; |
670 | else | 638 | else |
671 | type |= D2620; | 639 | type |= D2620; |
672 | 640 | ||
673 | /* FIXME: When should select a DTV78 firmware? | ||
674 | */ | ||
675 | switch (bandwidth) { | 641 | switch (bandwidth) { |
676 | case BANDWIDTH_8_MHZ: | 642 | case BANDWIDTH_8_MHZ: |
677 | type |= DTV8; | 643 | type |= DTV8; |
@@ -683,49 +649,96 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, | |||
683 | /* FIXME: Should allow select also ATSC */ | 649 | /* FIXME: Should allow select also ATSC */ |
684 | type |= DTV6 | QAM; | 650 | type |= DTV6 | QAM; |
685 | break; | 651 | break; |
686 | |||
687 | default: | 652 | default: |
688 | tuner_err("error: bandwidth not supported.\n"); | 653 | tuner_err("error: bandwidth not supported.\n"); |
689 | }; | 654 | }; |
690 | priv->bandwidth = bandwidth; | ||
691 | } | 655 | } |
692 | 656 | ||
693 | if (!change_digital_bandwidth && priv->mode == T_DIGITAL_TV) | 657 | new_fw.type = type; |
694 | return 0; | 658 | new_fw.id = std; |
659 | new_fw.std_req = std; | ||
660 | new_fw.scode_table = SCODE | priv->ctrl.scode_table; | ||
661 | new_fw.scode_nr = 0; | ||
662 | |||
663 | tuner_dbg("checking firmware, user requested type="); | ||
664 | if (debug) { | ||
665 | dump_firm_type(new_fw.type); | ||
666 | printk("(%x), id %016llx, scode_tbl ", new_fw.type, | ||
667 | (unsigned long long)new_fw.std_req); | ||
668 | dump_firm_type(priv->ctrl.scode_table); | ||
669 | printk("(%x), scode_nr %d\n", priv->ctrl.scode_table, | ||
670 | new_fw.scode_nr); | ||
671 | } | ||
672 | |||
673 | /* No need to reload base firmware if it matches */ | ||
674 | if (((BASE | new_fw.type) & BASE_TYPES) == | ||
675 | (priv->cur_fw.type & BASE_TYPES)) { | ||
676 | tuner_dbg("BASE firmware not changed.\n"); | ||
677 | goto skip_base; | ||
678 | } | ||
679 | |||
680 | /* Updating BASE - forget about all currently loaded firmware */ | ||
681 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); | ||
682 | |||
683 | /* Reset is needed before loading firmware */ | ||
684 | rc = priv->tuner_callback(priv->video_dev, | ||
685 | XC2028_TUNER_RESET, 0); | ||
686 | if (rc < 0) | ||
687 | goto fail; | ||
688 | |||
689 | rc = load_firmware(fe, BASE | new_fw.type, &new_fw.id); | ||
690 | if (rc < 0) { | ||
691 | tuner_err("Error %d while loading base firmware\n", | ||
692 | rc); | ||
693 | goto fail; | ||
694 | } | ||
695 | 695 | ||
696 | /* Load INIT1, if needed */ | 696 | /* Load INIT1, if needed */ |
697 | tuner_dbg("Load init1 firmware, if exists\n"); | 697 | tuner_dbg("Load init1 firmware, if exists\n"); |
698 | type0 = BASE | INIT1; | ||
699 | if (priv->ctrl.type == XC2028_FIRM_MTS) | ||
700 | type0 |= MTS; | ||
701 | 698 | ||
702 | /* FIXME: Should handle errors - if INIT1 found */ | 699 | rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &new_fw.id); |
703 | rc = load_firmware(fe, type0, &std0); | 700 | if (rc < 0 && rc != -ENOENT) { |
701 | tuner_err("Error %d while loading init1 firmware\n", | ||
702 | rc); | ||
703 | goto fail; | ||
704 | } | ||
704 | 705 | ||
705 | /* FIXME: Should add support for FM radio | 706 | skip_base: |
707 | /* | ||
708 | * No need to reload standard specific firmware if base firmware | ||
709 | * was not reloaded and requested video standards have not changed. | ||
706 | */ | 710 | */ |
707 | 711 | if (priv->cur_fw.type == (BASE | new_fw.type) && | |
708 | if (priv->ctrl.type == XC2028_FIRM_MTS) | 712 | priv->cur_fw.std_req == std) { |
709 | type |= MTS; | ||
710 | |||
711 | if (priv->firm_type & std) { | ||
712 | tuner_dbg("Std-specific firmware already loaded.\n"); | 713 | tuner_dbg("Std-specific firmware already loaded.\n"); |
713 | return 0; | 714 | goto skip_std_specific; |
714 | } | 715 | } |
715 | 716 | ||
717 | /* Reloading std-specific firmware forces a SCODE update */ | ||
718 | priv->cur_fw.scode_table = 0; | ||
719 | |||
716 | /* Add audio hack to std mask */ | 720 | /* Add audio hack to std mask */ |
717 | std |= parse_audio_std_option(); | 721 | if (new_mode == T_ANALOG_TV) |
722 | new_fw.id |= parse_audio_std_option(); | ||
718 | 723 | ||
719 | rc = load_firmware(fe, type, &std); | 724 | rc = load_firmware(fe, new_fw.type, &new_fw.id); |
720 | if (rc < 0) | 725 | if (rc < 0) |
721 | return rc; | 726 | goto fail; |
727 | |||
728 | skip_std_specific: | ||
729 | if (priv->cur_fw.scode_table == new_fw.scode_table && | ||
730 | priv->cur_fw.scode_nr == new_fw.scode_nr) { | ||
731 | tuner_dbg("SCODE firmware already loaded.\n"); | ||
732 | goto check_device; | ||
733 | } | ||
722 | 734 | ||
723 | /* Load SCODE firmware, if exists */ | 735 | /* Load SCODE firmware, if exists */ |
724 | tuner_dbg("Trying to load scode 0\n"); | 736 | tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr); |
725 | type |= SCODE; | ||
726 | 737 | ||
727 | rc = load_scode(fe, type, &std, 0); | 738 | rc = load_scode(fe, new_fw.type | new_fw.scode_table, |
739 | &new_fw.id, new_fw.scode_nr); | ||
728 | 740 | ||
741 | check_device: | ||
729 | xc2028_get_reg(priv, 0x0004, &version); | 742 | xc2028_get_reg(priv, 0x0004, &version); |
730 | xc2028_get_reg(priv, 0x0008, &hwmodel); | 743 | xc2028_get_reg(priv, 0x0008, &hwmodel); |
731 | 744 | ||
@@ -734,9 +747,23 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, | |||
734 | hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, | 747 | hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, |
735 | (version & 0xf0) >> 4, version & 0xf); | 748 | (version & 0xf0) >> 4, version & 0xf); |
736 | 749 | ||
737 | priv->firm_type = std; | 750 | memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); |
751 | |||
752 | /* | ||
753 | * By setting BASE in cur_fw.type only after successfully loading all | ||
754 | * firmwares, we can: | ||
755 | * 1. Identify that BASE firmware with type=0 has been loaded; | ||
756 | * 2. Tell whether BASE firmware was just changed the next time through. | ||
757 | */ | ||
758 | priv->cur_fw.type |= BASE; | ||
738 | 759 | ||
739 | return 0; | 760 | return 0; |
761 | |||
762 | fail: | ||
763 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); | ||
764 | if (rc == -ENOENT) | ||
765 | rc = -EINVAL; | ||
766 | return rc; | ||
740 | } | 767 | } |
741 | 768 | ||
742 | static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) | 769 | static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) |
@@ -785,16 +812,10 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , | |||
785 | mutex_lock(&priv->lock); | 812 | mutex_lock(&priv->lock); |
786 | 813 | ||
787 | /* HACK: It seems that specific firmware need to be reloaded | 814 | /* HACK: It seems that specific firmware need to be reloaded |
788 | when freq is changed */ | 815 | when watching analog TV and freq is changed */ |
789 | 816 | if (new_mode != T_DIGITAL_TV) | |
790 | priv->firm_type = 0; | 817 | priv->cur_fw.type = 0; |
791 | |||
792 | /* Reset GPIO 1 */ | ||
793 | rc = priv->tuner_callback(priv->video_dev, XC2028_TUNER_RESET, 0); | ||
794 | if (rc < 0) | ||
795 | goto ret; | ||
796 | 818 | ||
797 | msleep(10); | ||
798 | tuner_dbg("should set frequency %d kHz\n", freq / 1000); | 819 | tuner_dbg("should set frequency %d kHz\n", freq / 1000); |
799 | 820 | ||
800 | if (check_firmware(fe, new_mode, std, bandwidth) < 0) | 821 | if (check_firmware(fe, new_mode, std, bandwidth) < 0) |
@@ -802,7 +823,7 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , | |||
802 | 823 | ||
803 | if (new_mode == T_DIGITAL_TV) { | 824 | if (new_mode == T_DIGITAL_TV) { |
804 | offset = 2750000; | 825 | offset = 2750000; |
805 | if (priv->bandwidth == BANDWIDTH_7_MHZ) | 826 | if (priv->cur_fw.type & DTV7) |
806 | offset -= 500000; | 827 | offset -= 500000; |
807 | } | 828 | } |
808 | 829 | ||
@@ -994,9 +1015,6 @@ void *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg) | |||
994 | return NULL; | 1015 | return NULL; |
995 | } | 1016 | } |
996 | 1017 | ||
997 | priv->bandwidth = BANDWIDTH_6_MHZ; | ||
998 | priv->need_load_generic = 1; | ||
999 | priv->mode = T_UNINITIALIZED; | ||
1000 | priv->i2c_props.addr = cfg->i2c_addr; | 1018 | priv->i2c_props.addr = cfg->i2c_addr; |
1001 | priv->i2c_props.adap = cfg->i2c_adap; | 1019 | priv->i2c_props.adap = cfg->i2c_adap; |
1002 | priv->video_dev = video_dev; | 1020 | priv->video_dev = video_dev; |
diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index 4edc4b735c84..16259b14ce90 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h | |||
@@ -21,6 +21,7 @@ struct xc2028_ctrl { | |||
21 | char *fname; | 21 | char *fname; |
22 | int max_len; | 22 | int max_len; |
23 | int d2633:1; | 23 | int d2633:1; |
24 | unsigned int scode_table; | ||
24 | }; | 25 | }; |
25 | 26 | ||
26 | struct xc2028_config { | 27 | struct xc2028_config { |