aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/tuner-xc2028-types.h8
-rw-r--r--drivers/media/video/tuner-xc2028.c212
-rw-r--r--drivers/media/video/tuner-xc2028.h1
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
57struct 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
57struct xc2028_data { 65struct 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
240static int load_all_firmwares(struct dvb_frontend *fe) 242static 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 706skip_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
728skip_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
741check_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
762fail:
763 memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
764 if (rc == -ENOENT)
765 rc = -EINVAL;
766 return rc;
740} 767}
741 768
742static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) 769static 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
26struct xc2028_config { 27struct xc2028_config {