diff options
author | Devin Heitmueller <dheitmueller@kernellabs.com> | 2012-08-06 21:47:09 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-09 19:56:45 -0400 |
commit | 22d5c6f585352566ab4161d9aa7936100f94af05 (patch) | |
tree | d7ebb3accc98a2fdd1d6bc719576f62d83c9df70 /drivers/media/common/tuners/xc5000.c | |
parent | de49bc6ee9c38ac73abf41f3874918d930b2d985 (diff) |
[media] xc5000: add support for firmware load check and init status
The xc5000c and newer versions of the xc5000a firmware need minor revisions
to their initialization process. Add support for validating the firmware
was properly loaded, as well as checking the init status after initialization.
Based on advice from CrestaTech support as well as xc5000 datasheet v2.3.
Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/common/tuners/xc5000.c')
-rw-r--r-- | drivers/media/common/tuners/xc5000.c | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c index cd92b9e1ccdd..b488c0e1bcd7 100644 --- a/drivers/media/common/tuners/xc5000.c +++ b/drivers/media/common/tuners/xc5000.c | |||
@@ -63,6 +63,8 @@ struct xc5000_priv { | |||
63 | 63 | ||
64 | int chip_id; | 64 | int chip_id; |
65 | u16 pll_register_no; | 65 | u16 pll_register_no; |
66 | u8 init_status_supported; | ||
67 | u8 fw_checksum_supported; | ||
66 | }; | 68 | }; |
67 | 69 | ||
68 | /* Misc Defines */ | 70 | /* Misc Defines */ |
@@ -113,6 +115,8 @@ struct xc5000_priv { | |||
113 | #define XREG_BUSY 0x09 | 115 | #define XREG_BUSY 0x09 |
114 | #define XREG_BUILD 0x0D | 116 | #define XREG_BUILD 0x0D |
115 | #define XREG_TOTALGAIN 0x0F | 117 | #define XREG_TOTALGAIN 0x0F |
118 | #define XREG_FW_CHECKSUM 0x12 | ||
119 | #define XREG_INIT_STATUS 0x13 | ||
116 | 120 | ||
117 | /* | 121 | /* |
118 | Basic firmware description. This will remain with | 122 | Basic firmware description. This will remain with |
@@ -211,6 +215,8 @@ struct xc5000_fw_cfg { | |||
211 | char *name; | 215 | char *name; |
212 | u16 size; | 216 | u16 size; |
213 | u16 pll_reg; | 217 | u16 pll_reg; |
218 | u8 init_status_supported; | ||
219 | u8 fw_checksum_supported; | ||
214 | }; | 220 | }; |
215 | 221 | ||
216 | #define XC5000A_FIRMWARE "dvb-fe-xc5000-1.6.114.fw" | 222 | #define XC5000A_FIRMWARE "dvb-fe-xc5000-1.6.114.fw" |
@@ -225,6 +231,8 @@ static const struct xc5000_fw_cfg xc5000c_41_024_5 = { | |||
225 | .name = XC5000C_FIRMWARE, | 231 | .name = XC5000C_FIRMWARE, |
226 | .size = 16497, | 232 | .size = 16497, |
227 | .pll_reg = 0x13, | 233 | .pll_reg = 0x13, |
234 | .init_status_supported = 1, | ||
235 | .fw_checksum_supported = 1, | ||
228 | }; | 236 | }; |
229 | 237 | ||
230 | static inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id) | 238 | static inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id) |
@@ -624,6 +632,8 @@ static int xc5000_fwupload(struct dvb_frontend *fe) | |||
624 | const struct xc5000_fw_cfg *desired_fw = | 632 | const struct xc5000_fw_cfg *desired_fw = |
625 | xc5000_assign_firmware(priv->chip_id); | 633 | xc5000_assign_firmware(priv->chip_id); |
626 | priv->pll_register_no = desired_fw->pll_reg; | 634 | priv->pll_register_no = desired_fw->pll_reg; |
635 | priv->init_status_supported = desired_fw->init_status_supported; | ||
636 | priv->fw_checksum_supported = desired_fw->fw_checksum_supported; | ||
627 | 637 | ||
628 | /* request the firmware, this will block and timeout */ | 638 | /* request the firmware, this will block and timeout */ |
629 | printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", | 639 | printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", |
@@ -1090,6 +1100,7 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force) | |||
1090 | struct xc5000_priv *priv = fe->tuner_priv; | 1100 | struct xc5000_priv *priv = fe->tuner_priv; |
1091 | int ret = XC_RESULT_SUCCESS; | 1101 | int ret = XC_RESULT_SUCCESS; |
1092 | u16 pll_lock_status; | 1102 | u16 pll_lock_status; |
1103 | u16 fw_ck; | ||
1093 | 1104 | ||
1094 | if (force || xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) { | 1105 | if (force || xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) { |
1095 | 1106 | ||
@@ -1101,6 +1112,21 @@ fw_retry: | |||
1101 | 1112 | ||
1102 | msleep(20); | 1113 | msleep(20); |
1103 | 1114 | ||
1115 | if (priv->fw_checksum_supported) { | ||
1116 | if (xc5000_readreg(priv, XREG_FW_CHECKSUM, &fw_ck) | ||
1117 | != XC_RESULT_SUCCESS) { | ||
1118 | dprintk(1, "%s() FW checksum reading failed.\n", | ||
1119 | __func__); | ||
1120 | goto fw_retry; | ||
1121 | } | ||
1122 | |||
1123 | if (fw_ck == 0) { | ||
1124 | dprintk(1, "%s() FW checksum failed = 0x%04x\n", | ||
1125 | __func__, fw_ck); | ||
1126 | goto fw_retry; | ||
1127 | } | ||
1128 | } | ||
1129 | |||
1104 | /* Start the tuner self-calibration process */ | 1130 | /* Start the tuner self-calibration process */ |
1105 | ret |= xc_initialize(priv); | 1131 | ret |= xc_initialize(priv); |
1106 | 1132 | ||
@@ -1114,6 +1140,19 @@ fw_retry: | |||
1114 | */ | 1140 | */ |
1115 | xc_wait(100); | 1141 | xc_wait(100); |
1116 | 1142 | ||
1143 | if (priv->init_status_supported) { | ||
1144 | if (xc5000_readreg(priv, XREG_INIT_STATUS, &fw_ck) != XC_RESULT_SUCCESS) { | ||
1145 | dprintk(1, "%s() FW failed reading init status.\n", | ||
1146 | __func__); | ||
1147 | goto fw_retry; | ||
1148 | } | ||
1149 | |||
1150 | if (fw_ck == 0) { | ||
1151 | dprintk(1, "%s() FW init status failed = 0x%04x\n", __func__, fw_ck); | ||
1152 | goto fw_retry; | ||
1153 | } | ||
1154 | } | ||
1155 | |||
1117 | if (priv->pll_register_no) { | 1156 | if (priv->pll_register_no) { |
1118 | xc5000_readreg(priv, priv->pll_register_no, | 1157 | xc5000_readreg(priv, priv->pll_register_no, |
1119 | &pll_lock_status); | 1158 | &pll_lock_status); |