diff options
author | Andrew de Quincey <adq_dvb@lidskialf.net> | 2006-05-22 09:32:02 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-06-25 01:00:06 -0400 |
commit | 5c1208ba457a1668c81868060c08496a2d053be0 (patch) | |
tree | 293abaefbcb991b6f6d645447ff41aaea3428f11 /drivers/media/dvb/ttpci/budget-av.c | |
parent | 48c35756a762e2d569dfd9ab2f24d1b63ea657b9 (diff) |
V4L/DVB (3984): Fix CI interface on KNC1 DVBT and DVBC cards
These cards need special handling for CI - reinitialising the frontend
device when the CI module is reset. Additionally the tda10021 needs to be set
into a different transport stream mode when a CI module is present.
Signed-off-by: Andrew de Quincey <adq_dvb@lidskialf.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/dvb/ttpci/budget-av.c')
-rw-r--r-- | drivers/media/dvb/ttpci/budget-av.c | 194 |
1 files changed, 120 insertions, 74 deletions
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 68004187860f..3ff67523cce2 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c | |||
@@ -50,6 +50,12 @@ | |||
50 | 50 | ||
51 | #define DEBICICAM 0x02420000 | 51 | #define DEBICICAM 0x02420000 |
52 | 52 | ||
53 | #define SLOTSTATUS_NONE 1 | ||
54 | #define SLOTSTATUS_PRESENT 2 | ||
55 | #define SLOTSTATUS_RESET 4 | ||
56 | #define SLOTSTATUS_READY 8 | ||
57 | #define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) | ||
58 | |||
53 | struct budget_av { | 59 | struct budget_av { |
54 | struct budget budget; | 60 | struct budget budget; |
55 | struct video_device *vd; | 61 | struct video_device *vd; |
@@ -58,8 +64,15 @@ struct budget_av { | |||
58 | struct tasklet_struct ciintf_irq_tasklet; | 64 | struct tasklet_struct ciintf_irq_tasklet; |
59 | int slot_status; | 65 | int slot_status; |
60 | struct dvb_ca_en50221 ca; | 66 | struct dvb_ca_en50221 ca; |
67 | u8 reinitialise_demod:1; | ||
68 | u8 tda10021_poclkp:1; | ||
69 | u8 tda10021_ts_enabled; | ||
70 | int (*tda10021_set_frontend)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); | ||
61 | }; | 71 | }; |
62 | 72 | ||
73 | static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot); | ||
74 | |||
75 | |||
63 | /* GPIO Connections: | 76 | /* GPIO Connections: |
64 | * 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*! | 77 | * 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*! |
65 | * 1 - CI memory select 0=>IO memory, 1=>Attribute Memory | 78 | * 1 - CI memory select 0=>IO memory, 1=>Attribute Memory |
@@ -129,9 +142,10 @@ static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int ad | |||
129 | udelay(1); | 142 | udelay(1); |
130 | 143 | ||
131 | result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1); | 144 | result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1); |
132 | 145 | if (result == -ETIMEDOUT) { | |
133 | if (result == -ETIMEDOUT) | 146 | ciintf_slot_shutdown(ca, slot); |
134 | budget_av->slot_status = 0; | 147 | printk(KERN_INFO "budget-av: cam ejected 1\n"); |
148 | } | ||
135 | return result; | 149 | return result; |
136 | } | 150 | } |
137 | 151 | ||
@@ -147,9 +161,10 @@ static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int a | |||
147 | udelay(1); | 161 | udelay(1); |
148 | 162 | ||
149 | result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1); | 163 | result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1); |
150 | 164 | if (result == -ETIMEDOUT) { | |
151 | if (result == -ETIMEDOUT) | 165 | ciintf_slot_shutdown(ca, slot); |
152 | budget_av->slot_status = 0; | 166 | printk(KERN_INFO "budget-av: cam ejected 2\n"); |
167 | } | ||
153 | return result; | 168 | return result; |
154 | } | 169 | } |
155 | 170 | ||
@@ -165,9 +180,11 @@ static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 addre | |||
165 | udelay(1); | 180 | udelay(1); |
166 | 181 | ||
167 | result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0); | 182 | result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0); |
168 | 183 | if ((result == -ETIMEDOUT) || ((result == 0xff) && ((address & 3) < 2))) { | |
169 | if (result == -ETIMEDOUT) | 184 | ciintf_slot_shutdown(ca, slot); |
170 | budget_av->slot_status = 0; | 185 | printk(KERN_INFO "budget-av: cam ejected 3\n"); |
186 | return -ETIMEDOUT; | ||
187 | } | ||
171 | return result; | 188 | return result; |
172 | } | 189 | } |
173 | 190 | ||
@@ -183,9 +200,10 @@ static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 addr | |||
183 | udelay(1); | 200 | udelay(1); |
184 | 201 | ||
185 | result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0); | 202 | result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0); |
186 | 203 | if (result == -ETIMEDOUT) { | |
187 | if (result == -ETIMEDOUT) | 204 | ciintf_slot_shutdown(ca, slot); |
188 | budget_av->slot_status = 0; | 205 | printk(KERN_INFO "budget-av: cam ejected 5\n"); |
206 | } | ||
189 | return result; | 207 | return result; |
190 | } | 208 | } |
191 | 209 | ||
@@ -193,12 +211,12 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) | |||
193 | { | 211 | { |
194 | struct budget_av *budget_av = (struct budget_av *) ca->data; | 212 | struct budget_av *budget_av = (struct budget_av *) ca->data; |
195 | struct saa7146_dev *saa = budget_av->budget.dev; | 213 | struct saa7146_dev *saa = budget_av->budget.dev; |
196 | int timeout = 50; // 5 seconds (4.4.6 Ready) | ||
197 | 214 | ||
198 | if (slot != 0) | 215 | if (slot != 0) |
199 | return -EINVAL; | 216 | return -EINVAL; |
200 | 217 | ||
201 | dprintk(1, "ciintf_slot_reset\n"); | 218 | dprintk(1, "ciintf_slot_reset\n"); |
219 | budget_av->slot_status = SLOTSTATUS_RESET; | ||
202 | 220 | ||
203 | saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ | 221 | saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ |
204 | 222 | ||
@@ -208,20 +226,17 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) | |||
208 | msleep(20); /* 20 ms Vcc settling time */ | 226 | msleep(20); /* 20 ms Vcc settling time */ |
209 | 227 | ||
210 | saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */ | 228 | saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */ |
229 | ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); | ||
230 | msleep(20); | ||
211 | 231 | ||
212 | /* This should have been based on pin 16 READY of the pcmcia port, | 232 | /* reinitialise the frontend if necessary */ |
213 | * but AFAICS it is not routed to the saa7146 */ | 233 | if (budget_av->reinitialise_demod) |
214 | while (--timeout > 0 && ciintf_read_attribute_mem(ca, slot, 0) != 0x1d) | 234 | dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); |
215 | msleep(100); | ||
216 | |||
217 | /* reinitialise the frontend */ | ||
218 | dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); | ||
219 | 235 | ||
220 | if (timeout <= 0) | 236 | /* set tda10021 back to original clock configuration on reset */ |
221 | { | 237 | if (budget_av->tda10021_poclkp) { |
222 | printk(KERN_ERR "budget-av: cam reset failed (timeout).\n"); | 238 | tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0); |
223 | saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ | 239 | budget_av->tda10021_ts_enabled = 0; |
224 | return -ETIMEDOUT; | ||
225 | } | 240 | } |
226 | 241 | ||
227 | return 0; | 242 | return 0; |
@@ -238,7 +253,13 @@ static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) | |||
238 | dprintk(1, "ciintf_slot_shutdown\n"); | 253 | dprintk(1, "ciintf_slot_shutdown\n"); |
239 | 254 | ||
240 | ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); | 255 | ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); |
241 | budget_av->slot_status = 0; | 256 | budget_av->slot_status = SLOTSTATUS_NONE; |
257 | |||
258 | /* set tda10021 back to original clock configuration when cam removed */ | ||
259 | if (budget_av->tda10021_poclkp) { | ||
260 | tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0); | ||
261 | budget_av->tda10021_ts_enabled = 0; | ||
262 | } | ||
242 | return 0; | 263 | return 0; |
243 | } | 264 | } |
244 | 265 | ||
@@ -253,6 +274,13 @@ static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) | |||
253 | dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status); | 274 | dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status); |
254 | 275 | ||
255 | ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); | 276 | ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); |
277 | |||
278 | /* tda10021 seems to need a different TS clock config when data is routed to the CAM */ | ||
279 | if (budget_av->tda10021_poclkp) { | ||
280 | tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1); | ||
281 | budget_av->tda10021_ts_enabled = 1; | ||
282 | } | ||
283 | |||
256 | return 0; | 284 | return 0; |
257 | } | 285 | } |
258 | 286 | ||
@@ -260,50 +288,61 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open | |||
260 | { | 288 | { |
261 | struct budget_av *budget_av = (struct budget_av *) ca->data; | 289 | struct budget_av *budget_av = (struct budget_av *) ca->data; |
262 | struct saa7146_dev *saa = budget_av->budget.dev; | 290 | struct saa7146_dev *saa = budget_av->budget.dev; |
263 | int cam_present = 0; | 291 | int result; |
264 | 292 | ||
265 | if (slot != 0) | 293 | if (slot != 0) |
266 | return -EINVAL; | 294 | return -EINVAL; |
267 | 295 | ||
268 | if (!budget_av->slot_status) | 296 | /* test the card detect line - needs to be done carefully |
269 | { | 297 | * since it never goes high for some CAMs on this interface (e.g. topuptv) */ |
270 | // first of all test the card detect line | 298 | if (budget_av->slot_status == SLOTSTATUS_NONE) { |
271 | saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); | 299 | saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); |
272 | udelay(1); | 300 | udelay(1); |
273 | if (saa7146_read(saa, PSR) & MASK_06) | 301 | if (saa7146_read(saa, PSR) & MASK_06) { |
274 | { | 302 | if (budget_av->slot_status == SLOTSTATUS_NONE) { |
275 | cam_present = 1; | 303 | budget_av->slot_status = SLOTSTATUS_PRESENT; |
304 | printk(KERN_INFO "budget-av: cam inserted A\n"); | ||
305 | } | ||
276 | } | 306 | } |
277 | saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); | 307 | saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); |
308 | } | ||
278 | 309 | ||
279 | // that is unreliable however, so try and read from IO memory | 310 | /* We also try and read from IO memory to work round the above detection bug. If |
280 | if (!cam_present) | 311 | * there is no CAM, we will get a timeout. Only done if there is no cam |
281 | { | 312 | * present, since this test actually breaks some cams :( |
282 | saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); | 313 | * |
283 | if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT) | 314 | * if the CI interface is not open, we also do the above test since we |
284 | { | 315 | * don't care if the cam has problems - we'll be resetting it on open() anyway */ |
285 | cam_present = 1; | 316 | if ((budget_av->slot_status == SLOTSTATUS_NONE) || (!open)) { |
317 | saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); | ||
318 | result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1); | ||
319 | if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) { | ||
320 | budget_av->slot_status = SLOTSTATUS_PRESENT; | ||
321 | printk(KERN_INFO "budget-av: cam inserted B\n"); | ||
322 | } else if (result < 0) { | ||
323 | if (budget_av->slot_status != SLOTSTATUS_NONE) { | ||
324 | ciintf_slot_shutdown(ca, slot); | ||
325 | printk(KERN_INFO "budget-av: cam ejected 5\n"); | ||
326 | return 0; | ||
286 | } | 327 | } |
287 | } | 328 | } |
329 | } | ||
288 | 330 | ||
289 | // did we find something? | 331 | /* read from attribute memory in reset/ready state to know when the CAM is ready */ |
290 | if (cam_present) { | 332 | if (budget_av->slot_status == SLOTSTATUS_RESET) { |
291 | printk(KERN_INFO "budget-av: cam inserted\n"); | 333 | result = ciintf_read_attribute_mem(ca, slot, 0); |
292 | budget_av->slot_status = 1; | 334 | if (result == 0x1d) { |
293 | } | 335 | budget_av->slot_status = SLOTSTATUS_READY; |
294 | } else if (!open) { | ||
295 | saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); | ||
296 | if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT) | ||
297 | { | ||
298 | printk(KERN_INFO "budget-av: cam ejected\n"); | ||
299 | saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ | ||
300 | budget_av->slot_status = 0; | ||
301 | } | 336 | } |
302 | } | 337 | } |
303 | 338 | ||
304 | if (budget_av->slot_status == 1) | 339 | /* work out correct return code */ |
305 | return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; | 340 | if (budget_av->slot_status != SLOTSTATUS_NONE) { |
306 | 341 | if (budget_av->slot_status & SLOTSTATUS_READY) { | |
342 | return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; | ||
343 | } | ||
344 | return DVB_CA_EN50221_POLL_CAM_PRESENT; | ||
345 | } | ||
307 | return 0; | 346 | return 0; |
308 | } | 347 | } |
309 | 348 | ||
@@ -333,6 +372,8 @@ static int ciintf_init(struct budget_av *budget_av) | |||
333 | budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable; | 372 | budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable; |
334 | budget_av->ca.poll_slot_status = ciintf_poll_slot_status; | 373 | budget_av->ca.poll_slot_status = ciintf_poll_slot_status; |
335 | budget_av->ca.data = budget_av; | 374 | budget_av->ca.data = budget_av; |
375 | budget_av->budget.ci_present = 1; | ||
376 | budget_av->slot_status = SLOTSTATUS_NONE; | ||
336 | 377 | ||
337 | if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter, | 378 | if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter, |
338 | &budget_av->ca, 0, 1)) != 0) { | 379 | &budget_av->ca, 0, 1)) != 0) { |
@@ -341,7 +382,6 @@ static int ciintf_init(struct budget_av *budget_av) | |||
341 | } | 382 | } |
342 | 383 | ||
343 | printk(KERN_INFO "budget-av: ci interface initialised.\n"); | 384 | printk(KERN_INFO "budget-av: ci interface initialised.\n"); |
344 | budget_av->budget.ci_present = 1; | ||
345 | return 0; | 385 | return 0; |
346 | 386 | ||
347 | error: | 387 | error: |
@@ -976,7 +1016,7 @@ static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe, | |||
976 | 1016 | ||
977 | static struct stv0299_config philips_sd1878_config = { | 1017 | static struct stv0299_config philips_sd1878_config = { |
978 | .demod_address = 0x68, | 1018 | .demod_address = 0x68, |
979 | .inittab = philips_sd1878_inittab, | 1019 | .inittab = philips_sd1878_inittab, |
980 | .mclk = 88000000UL, | 1020 | .mclk = 88000000UL, |
981 | .invert = 0, | 1021 | .invert = 0, |
982 | .skip_reinit = 0, | 1022 | .skip_reinit = 0, |
@@ -1018,6 +1058,23 @@ static u8 read_pwm(struct budget_av *budget_av) | |||
1018 | #define SUBID_DVBT_KNC1 0x0030 | 1058 | #define SUBID_DVBT_KNC1 0x0030 |
1019 | #define SUBID_DVBT_CINERGY1200 0x1157 | 1059 | #define SUBID_DVBT_CINERGY1200 0x1157 |
1020 | 1060 | ||
1061 | |||
1062 | static int tda10021_set_frontend(struct dvb_frontend *fe, | ||
1063 | struct dvb_frontend_parameters *p) | ||
1064 | { | ||
1065 | struct budget_av* budget_av = fe->dvb->priv; | ||
1066 | int result; | ||
1067 | |||
1068 | result = budget_av->tda10021_set_frontend(fe, p); | ||
1069 | if (budget_av->tda10021_ts_enabled) { | ||
1070 | tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1); | ||
1071 | } else { | ||
1072 | tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0); | ||
1073 | } | ||
1074 | |||
1075 | return result; | ||
1076 | } | ||
1077 | |||
1021 | static void frontend_init(struct budget_av *budget_av) | 1078 | static void frontend_init(struct budget_av *budget_av) |
1022 | { | 1079 | { |
1023 | struct saa7146_dev * saa = budget_av->budget.dev; | 1080 | struct saa7146_dev * saa = budget_av->budget.dev; |
@@ -1083,34 +1140,23 @@ static void frontend_init(struct budget_av *budget_av) | |||
1083 | 1140 | ||
1084 | case SUBID_DVBC_KNC1: | 1141 | case SUBID_DVBC_KNC1: |
1085 | case SUBID_DVBC_KNC1_PLUS: | 1142 | case SUBID_DVBC_KNC1_PLUS: |
1143 | case SUBID_DVBC_CINERGY1200: | ||
1144 | budget_av->reinitialise_demod = 1; | ||
1086 | fe = tda10021_attach(&philips_cu1216_config, | 1145 | fe = tda10021_attach(&philips_cu1216_config, |
1087 | &budget_av->budget.i2c_adap, | 1146 | &budget_av->budget.i2c_adap, |
1088 | read_pwm(budget_av)); | 1147 | read_pwm(budget_av)); |
1089 | if (fe) { | 1148 | if (fe) { |
1149 | budget_av->tda10021_poclkp = 1; | ||
1150 | budget_av->tda10021_set_frontend = fe->ops->set_frontend; | ||
1151 | fe->ops->set_frontend = tda10021_set_frontend; | ||
1090 | fe->ops->tuner_ops.set_params = philips_cu1216_tuner_set_params; | 1152 | fe->ops->tuner_ops.set_params = philips_cu1216_tuner_set_params; |
1091 | } | 1153 | } |
1092 | break; | 1154 | break; |
1093 | 1155 | ||
1094 | case SUBID_DVBT_KNC1: | 1156 | case SUBID_DVBT_KNC1: |
1095 | case SUBID_DVBT_KNC1_PLUS: | 1157 | case SUBID_DVBT_KNC1_PLUS: |
1096 | fe = tda10046_attach(&philips_tu1216_config, | ||
1097 | &budget_av->budget.i2c_adap); | ||
1098 | if (fe) { | ||
1099 | fe->ops->tuner_ops.init = philips_tu1216_tuner_init; | ||
1100 | fe->ops->tuner_ops.set_params = philips_tu1216_tuner_set_params; | ||
1101 | } | ||
1102 | break; | ||
1103 | |||
1104 | case SUBID_DVBC_CINERGY1200: | ||
1105 | fe = tda10021_attach(&philips_cu1216_config, | ||
1106 | &budget_av->budget.i2c_adap, | ||
1107 | read_pwm(budget_av)); | ||
1108 | if (fe) { | ||
1109 | fe->ops->tuner_ops.set_params = philips_cu1216_tuner_set_params; | ||
1110 | } | ||
1111 | break; | ||
1112 | |||
1113 | case SUBID_DVBT_CINERGY1200: | 1158 | case SUBID_DVBT_CINERGY1200: |
1159 | budget_av->reinitialise_demod = 1; | ||
1114 | fe = tda10046_attach(&philips_tu1216_config, | 1160 | fe = tda10046_attach(&philips_tu1216_config, |
1115 | &budget_av->budget.i2c_adap); | 1161 | &budget_av->budget.i2c_adap); |
1116 | if (fe) { | 1162 | if (fe) { |