Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / tm6000 / tm6000-cards.c
blob146c7e86deca4d4109027fd9489be60d061809db
1 /*
2 * tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
4 * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation version 2
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <linux/init.h>
21 #include <linux/module.h>
22 #include <linux/pci.h>
23 #include <linux/delay.h>
24 #include <linux/i2c.h>
25 #include <linux/usb.h>
26 #include <linux/version.h>
27 #include <linux/slab.h>
28 #include <media/v4l2-common.h>
29 #include <media/tuner.h>
30 #include <media/tvaudio.h>
31 #include <media/i2c-addr.h>
32 #include <media/rc-map.h>
34 #include "tm6000.h"
35 #include "tm6000-regs.h"
36 #include "tuner-xc2028.h"
37 #include "xc5000.h"
39 #define TM6000_BOARD_UNKNOWN 0
40 #define TM5600_BOARD_GENERIC 1
41 #define TM6000_BOARD_GENERIC 2
42 #define TM6010_BOARD_GENERIC 3
43 #define TM5600_BOARD_10MOONS_UT821 4
44 #define TM5600_BOARD_10MOONS_UT330 5
45 #define TM6000_BOARD_ADSTECH_DUAL_TV 6
46 #define TM6000_BOARD_FREECOM_AND_SIMILAR 7
47 #define TM6000_BOARD_ADSTECH_MINI_DUAL_TV 8
48 #define TM6010_BOARD_HAUPPAUGE_900H 9
49 #define TM6010_BOARD_BEHOLD_WANDER 10
50 #define TM6010_BOARD_BEHOLD_VOYAGER 11
51 #define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE 12
52 #define TM6010_BOARD_TWINHAN_TU501 13
53 #define TM6010_BOARD_BEHOLD_WANDER_LITE 14
54 #define TM6010_BOARD_BEHOLD_VOYAGER_LITE 15
55 #define TM5600_BOARD_TERRATEC_GRABSTER 16
57 #define TM6000_MAXBOARDS 16
58 static unsigned int card[] = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
60 module_param_array(card, int, NULL, 0444);
62 static unsigned long tm6000_devused;
65 struct tm6000_board {
66 char *name;
68 struct tm6000_capabilities caps;
69 enum tm6000_inaudio aradio;
70 enum tm6000_inaudio avideo;
72 enum tm6000_devtype type; /* variant of the chipset */
73 int tuner_type; /* type of the tuner */
74 int tuner_addr; /* tuner address */
75 int demod_addr; /* demodulator address */
77 struct tm6000_gpio gpio;
79 char *ir_codes;
82 struct tm6000_board tm6000_boards[] = {
83 [TM6000_BOARD_UNKNOWN] = {
84 .name = "Unknown tm6000 video grabber",
85 .caps = {
86 .has_tuner = 1,
88 .gpio = {
89 .tuner_reset = TM6000_GPIO_1,
92 [TM5600_BOARD_GENERIC] = {
93 .name = "Generic tm5600 board",
94 .type = TM5600,
95 .tuner_type = TUNER_XC2028,
96 .tuner_addr = 0xc2 >> 1,
97 .caps = {
98 .has_tuner = 1,
100 .gpio = {
101 .tuner_reset = TM6000_GPIO_1,
104 [TM6000_BOARD_GENERIC] = {
105 .name = "Generic tm6000 board",
106 .tuner_type = TUNER_XC2028,
107 .tuner_addr = 0xc2 >> 1,
108 .caps = {
109 .has_tuner = 1,
110 .has_dvb = 1,
112 .gpio = {
113 .tuner_reset = TM6000_GPIO_1,
116 [TM6010_BOARD_GENERIC] = {
117 .name = "Generic tm6010 board",
118 .type = TM6010,
119 .tuner_type = TUNER_XC2028,
120 .tuner_addr = 0xc2 >> 1,
121 .demod_addr = 0x1e >> 1,
122 .caps = {
123 .has_tuner = 1,
124 .has_dvb = 1,
125 .has_zl10353 = 1,
126 .has_eeprom = 1,
127 .has_remote = 1,
129 .gpio = {
130 .tuner_reset = TM6010_GPIO_2,
131 .tuner_on = TM6010_GPIO_3,
132 .demod_reset = TM6010_GPIO_1,
133 .demod_on = TM6010_GPIO_4,
134 .power_led = TM6010_GPIO_7,
135 .dvb_led = TM6010_GPIO_5,
136 .ir = TM6010_GPIO_0,
139 [TM5600_BOARD_10MOONS_UT821] = {
140 .name = "10Moons UT 821",
141 .tuner_type = TUNER_XC2028,
142 .type = TM5600,
143 .tuner_addr = 0xc2 >> 1,
144 .caps = {
145 .has_tuner = 1,
146 .has_eeprom = 1,
148 .gpio = {
149 .tuner_reset = TM6000_GPIO_1,
152 [TM5600_BOARD_10MOONS_UT330] = {
153 .name = "10Moons UT 330",
154 .tuner_type = TUNER_PHILIPS_FQ1216AME_MK4,
155 .tuner_addr = 0xc8 >> 1,
156 .caps = {
157 .has_tuner = 1,
158 .has_dvb = 0,
159 .has_zl10353 = 0,
160 .has_eeprom = 1,
163 [TM6000_BOARD_ADSTECH_DUAL_TV] = {
164 .name = "ADSTECH Dual TV USB",
165 .tuner_type = TUNER_XC2028,
166 .tuner_addr = 0xc8 >> 1,
167 .caps = {
168 .has_tuner = 1,
169 .has_tda9874 = 1,
170 .has_dvb = 1,
171 .has_zl10353 = 1,
172 .has_eeprom = 1,
175 [TM6000_BOARD_FREECOM_AND_SIMILAR] = {
176 .name = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual",
177 .tuner_type = TUNER_XC2028, /* has a XC3028 */
178 .tuner_addr = 0xc2 >> 1,
179 .demod_addr = 0x1e >> 1,
180 .caps = {
181 .has_tuner = 1,
182 .has_dvb = 1,
183 .has_zl10353 = 1,
184 .has_eeprom = 0,
185 .has_remote = 1,
187 .gpio = {
188 .tuner_reset = TM6000_GPIO_4,
191 [TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = {
192 .name = "ADSTECH Mini Dual TV USB",
193 .tuner_type = TUNER_XC2028, /* has a XC3028 */
194 .tuner_addr = 0xc8 >> 1,
195 .demod_addr = 0x1e >> 1,
196 .caps = {
197 .has_tuner = 1,
198 .has_dvb = 1,
199 .has_zl10353 = 1,
200 .has_eeprom = 0,
202 .gpio = {
203 .tuner_reset = TM6000_GPIO_4,
206 [TM6010_BOARD_HAUPPAUGE_900H] = {
207 .name = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick",
208 .tuner_type = TUNER_XC2028, /* has a XC3028 */
209 .tuner_addr = 0xc2 >> 1,
210 .demod_addr = 0x1e >> 1,
211 .type = TM6010,
212 .caps = {
213 .has_tuner = 1,
214 .has_dvb = 1,
215 .has_zl10353 = 1,
216 .has_eeprom = 1,
217 .has_remote = 1,
219 .gpio = {
220 .tuner_reset = TM6010_GPIO_2,
221 .tuner_on = TM6010_GPIO_3,
222 .demod_reset = TM6010_GPIO_1,
223 .demod_on = TM6010_GPIO_4,
224 .power_led = TM6010_GPIO_7,
225 .dvb_led = TM6010_GPIO_5,
226 .ir = TM6010_GPIO_0,
229 [TM6010_BOARD_BEHOLD_WANDER] = {
230 .name = "Beholder Wander DVB-T/TV/FM USB2.0",
231 .tuner_type = TUNER_XC5000,
232 .tuner_addr = 0xc2 >> 1,
233 .demod_addr = 0x1e >> 1,
234 .type = TM6010,
235 .avideo = TM6000_AIP_SIF1,
236 .aradio = TM6000_AIP_LINE1,
237 .caps = {
238 .has_tuner = 1,
239 .has_dvb = 1,
240 .has_zl10353 = 1,
241 .has_eeprom = 1,
242 .has_remote = 1,
243 .has_input_comp = 1,
244 .has_input_svid = 1,
246 .gpio = {
247 .tuner_reset = TM6010_GPIO_0,
248 .demod_reset = TM6010_GPIO_1,
249 .power_led = TM6010_GPIO_6,
252 [TM6010_BOARD_BEHOLD_VOYAGER] = {
253 .name = "Beholder Voyager TV/FM USB2.0",
254 .tuner_type = TUNER_XC5000,
255 .tuner_addr = 0xc2 >> 1,
256 .type = TM6010,
257 .avideo = TM6000_AIP_SIF1,
258 .aradio = TM6000_AIP_LINE1,
259 .caps = {
260 .has_tuner = 1,
261 .has_dvb = 0,
262 .has_zl10353 = 0,
263 .has_eeprom = 1,
264 .has_remote = 1,
265 .has_input_comp = 1,
266 .has_input_svid = 1,
268 .gpio = {
269 .tuner_reset = TM6010_GPIO_0,
270 .power_led = TM6010_GPIO_6,
273 [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
274 .name = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
275 .tuner_type = TUNER_XC2028, /* has a XC3028 */
276 .tuner_addr = 0xc2 >> 1,
277 .demod_addr = 0x1e >> 1,
278 .type = TM6010,
279 .caps = {
280 .has_tuner = 1,
281 .has_dvb = 1,
282 .has_zl10353 = 1,
283 .has_eeprom = 1,
284 .has_remote = 1,
286 .gpio = {
287 .tuner_reset = TM6010_GPIO_2,
288 .tuner_on = TM6010_GPIO_3,
289 .demod_reset = TM6010_GPIO_1,
290 .demod_on = TM6010_GPIO_4,
291 .power_led = TM6010_GPIO_7,
292 .dvb_led = TM6010_GPIO_5,
293 .ir = TM6010_GPIO_0,
295 .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
297 [TM5600_BOARD_TERRATEC_GRABSTER] = {
298 .name = "Terratec Grabster AV 150/250 MX",
299 .type = TM5600,
300 .tuner_type = TUNER_ABSENT,
302 [TM6010_BOARD_TWINHAN_TU501] = {
303 .name = "Twinhan TU501(704D1)",
304 .tuner_type = TUNER_XC2028, /* has a XC3028 */
305 .tuner_addr = 0xc2 >> 1,
306 .demod_addr = 0x1e >> 1,
307 .type = TM6010,
308 .caps = {
309 .has_tuner = 1,
310 .has_dvb = 1,
311 .has_zl10353 = 1,
312 .has_eeprom = 1,
313 .has_remote = 1,
315 .gpio = {
316 .tuner_reset = TM6010_GPIO_2,
317 .tuner_on = TM6010_GPIO_3,
318 .demod_reset = TM6010_GPIO_1,
319 .demod_on = TM6010_GPIO_4,
320 .power_led = TM6010_GPIO_7,
321 .dvb_led = TM6010_GPIO_5,
322 .ir = TM6010_GPIO_0,
325 [TM6010_BOARD_BEHOLD_WANDER_LITE] = {
326 .name = "Beholder Wander Lite DVB-T/TV/FM USB2.0",
327 .tuner_type = TUNER_XC5000,
328 .tuner_addr = 0xc2 >> 1,
329 .demod_addr = 0x1e >> 1,
330 .type = TM6010,
331 .avideo = TM6000_AIP_SIF1,
332 .aradio = TM6000_AIP_LINE1,
333 .caps = {
334 .has_tuner = 1,
335 .has_dvb = 1,
336 .has_zl10353 = 1,
337 .has_eeprom = 1,
338 .has_remote = 0,
339 .has_input_comp = 0,
340 .has_input_svid = 0,
342 .gpio = {
343 .tuner_reset = TM6010_GPIO_0,
344 .demod_reset = TM6010_GPIO_1,
345 .power_led = TM6010_GPIO_6,
348 [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = {
349 .name = "Beholder Voyager Lite TV/FM USB2.0",
350 .tuner_type = TUNER_XC5000,
351 .tuner_addr = 0xc2 >> 1,
352 .type = TM6010,
353 .avideo = TM6000_AIP_SIF1,
354 .aradio = TM6000_AIP_LINE1,
355 .caps = {
356 .has_tuner = 1,
357 .has_dvb = 0,
358 .has_zl10353 = 0,
359 .has_eeprom = 1,
360 .has_remote = 0,
361 .has_input_comp = 0,
362 .has_input_svid = 0,
364 .gpio = {
365 .tuner_reset = TM6010_GPIO_0,
366 .power_led = TM6010_GPIO_6,
371 /* table of devices that work with this driver */
372 struct usb_device_id tm6000_id_table[] = {
373 { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_10MOONS_UT821 },
374 { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC },
375 { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV },
376 { USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR },
377 { USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV },
378 { USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
379 { USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
380 { USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
381 { USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
382 { USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER },
383 { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER },
384 { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
385 { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
386 { USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER },
387 { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
388 { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
389 { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
390 { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
391 { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE },
392 { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE },
393 { },
396 /* Control power led for show some activity */
397 void tm6000_flash_led(struct tm6000_core *dev, u8 state)
399 /* Power LED unconfigured */
400 if (!dev->gpio.power_led)
401 return;
403 /* ON Power LED */
404 if (state) {
405 switch (dev->model) {
406 case TM6010_BOARD_HAUPPAUGE_900H:
407 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
408 case TM6010_BOARD_TWINHAN_TU501:
409 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
410 dev->gpio.power_led, 0x00);
411 break;
412 case TM6010_BOARD_BEHOLD_WANDER:
413 case TM6010_BOARD_BEHOLD_VOYAGER:
414 case TM6010_BOARD_BEHOLD_WANDER_LITE:
415 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
416 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
417 dev->gpio.power_led, 0x01);
418 break;
421 /* OFF Power LED */
422 else {
423 switch (dev->model) {
424 case TM6010_BOARD_HAUPPAUGE_900H:
425 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
426 case TM6010_BOARD_TWINHAN_TU501:
427 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
428 dev->gpio.power_led, 0x01);
429 break;
430 case TM6010_BOARD_BEHOLD_WANDER:
431 case TM6010_BOARD_BEHOLD_VOYAGER:
432 case TM6010_BOARD_BEHOLD_WANDER_LITE:
433 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
434 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
435 dev->gpio.power_led, 0x00);
436 break;
441 /* Tuner callback to provide the proper gpio changes needed for xc5000 */
442 int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
444 int rc = 0;
445 struct tm6000_core *dev = ptr;
447 if (dev->tuner_type != TUNER_XC5000)
448 return 0;
450 switch (command) {
451 case XC5000_TUNER_RESET:
452 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
453 dev->gpio.tuner_reset, 0x01);
454 msleep(15);
455 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
456 dev->gpio.tuner_reset, 0x00);
457 msleep(15);
458 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
459 dev->gpio.tuner_reset, 0x01);
460 break;
462 return rc;
464 EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
466 /* Tuner callback to provide the proper gpio changes needed for xc2028 */
468 int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
470 int rc = 0;
471 struct tm6000_core *dev = ptr;
473 if (dev->tuner_type != TUNER_XC2028)
474 return 0;
476 switch (command) {
477 case XC2028_RESET_CLK:
478 tm6000_ir_wait(dev, 0);
480 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
481 0x02, arg);
482 msleep(10);
483 rc = tm6000_i2c_reset(dev, 10);
484 break;
485 case XC2028_TUNER_RESET:
486 /* Reset codes during load firmware */
487 switch (arg) {
488 case 0:
489 /* newer tuner can faster reset */
490 switch (dev->model) {
491 case TM5600_BOARD_10MOONS_UT821:
492 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
493 dev->gpio.tuner_reset, 0x01);
494 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
495 0x300, 0x01);
496 msleep(10);
497 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
498 dev->gpio.tuner_reset, 0x00);
499 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
500 0x300, 0x00);
501 msleep(10);
502 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
503 dev->gpio.tuner_reset, 0x01);
504 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
505 0x300, 0x01);
506 break;
507 case TM6010_BOARD_HAUPPAUGE_900H:
508 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
509 case TM6010_BOARD_TWINHAN_TU501:
510 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
511 dev->gpio.tuner_reset, 0x01);
512 msleep(60);
513 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
514 dev->gpio.tuner_reset, 0x00);
515 msleep(75);
516 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
517 dev->gpio.tuner_reset, 0x01);
518 msleep(60);
519 break;
520 default:
521 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
522 dev->gpio.tuner_reset, 0x00);
523 msleep(130);
524 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
525 dev->gpio.tuner_reset, 0x01);
526 msleep(130);
527 break;
530 tm6000_ir_wait(dev, 1);
531 break;
532 case 1:
533 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
534 0x02, 0x01);
535 msleep(10);
536 break;
537 case 2:
538 rc = tm6000_i2c_reset(dev, 100);
539 break;
542 return rc;
544 EXPORT_SYMBOL_GPL(tm6000_tuner_callback);
546 int tm6000_cards_setup(struct tm6000_core *dev)
548 int i, rc;
551 * Board-specific initialization sequence. Handles all GPIO
552 * initialization sequences that are board-specific.
553 * Up to now, all found devices use GPIO1 and GPIO4 at the same way.
554 * Probably, they're all based on some reference device. Due to that,
555 * there's a common routine at the end to handle those GPIO's. Devices
556 * that use different pinups or init sequences can just return at
557 * the board-specific session.
559 switch (dev->model) {
560 case TM6010_BOARD_HAUPPAUGE_900H:
561 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
562 case TM6010_BOARD_TWINHAN_TU501:
563 case TM6010_BOARD_GENERIC:
564 /* Turn xceive 3028 on */
565 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01);
566 msleep(15);
567 /* Turn zarlink zl10353 on */
568 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
569 msleep(15);
570 /* Reset zarlink zl10353 */
571 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
572 msleep(50);
573 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
574 msleep(15);
575 /* Turn zarlink zl10353 off */
576 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01);
577 msleep(15);
578 /* ir ? */
579 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01);
580 msleep(15);
581 /* Power led on (blue) */
582 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00);
583 msleep(15);
584 /* DVB led off (orange) */
585 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01);
586 msleep(15);
587 /* Turn zarlink zl10353 on */
588 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
589 msleep(15);
590 break;
591 case TM6010_BOARD_BEHOLD_WANDER:
592 case TM6010_BOARD_BEHOLD_WANDER_LITE:
593 /* Power led on (blue) */
594 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
595 msleep(15);
596 /* Reset zarlink zl10353 */
597 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
598 msleep(50);
599 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
600 msleep(15);
601 break;
602 case TM6010_BOARD_BEHOLD_VOYAGER:
603 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
604 /* Power led on (blue) */
605 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
606 msleep(15);
607 break;
608 default:
609 break;
613 * Default initialization. Most of the devices seem to use GPIO1
614 * and GPIO4.on the same way, so, this handles the common sequence
615 * used by most devices.
616 * If a device uses a different sequence or different GPIO pins for
617 * reset, just add the code at the board-specific part
620 if (dev->gpio.tuner_reset) {
621 for (i = 0; i < 2; i++) {
622 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
623 dev->gpio.tuner_reset, 0x00);
624 if (rc < 0) {
625 printk(KERN_ERR "Error %i doing tuner reset\n", rc);
626 return rc;
629 msleep(10); /* Just to be conservative */
630 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
631 dev->gpio.tuner_reset, 0x01);
632 if (rc < 0) {
633 printk(KERN_ERR "Error %i doing tuner reset\n", rc);
634 return rc;
637 } else {
638 printk(KERN_ERR "Tuner reset is not configured\n");
639 return -1;
642 msleep(50);
644 return 0;
647 static void tm6000_config_tuner(struct tm6000_core *dev)
649 struct tuner_setup tun_setup;
651 /* Load tuner module */
652 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
653 "tuner", dev->tuner_addr, NULL);
655 memset(&tun_setup, 0, sizeof(tun_setup));
656 tun_setup.type = dev->tuner_type;
657 tun_setup.addr = dev->tuner_addr;
659 tun_setup.mode_mask = 0;
660 if (dev->caps.has_tuner)
661 tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO);
663 switch (dev->tuner_type) {
664 case TUNER_XC2028:
665 tun_setup.tuner_callback = tm6000_tuner_callback;
666 break;
667 case TUNER_XC5000:
668 tun_setup.tuner_callback = tm6000_xc5000_callback;
669 break;
672 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
674 switch (dev->tuner_type) {
675 case TUNER_XC2028: {
676 struct v4l2_priv_tun_config xc2028_cfg;
677 struct xc2028_ctrl ctl;
679 memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
680 memset(&ctl, 0, sizeof(ctl));
682 ctl.input1 = 1;
683 ctl.read_not_reliable = 0;
684 ctl.msleep = 10;
685 ctl.demod = XC3028_FE_ZARLINK456;
686 ctl.vhfbw7 = 1;
687 ctl.uhfbw8 = 1;
688 xc2028_cfg.tuner = TUNER_XC2028;
689 xc2028_cfg.priv = &ctl;
691 switch (dev->model) {
692 case TM6010_BOARD_HAUPPAUGE_900H:
693 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
694 case TM6010_BOARD_TWINHAN_TU501:
695 ctl.fname = "xc3028L-v36.fw";
696 break;
697 default:
698 if (dev->dev_type == TM6010)
699 ctl.fname = "xc3028-v27.fw";
700 else
701 ctl.fname = "xc3028-v24.fw";
704 printk(KERN_INFO "Setting firmware parameters for xc2028\n");
705 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
706 &xc2028_cfg);
709 break;
710 case TUNER_XC5000:
712 struct v4l2_priv_tun_config xc5000_cfg;
713 struct xc5000_config ctl = {
714 .i2c_address = dev->tuner_addr,
715 .if_khz = 4570,
716 .radio_input = XC5000_RADIO_FM1_MONO,
719 xc5000_cfg.tuner = TUNER_XC5000;
720 xc5000_cfg.priv = &ctl;
722 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
723 &xc5000_cfg);
725 break;
726 default:
727 printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n");
728 break;
732 static int tm6000_init_dev(struct tm6000_core *dev)
734 struct v4l2_frequency f;
735 int rc = 0;
737 mutex_init(&dev->lock);
739 mutex_lock(&dev->lock);
741 /* Initializa board-specific data */
742 dev->dev_type = tm6000_boards[dev->model].type;
743 dev->tuner_type = tm6000_boards[dev->model].tuner_type;
744 dev->tuner_addr = tm6000_boards[dev->model].tuner_addr;
746 dev->gpio = tm6000_boards[dev->model].gpio;
748 dev->ir_codes = tm6000_boards[dev->model].ir_codes;
750 dev->demod_addr = tm6000_boards[dev->model].demod_addr;
752 dev->caps = tm6000_boards[dev->model].caps;
754 dev->avideo = tm6000_boards[dev->model].avideo;
755 dev->aradio = tm6000_boards[dev->model].aradio;
756 /* initialize hardware */
757 rc = tm6000_init(dev);
758 if (rc < 0)
759 goto err;
761 rc = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
762 if (rc < 0)
763 goto err;
765 /* register i2c bus */
766 rc = tm6000_i2c_register(dev);
767 if (rc < 0)
768 goto err;
770 /* Default values for STD and resolutions */
771 dev->width = 720;
772 dev->height = 480;
773 dev->norm = V4L2_STD_PAL_M;
775 /* Configure tuner */
776 tm6000_config_tuner(dev);
778 /* Set video standard */
779 v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
781 /* Set tuner frequency - also loads firmware on xc2028/xc3028 */
782 f.tuner = 0;
783 f.type = V4L2_TUNER_ANALOG_TV;
784 f.frequency = 3092; /* 193.25 MHz */
785 dev->freq = f.frequency;
786 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
788 if (dev->caps.has_tda9874)
789 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
790 "tvaudio", I2C_ADDR_TDA9874, NULL);
792 /* register and initialize V4L2 */
793 rc = tm6000_v4l2_register(dev);
794 if (rc < 0)
795 goto err;
797 tm6000_add_into_devlist(dev);
798 tm6000_init_extension(dev);
800 tm6000_ir_init(dev);
802 mutex_unlock(&dev->lock);
803 return 0;
805 err:
806 mutex_unlock(&dev->lock);
807 return rc;
810 /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
811 #define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
813 static void get_max_endpoint(struct usb_device *udev,
814 struct usb_host_interface *alt,
815 char *msgtype,
816 struct usb_host_endpoint *curr_e,
817 struct tm6000_endpoint *tm_ep)
819 u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize);
820 unsigned int size = tmp & 0x7ff;
822 if (udev->speed == USB_SPEED_HIGH)
823 size = size * hb_mult(tmp);
825 if (size > tm_ep->maxsize) {
826 tm_ep->endp = curr_e;
827 tm_ep->maxsize = size;
828 tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber;
829 tm_ep->bAlternateSetting = alt->desc.bAlternateSetting;
831 printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n",
832 msgtype, curr_e->desc.bEndpointAddress,
833 size);
838 * tm6000_usb_probe()
839 * checks for supported devices
841 static int tm6000_usb_probe(struct usb_interface *interface,
842 const struct usb_device_id *id)
844 struct usb_device *usbdev;
845 struct tm6000_core *dev = NULL;
846 int i, rc = 0;
847 int nr = 0;
848 char *speed;
850 usbdev = usb_get_dev(interface_to_usbdev(interface));
852 /* Selects the proper interface */
853 rc = usb_set_interface(usbdev, 0, 1);
854 if (rc < 0)
855 goto err;
857 /* Check to see next free device and mark as used */
858 nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS);
859 if (nr >= TM6000_MAXBOARDS) {
860 printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS);
861 usb_put_dev(usbdev);
862 return -ENOMEM;
865 /* Create and initialize dev struct */
866 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
867 if (dev == NULL) {
868 printk(KERN_ERR "tm6000" ": out of memory!\n");
869 usb_put_dev(usbdev);
870 return -ENOMEM;
872 spin_lock_init(&dev->slock);
874 /* Increment usage count */
875 tm6000_devused |= 1<<nr;
876 snprintf(dev->name, 29, "tm6000 #%d", nr);
878 dev->model = id->driver_info;
879 if ((card[nr] >= 0) && (card[nr] < ARRAY_SIZE(tm6000_boards)))
880 dev->model = card[nr];
882 dev->udev = usbdev;
883 dev->devno = nr;
885 switch (usbdev->speed) {
886 case USB_SPEED_LOW:
887 speed = "1.5";
888 break;
889 case USB_SPEED_UNKNOWN:
890 case USB_SPEED_FULL:
891 speed = "12";
892 break;
893 case USB_SPEED_HIGH:
894 speed = "480";
895 break;
896 default:
897 speed = "unknown";
902 /* Get endpoints */
903 for (i = 0; i < interface->num_altsetting; i++) {
904 int ep;
906 for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
907 struct usb_host_endpoint *e;
908 int dir_out;
910 e = &interface->altsetting[i].endpoint[ep];
912 dir_out = ((e->desc.bEndpointAddress &
913 USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
915 printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n",
917 interface->altsetting[i].desc.bInterfaceNumber,
918 interface->altsetting[i].desc.bInterfaceClass);
920 switch (e->desc.bmAttributes) {
921 case USB_ENDPOINT_XFER_BULK:
922 if (!dir_out) {
923 get_max_endpoint(usbdev,
924 &interface->altsetting[i],
925 "Bulk IN", e,
926 &dev->bulk_in);
927 } else {
928 get_max_endpoint(usbdev,
929 &interface->altsetting[i],
930 "Bulk OUT", e,
931 &dev->bulk_out);
933 break;
934 case USB_ENDPOINT_XFER_ISOC:
935 if (!dir_out) {
936 get_max_endpoint(usbdev,
937 &interface->altsetting[i],
938 "ISOC IN", e,
939 &dev->isoc_in);
940 } else {
941 get_max_endpoint(usbdev,
942 &interface->altsetting[i],
943 "ISOC OUT", e,
944 &dev->isoc_out);
946 break;
947 case USB_ENDPOINT_XFER_INT:
948 if (!dir_out) {
949 get_max_endpoint(usbdev,
950 &interface->altsetting[i],
951 "INT IN", e,
952 &dev->int_in);
953 } else {
954 get_max_endpoint(usbdev,
955 &interface->altsetting[i],
956 "INT OUT", e,
957 &dev->int_out);
959 break;
965 printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n",
966 speed,
967 le16_to_cpu(dev->udev->descriptor.idVendor),
968 le16_to_cpu(dev->udev->descriptor.idProduct),
969 interface->altsetting->desc.bInterfaceNumber);
971 /* check if the the device has the iso in endpoint at the correct place */
972 if (!dev->isoc_in.endp) {
973 printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n");
974 rc = -ENODEV;
976 goto err;
979 /* save our data pointer in this interface device */
980 usb_set_intfdata(interface, dev);
982 printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name);
984 rc = tm6000_init_dev(dev);
986 if (rc < 0)
987 goto err;
989 return 0;
991 err:
992 printk(KERN_ERR "tm6000: Error %d while registering\n", rc);
994 tm6000_devused &= ~(1<<nr);
995 usb_put_dev(usbdev);
997 kfree(dev);
998 return rc;
1002 * tm6000_usb_disconnect()
1003 * called when the device gets diconencted
1004 * video device will be unregistered on v4l2_close in case it is still open
1006 static void tm6000_usb_disconnect(struct usb_interface *interface)
1008 struct tm6000_core *dev = usb_get_intfdata(interface);
1009 usb_set_intfdata(interface, NULL);
1011 if (!dev)
1012 return;
1014 printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
1016 tm6000_ir_fini(dev);
1018 if (dev->gpio.power_led) {
1019 switch (dev->model) {
1020 case TM6010_BOARD_HAUPPAUGE_900H:
1021 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
1022 case TM6010_BOARD_TWINHAN_TU501:
1023 /* Power led off */
1024 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
1025 dev->gpio.power_led, 0x01);
1026 msleep(15);
1027 break;
1028 case TM6010_BOARD_BEHOLD_WANDER:
1029 case TM6010_BOARD_BEHOLD_VOYAGER:
1030 case TM6010_BOARD_BEHOLD_WANDER_LITE:
1031 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
1032 /* Power led off */
1033 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
1034 dev->gpio.power_led, 0x00);
1035 msleep(15);
1036 break;
1039 tm6000_v4l2_unregister(dev);
1041 tm6000_i2c_unregister(dev);
1043 v4l2_device_unregister(&dev->v4l2_dev);
1045 dev->state |= DEV_DISCONNECTED;
1047 usb_put_dev(dev->udev);
1049 tm6000_close_extension(dev);
1050 tm6000_remove_from_devlist(dev);
1052 kfree(dev);
1055 static struct usb_driver tm6000_usb_driver = {
1056 .name = "tm6000",
1057 .probe = tm6000_usb_probe,
1058 .disconnect = tm6000_usb_disconnect,
1059 .id_table = tm6000_id_table,
1062 static int __init tm6000_module_init(void)
1064 int result;
1066 printk(KERN_INFO "tm6000" " v4l2 driver version %d.%d.%d loaded\n",
1067 (TM6000_VERSION >> 16) & 0xff,
1068 (TM6000_VERSION >> 8) & 0xff, TM6000_VERSION & 0xff);
1070 /* register this driver with the USB subsystem */
1071 result = usb_register(&tm6000_usb_driver);
1072 if (result)
1073 printk(KERN_ERR "tm6000"
1074 " usb_register failed. Error number %d.\n", result);
1076 return result;
1079 static void __exit tm6000_module_exit(void)
1081 /* deregister at USB subsystem */
1082 usb_deregister(&tm6000_usb_driver);
1085 module_init(tm6000_module_init);
1086 module_exit(tm6000_module_exit);
1088 MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter");
1089 MODULE_AUTHOR("Mauro Carvalho Chehab");
1090 MODULE_LICENSE("GPL");