diff options
Diffstat (limited to 'drivers/media/common/tuners/xc4000.c')
-rw-r--r-- | drivers/media/common/tuners/xc4000.c | 424 |
1 files changed, 393 insertions, 31 deletions
diff --git a/drivers/media/common/tuners/xc4000.c b/drivers/media/common/tuners/xc4000.c index 68f5e2beee1e..98ec80abb047 100644 --- a/drivers/media/common/tuners/xc4000.c +++ b/drivers/media/common/tuners/xc4000.c | |||
@@ -28,11 +28,13 @@ | |||
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/dvb/frontend.h> | 29 | #include <linux/dvb/frontend.h> |
30 | #include <linux/i2c.h> | 30 | #include <linux/i2c.h> |
31 | #include <asm/unaligned.h> | ||
31 | 32 | ||
32 | #include "dvb_frontend.h" | 33 | #include "dvb_frontend.h" |
33 | 34 | ||
34 | #include "xc4000.h" | 35 | #include "xc4000.h" |
35 | #include "tuner-i2c.h" | 36 | #include "tuner-i2c.h" |
37 | #include "tuner-xc2028-types.h" | ||
36 | 38 | ||
37 | static int debug; | 39 | static int debug; |
38 | module_param(debug, int, 0644); | 40 | module_param(debug, int, 0644); |
@@ -50,13 +52,34 @@ static LIST_HEAD(hybrid_tuner_instance_list); | |||
50 | #define dprintk(level, fmt, arg...) if (debug >= level) \ | 52 | #define dprintk(level, fmt, arg...) if (debug >= level) \ |
51 | printk(KERN_INFO "%s: " fmt, "xc4000", ## arg) | 53 | printk(KERN_INFO "%s: " fmt, "xc4000", ## arg) |
52 | 54 | ||
53 | #define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.26.fw" | 55 | #define XC4000_DEFAULT_FIRMWARE "xc4000-01.fw" |
54 | #define XC4000_DEFAULT_FIRMWARE_SIZE 8236 | 56 | #define XC4000_DEFAULT_FIRMWARE_SIZE 8434 |
57 | |||
58 | |||
59 | /* struct for storing firmware table */ | ||
60 | struct firmware_description { | ||
61 | unsigned int type; | ||
62 | v4l2_std_id id; | ||
63 | __u16 int_freq; | ||
64 | unsigned char *ptr; | ||
65 | unsigned int size; | ||
66 | }; | ||
67 | |||
68 | struct firmware_properties { | ||
69 | unsigned int type; | ||
70 | v4l2_std_id id; | ||
71 | v4l2_std_id std_req; | ||
72 | __u16 int_freq; | ||
73 | unsigned int scode_table; | ||
74 | int scode_nr; | ||
75 | }; | ||
55 | 76 | ||
56 | struct xc4000_priv { | 77 | struct xc4000_priv { |
57 | struct tuner_i2c_props i2c_props; | 78 | struct tuner_i2c_props i2c_props; |
58 | struct list_head hybrid_tuner_instance_list; | 79 | struct list_head hybrid_tuner_instance_list; |
59 | 80 | struct firmware_description *firm; | |
81 | int firm_size; | ||
82 | __u16 firm_version; | ||
60 | u32 if_khz; | 83 | u32 if_khz; |
61 | u32 freq_hz; | 84 | u32 freq_hz; |
62 | u32 bandwidth; | 85 | u32 bandwidth; |
@@ -167,10 +190,6 @@ struct XC_TV_STANDARD { | |||
167 | #define DK_SECAM_A2MONO 14 | 190 | #define DK_SECAM_A2MONO 14 |
168 | #define L_SECAM_NICAM 15 | 191 | #define L_SECAM_NICAM 15 |
169 | #define LC_SECAM_NICAM 16 | 192 | #define LC_SECAM_NICAM 16 |
170 | #define DTV6 17 | ||
171 | #define DTV8 18 | ||
172 | #define DTV7_8 19 | ||
173 | #define DTV7 20 | ||
174 | #define FM_Radio_INPUT2 21 | 193 | #define FM_Radio_INPUT2 21 |
175 | #define FM_Radio_INPUT1 22 | 194 | #define FM_Radio_INPUT1 22 |
176 | 195 | ||
@@ -575,42 +594,358 @@ static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val) | |||
575 | return XC_RESULT_SUCCESS; | 594 | return XC_RESULT_SUCCESS; |
576 | } | 595 | } |
577 | 596 | ||
597 | |||
598 | static int seek_firmware(struct dvb_frontend *fe, unsigned int type, | ||
599 | v4l2_std_id *id) | ||
600 | { | ||
601 | struct xc4000_priv *priv = fe->tuner_priv; | ||
602 | int i, best_i = -1, best_nr_matches = 0; | ||
603 | unsigned int type_mask = 0; | ||
604 | |||
605 | printk("%s called, want type=", __func__); | ||
606 | if (debug) { | ||
607 | // dump_firm_type(type); | ||
608 | printk("(%x), id %016llx.\n", type, (unsigned long long)*id); | ||
609 | } | ||
610 | |||
611 | if (!priv->firm) { | ||
612 | printk("Error! firmware not loaded\n"); | ||
613 | return -EINVAL; | ||
614 | } | ||
615 | |||
616 | if (((type & ~SCODE) == 0) && (*id == 0)) | ||
617 | *id = V4L2_STD_PAL; | ||
618 | |||
619 | if (type & BASE) | ||
620 | type_mask = BASE_TYPES; | ||
621 | else if (type & SCODE) { | ||
622 | type &= SCODE_TYPES; | ||
623 | type_mask = SCODE_TYPES & ~HAS_IF; | ||
624 | } else if (type & DTV_TYPES) | ||
625 | type_mask = DTV_TYPES; | ||
626 | else if (type & STD_SPECIFIC_TYPES) | ||
627 | type_mask = STD_SPECIFIC_TYPES; | ||
628 | |||
629 | type &= type_mask; | ||
630 | |||
631 | if (!(type & SCODE)) | ||
632 | type_mask = ~0; | ||
633 | |||
634 | /* Seek for exact match */ | ||
635 | for (i = 0; i < priv->firm_size; i++) { | ||
636 | if ((type == (priv->firm[i].type & type_mask)) && | ||
637 | (*id == priv->firm[i].id)) | ||
638 | goto found; | ||
639 | } | ||
640 | |||
641 | /* Seek for generic video standard match */ | ||
642 | for (i = 0; i < priv->firm_size; i++) { | ||
643 | v4l2_std_id match_mask; | ||
644 | int nr_matches; | ||
645 | |||
646 | if (type != (priv->firm[i].type & type_mask)) | ||
647 | continue; | ||
648 | |||
649 | match_mask = *id & priv->firm[i].id; | ||
650 | if (!match_mask) | ||
651 | continue; | ||
652 | |||
653 | if ((*id & match_mask) == *id) | ||
654 | goto found; /* Supports all the requested standards */ | ||
655 | |||
656 | nr_matches = hweight64(match_mask); | ||
657 | if (nr_matches > best_nr_matches) { | ||
658 | best_nr_matches = nr_matches; | ||
659 | best_i = i; | ||
660 | } | ||
661 | } | ||
662 | |||
663 | if (best_nr_matches > 0) { | ||
664 | printk("Selecting best matching firmware (%d bits) for " | ||
665 | "type=", best_nr_matches); | ||
666 | // dump_firm_type(type); | ||
667 | printk("(%x), id %016llx:\n", type, (unsigned long long)*id); | ||
668 | i = best_i; | ||
669 | goto found; | ||
670 | } | ||
671 | |||
672 | /*FIXME: Would make sense to seek for type "hint" match ? */ | ||
673 | |||
674 | i = -ENOENT; | ||
675 | goto ret; | ||
676 | |||
677 | found: | ||
678 | *id = priv->firm[i].id; | ||
679 | |||
680 | ret: | ||
681 | printk("%s firmware for type=", (i < 0) ? "Can't find" : "Found"); | ||
682 | if (debug) { | ||
683 | // dump_firm_type(type); | ||
684 | printk("(%x), id %016llx.\n", type, (unsigned long long)*id); | ||
685 | } | ||
686 | return i; | ||
687 | } | ||
688 | |||
689 | static int load_firmware(struct dvb_frontend *fe, unsigned int type, | ||
690 | v4l2_std_id *id) | ||
691 | { | ||
692 | struct xc4000_priv *priv = fe->tuner_priv; | ||
693 | int pos, rc; | ||
694 | unsigned char *p, *endp, buf[XC_MAX_I2C_WRITE_LENGTH]; | ||
695 | |||
696 | printk("%s called\n", __func__); | ||
697 | |||
698 | pos = seek_firmware(fe, type, id); | ||
699 | if (pos < 0) | ||
700 | return pos; | ||
701 | |||
702 | printk("Loading firmware for type="); | ||
703 | // dump_firm_type(priv->firm[pos].type); | ||
704 | printk("(%x), id %016llx.\n", priv->firm[pos].type, | ||
705 | (unsigned long long)*id); | ||
706 | |||
707 | p = priv->firm[pos].ptr; | ||
708 | endp = p + priv->firm[pos].size; | ||
709 | |||
710 | while (p < endp) { | ||
711 | __u16 size; | ||
712 | |||
713 | printk("block %02x %02x %02x %02x %02x %02x\n", p[0], p[1], p[2], p[3], p[4], p[5]); | ||
714 | |||
715 | /* Checks if there's enough bytes to read */ | ||
716 | if (p + sizeof(size) > endp) { | ||
717 | printk("Firmware chunk size is wrong\n"); | ||
718 | return -EINVAL; | ||
719 | } | ||
720 | |||
721 | size = be16_to_cpu(*(__u16 *) p); | ||
722 | p += sizeof(size); | ||
723 | |||
724 | printk("djh size=%x\n", size); | ||
725 | |||
726 | if (size == 0xffff) | ||
727 | return 0; | ||
728 | |||
729 | if (!size) { | ||
730 | /* Special callback command received */ | ||
731 | rc = xc4000_TunerReset(fe); | ||
732 | if (rc != XC_RESULT_SUCCESS) { | ||
733 | printk("Error at RESET code %d\n", | ||
734 | (*p) & 0x7f); | ||
735 | return -EINVAL; | ||
736 | } | ||
737 | continue; | ||
738 | } | ||
739 | if (size >= 0xff00) { | ||
740 | switch (size) { | ||
741 | #ifdef DJH_XXX | ||
742 | case 0xff00: | ||
743 | rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0); | ||
744 | if (rc < 0) { | ||
745 | printk("Error at RESET code %d\n", | ||
746 | (*p) & 0x7f); | ||
747 | return -EINVAL; | ||
748 | } | ||
749 | break; | ||
750 | #endif | ||
751 | default: | ||
752 | printk("Invalid RESET code %d\n", | ||
753 | size & 0x7f); | ||
754 | return -EINVAL; | ||
755 | |||
756 | } | ||
757 | continue; | ||
758 | } | ||
759 | |||
760 | /* Checks for a sleep command */ | ||
761 | if (size & 0x8000) { | ||
762 | printk("djh doing msleep for %x\n", (size & 0x7fff)); | ||
763 | msleep(size & 0x7fff); | ||
764 | continue; | ||
765 | } | ||
766 | |||
767 | if ((size + p > endp)) { | ||
768 | printk("missing bytes: need %d, have %d\n", | ||
769 | size, (int)(endp - p)); | ||
770 | return -EINVAL; | ||
771 | } | ||
772 | |||
773 | buf[0] = *p; | ||
774 | p++; | ||
775 | size--; | ||
776 | |||
777 | /* Sends message chunks */ | ||
778 | printk("djh final size %d\n", size); | ||
779 | while (size > 0) { | ||
780 | int len = (size < XC_MAX_I2C_WRITE_LENGTH - 1) ? | ||
781 | size : XC_MAX_I2C_WRITE_LENGTH - 1; | ||
782 | |||
783 | memcpy(buf + 1, p, len); | ||
784 | |||
785 | // rc = i2c_send(priv, buf, len + 1); | ||
786 | printk("djh sending %d\n", len + 1); | ||
787 | rc = xc_send_i2c_data(priv, buf, len + 1); | ||
788 | if (rc < 0) { | ||
789 | printk("%d returned from send\n", rc); | ||
790 | return -EINVAL; | ||
791 | } | ||
792 | |||
793 | p += len; | ||
794 | size -= len; | ||
795 | } | ||
796 | } | ||
797 | return 0; | ||
798 | } | ||
799 | |||
800 | //static int load_all_firmwares(struct dvb_frontend *fe) | ||
578 | static int xc4000_fwupload(struct dvb_frontend *fe) | 801 | static int xc4000_fwupload(struct dvb_frontend *fe) |
579 | { | 802 | { |
580 | struct xc4000_priv *priv = fe->tuner_priv; | 803 | struct xc4000_priv *priv = fe->tuner_priv; |
581 | const struct firmware *fw; | 804 | const struct firmware *fw = NULL; |
582 | int ret; | 805 | const unsigned char *p, *endp; |
806 | int rc = 0; | ||
807 | int n, n_array; | ||
808 | char name[33]; | ||
809 | char *fname; | ||
810 | |||
811 | printk("%s called\n", __func__); | ||
812 | |||
813 | fname = XC4000_DEFAULT_FIRMWARE; | ||
814 | |||
815 | printk("Reading firmware %s\n", fname); | ||
816 | rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent); | ||
817 | if (rc < 0) { | ||
818 | if (rc == -ENOENT) | ||
819 | printk("Error: firmware %s not found.\n", | ||
820 | fname); | ||
821 | else | ||
822 | printk("Error %d while requesting firmware %s \n", | ||
823 | rc, fname); | ||
583 | 824 | ||
584 | /* request the firmware, this will block and timeout */ | 825 | return rc; |
585 | printk(KERN_INFO "xc4000: waiting for firmware upload (%s)...\n", | 826 | } |
586 | XC4000_DEFAULT_FIRMWARE); | 827 | p = fw->data; |
828 | endp = p + fw->size; | ||
587 | 829 | ||
588 | ret = request_firmware(&fw, XC4000_DEFAULT_FIRMWARE, | 830 | if (fw->size < sizeof(name) - 1 + 2 + 2) { |
589 | priv->i2c_props.adap->dev.parent); | 831 | printk("Error: firmware file %s has invalid size!\n", |
590 | if (ret) { | 832 | fname); |
591 | printk(KERN_ERR "xc4000: Upload failed. (file not found?)\n"); | 833 | goto corrupt; |
592 | ret = XC_RESULT_RESET_FAILURE; | ||
593 | goto out; | ||
594 | } else { | ||
595 | printk(KERN_DEBUG "xc4000: firmware read %Zu bytes.\n", | ||
596 | fw->size); | ||
597 | ret = XC_RESULT_SUCCESS; | ||
598 | } | 834 | } |
599 | 835 | ||
600 | if (fw->size != XC4000_DEFAULT_FIRMWARE_SIZE) { | 836 | memcpy(name, p, sizeof(name) - 1); |
601 | printk(KERN_ERR "xc4000: firmware incorrect size\n"); | 837 | name[sizeof(name) - 1] = 0; |
602 | ret = XC_RESULT_RESET_FAILURE; | 838 | p += sizeof(name) - 1; |
603 | } else { | 839 | |
604 | printk(KERN_INFO "xc4000: firmware uploading...\n"); | 840 | priv->firm_version = get_unaligned_le16(p); |
605 | ret = xc_load_i2c_sequence(fe, fw->data); | 841 | p += 2; |
606 | printk(KERN_INFO "xc4000: firmware upload complete...\n"); | 842 | |
843 | n_array = get_unaligned_le16(p); | ||
844 | p += 2; | ||
845 | |||
846 | printk("Loading %d firmware images from %s, type: %s, ver %d.%d\n", | ||
847 | n_array, fname, name, | ||
848 | priv->firm_version >> 8, priv->firm_version & 0xff); | ||
849 | |||
850 | priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); | ||
851 | if (priv->firm == NULL) { | ||
852 | printk("Not enough memory to load firmware file.\n"); | ||
853 | rc = -ENOMEM; | ||
854 | goto err; | ||
855 | } | ||
856 | priv->firm_size = n_array; | ||
857 | |||
858 | n = -1; | ||
859 | while (p < endp) { | ||
860 | __u32 type, size; | ||
861 | v4l2_std_id id; | ||
862 | __u16 int_freq = 0; | ||
863 | |||
864 | n++; | ||
865 | if (n >= n_array) { | ||
866 | printk("More firmware images in file than " | ||
867 | "were expected!\n"); | ||
868 | goto corrupt; | ||
869 | } | ||
870 | |||
871 | /* Checks if there's enough bytes to read */ | ||
872 | if (endp - p < sizeof(type) + sizeof(id) + sizeof(size)) | ||
873 | goto header; | ||
874 | |||
875 | type = get_unaligned_le32(p); | ||
876 | p += sizeof(type); | ||
877 | |||
878 | id = get_unaligned_le64(p); | ||
879 | p += sizeof(id); | ||
880 | |||
881 | if (type & HAS_IF) { | ||
882 | int_freq = get_unaligned_le16(p); | ||
883 | p += sizeof(int_freq); | ||
884 | if (endp - p < sizeof(size)) | ||
885 | goto header; | ||
886 | } | ||
887 | |||
888 | size = get_unaligned_le32(p); | ||
889 | p += sizeof(size); | ||
890 | |||
891 | if (!size || size > endp - p) { | ||
892 | printk("Firmware type "); | ||
893 | // dump_firm_type(type); | ||
894 | printk("(%x), id %llx is corrupted " | ||
895 | "(size=%d, expected %d)\n", | ||
896 | type, (unsigned long long)id, | ||
897 | (unsigned)(endp - p), size); | ||
898 | goto corrupt; | ||
899 | } | ||
900 | |||
901 | priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); | ||
902 | if (priv->firm[n].ptr == NULL) { | ||
903 | printk("Not enough memory to load firmware file.\n"); | ||
904 | rc = -ENOMEM; | ||
905 | goto err; | ||
906 | } | ||
907 | printk("Reading firmware type "); | ||
908 | if (debug) { | ||
909 | // dump_firm_type_and_int_freq(type, int_freq); | ||
910 | printk("(%x), id %llx, size=%d.\n", | ||
911 | type, (unsigned long long)id, size); | ||
912 | } | ||
913 | |||
914 | memcpy(priv->firm[n].ptr, p, size); | ||
915 | priv->firm[n].type = type; | ||
916 | priv->firm[n].id = id; | ||
917 | priv->firm[n].size = size; | ||
918 | priv->firm[n].int_freq = int_freq; | ||
919 | |||
920 | p += size; | ||
607 | } | 921 | } |
608 | 922 | ||
609 | out: | 923 | if (n + 1 != priv->firm_size) { |
924 | printk("Firmware file is incomplete!\n"); | ||
925 | goto corrupt; | ||
926 | } | ||
927 | |||
928 | goto done; | ||
929 | |||
930 | header: | ||
931 | printk("Firmware header is incomplete!\n"); | ||
932 | corrupt: | ||
933 | rc = -EINVAL; | ||
934 | printk("Error: firmware file is corrupted!\n"); | ||
935 | |||
936 | err: | ||
937 | printk("Releasing partially loaded firmware file.\n"); | ||
938 | // free_firmware(priv); | ||
939 | |||
940 | done: | ||
610 | release_firmware(fw); | 941 | release_firmware(fw); |
611 | return ret; | 942 | if (rc == 0) |
943 | printk("Firmware files loaded.\n"); | ||
944 | |||
945 | return rc; | ||
612 | } | 946 | } |
613 | 947 | ||
948 | |||
614 | static void xc_debug_dump(struct xc4000_priv *priv) | 949 | static void xc_debug_dump(struct xc4000_priv *priv) |
615 | { | 950 | { |
616 | u16 adc_envelope; | 951 | u16 adc_envelope; |
@@ -1002,7 +1337,9 @@ struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, | |||
1002 | { | 1337 | { |
1003 | struct xc4000_priv *priv = NULL; | 1338 | struct xc4000_priv *priv = NULL; |
1004 | int instance; | 1339 | int instance; |
1340 | v4l2_std_id std0; | ||
1005 | u16 id = 0; | 1341 | u16 id = 0; |
1342 | int rc; | ||
1006 | 1343 | ||
1007 | dprintk(1, "%s(%d-%04x)\n", __func__, | 1344 | dprintk(1, "%s(%d-%04x)\n", __func__, |
1008 | i2c ? i2c_adapter_id(i2c) : -1, | 1345 | i2c ? i2c_adapter_id(i2c) : -1, |
@@ -1069,6 +1406,31 @@ struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, | |||
1069 | memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops, | 1406 | memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops, |
1070 | sizeof(struct dvb_tuner_ops)); | 1407 | sizeof(struct dvb_tuner_ops)); |
1071 | 1408 | ||
1409 | /* FIXME: For now, load the firmware at startup. We will remove this | ||
1410 | before the code goes to production... */ | ||
1411 | xc4000_fwupload(fe); | ||
1412 | printk("xc4000_fwupload done\n"); | ||
1413 | |||
1414 | std0 = 0; | ||
1415 | // rc = load_firmware(fe, BASE | new_fw.type, &std0); | ||
1416 | rc = load_firmware(fe, BASE, &std0); | ||
1417 | if (rc < 0) { | ||
1418 | tuner_err("Error %d while loading base firmware\n", | ||
1419 | rc); | ||
1420 | goto fail; | ||
1421 | } | ||
1422 | |||
1423 | /* Load INIT1, if needed */ | ||
1424 | tuner_dbg("Load init1 firmware, if exists\n"); | ||
1425 | |||
1426 | // rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0); | ||
1427 | rc = load_firmware(fe, INIT1, &std0); | ||
1428 | printk("init1 load result %x\n", rc); | ||
1429 | |||
1430 | if (xc4000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS) | ||
1431 | goto fail; | ||
1432 | printk("djh id is now %x\n", id); | ||
1433 | |||
1072 | return fe; | 1434 | return fe; |
1073 | fail: | 1435 | fail: |
1074 | mutex_unlock(&xc4000_list_mutex); | 1436 | mutex_unlock(&xc4000_list_mutex); |