aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/tuner-xc2028.c
diff options
context:
space:
mode:
authorChris Pascoe <c.pascoe@itee.uq.edu.au>2007-11-19 09:35:45 -0500
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-01-25 16:02:31 -0500
commit8bf799a6217f6336fb95f37bf1b130003404bd7b (patch)
tree6a184fca900c1c63aa65976d5aac0237536e5e67 /drivers/media/video/tuner-xc2028.c
parente0f0b37a3e624440b1b0e8a5978b367895226e75 (diff)
V4L/DVB (6647): xc2028: retry firmware load if tuner does not respond
In practice, the tuner occasionally fails to respond correctly after a firmware load. Retry the firmware load if the firmware/hardware version we read back from the tuner after programming does not match what we expect. Signed-off-by: Chris Pascoe <c.pascoe@itee.uq.edu.au> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/tuner-xc2028.c')
-rw-r--r--drivers/media/video/tuner-xc2028.c37
1 files changed, 34 insertions, 3 deletions
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c
index 8140d8ad0792..cc6fa2fa859b 100644
--- a/drivers/media/video/tuner-xc2028.c
+++ b/drivers/media/video/tuner-xc2028.c
@@ -75,6 +75,9 @@ struct xc2028_data {
75 int firm_size; 75 int firm_size;
76 __u16 firm_version; 76 __u16 firm_version;
77 77
78 __u16 hwmodel;
79 __u16 hwvers;
80
78 struct xc2028_ctrl ctrl; 81 struct xc2028_ctrl ctrl;
79 82
80 struct firmware_properties cur_fw; 83 struct firmware_properties cur_fw;
@@ -607,7 +610,7 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
607 v4l2_std_id std, fe_bandwidth_t bandwidth) 610 v4l2_std_id std, fe_bandwidth_t bandwidth)
608{ 611{
609 struct xc2028_data *priv = fe->tuner_priv; 612 struct xc2028_data *priv = fe->tuner_priv;
610 int rc = 0; 613 int rc = 0, is_retry = 0;
611 unsigned int type = 0; 614 unsigned int type = 0;
612 struct firmware_properties new_fw; 615 struct firmware_properties new_fw;
613 u16 version, hwmodel; 616 u16 version, hwmodel;
@@ -654,6 +657,7 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
654 }; 657 };
655 } 658 }
656 659
660retry:
657 new_fw.type = type; 661 new_fw.type = type;
658 new_fw.id = std; 662 new_fw.id = std;
659 new_fw.std_req = std; 663 new_fw.std_req = std;
@@ -739,14 +743,34 @@ skip_std_specific:
739 &new_fw.id, new_fw.scode_nr); 743 &new_fw.id, new_fw.scode_nr);
740 744
741check_device: 745check_device:
742 xc2028_get_reg(priv, 0x0004, &version); 746 if (xc2028_get_reg(priv, 0x0004, &version) < 0 ||
743 xc2028_get_reg(priv, 0x0008, &hwmodel); 747 xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) {
748 tuner_err("Unable to read tuner registers.\n");
749 goto fail;
750 }
744 751
745 tuner_info("Device is Xceive %d version %d.%d, " 752 tuner_info("Device is Xceive %d version %d.%d, "
746 "firmware version %d.%d\n", 753 "firmware version %d.%d\n",
747 hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, 754 hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
748 (version & 0xf0) >> 4, version & 0xf); 755 (version & 0xf0) >> 4, version & 0xf);
749 756
757 /* Check firmware version against what we downloaded. */
758 if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) {
759 tuner_err("Incorrect readback of firmware version.\n");
760 goto fail;
761 }
762
763 /* Check that the tuner hardware model remains consistent over time. */
764 if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) {
765 priv->hwmodel = hwmodel;
766 priv->hwvers = version & 0xff00;
767 } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
768 priv->hwvers != (version & 0xff00)) {
769 tuner_err("Read invalid device hardware information - tuner "
770 "hung?\n");
771 goto fail;
772 }
773
750 memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); 774 memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
751 775
752 /* 776 /*
@@ -761,6 +785,13 @@ check_device:
761 785
762fail: 786fail:
763 memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); 787 memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
788 if (!is_retry) {
789 msleep(50);
790 is_retry = 1;
791 tuner_dbg("Retrying firmware load\n");
792 goto retry;
793 }
794
764 if (rc == -ENOENT) 795 if (rc == -ENOENT)
765 rc = -EINVAL; 796 rc = -EINVAL;
766 return rc; 797 return rc;