diff options
author | Chris Pascoe <c.pascoe@itee.uq.edu.au> | 2007-11-19 19:57:10 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-01-25 16:02:32 -0500 |
commit | aeb012bbf460171b75ba17dc064a543f7256521f (patch) | |
tree | 1e8a735d06bf9e541f4db37c0d808eb91074d2ee /drivers/media/dvb/dvb-usb | |
parent | 45819c381fc4fb342dc091f30eef4b56193e34d5 (diff) |
V4L/DVB (6649): Add support for the DViCO FusionHDTV Dual Digital 4
Add support for DViCO's Dual Digital 4 with xc3028 tuner, zl10353 DVB-T
demodulator and a new-style I2C IR remote control receiver.
This would not have been possible without the work of and advice from
Mike Krufky, who originally got the Dual Digital 4 and second-gen DVB-T
NANO devices working with the out-of-tree XC3028 driver.
I converted it to use the in-tree XC3028 driver (after making it suitable
for our use), and added the IR remote control support based on his advice.
NB: a firmware package is required to use this device.
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/dvb/dvb-usb')
-rw-r--r-- | drivers/media/dvb/dvb-usb/cxusb.c | 200 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/cxusb.h | 2 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 |
3 files changed, 201 insertions, 2 deletions
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 74eeb168f241..ec8516ac8105 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c | |||
@@ -15,7 +15,7 @@ | |||
15 | * | 15 | * |
16 | * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) | 16 | * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) |
17 | * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org) | 17 | * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org) |
18 | * Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au) | 18 | * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au) |
19 | * | 19 | * |
20 | * This program is free software; you can redistribute it and/or modify it | 20 | * This program is free software; you can redistribute it and/or modify it |
21 | * under the terms of the GNU General Public License as published by the Free | 21 | * under the terms of the GNU General Public License as published by the Free |
@@ -30,6 +30,8 @@ | |||
30 | #include "mt352.h" | 30 | #include "mt352.h" |
31 | #include "mt352_priv.h" | 31 | #include "mt352_priv.h" |
32 | #include "zl10353.h" | 32 | #include "zl10353.h" |
33 | #include "tuner-xc2028.h" | ||
34 | #include "tuner-xc2028-types.h" | ||
33 | 35 | ||
34 | /* debug */ | 36 | /* debug */ |
35 | static int dvb_usb_cxusb_debug; | 37 | static int dvb_usb_cxusb_debug; |
@@ -73,6 +75,29 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) | |||
73 | st->gpio_write_state[GPIO_TUNER] = onoff; | 75 | st->gpio_write_state[GPIO_TUNER] = onoff; |
74 | } | 76 | } |
75 | 77 | ||
78 | static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask, | ||
79 | u8 newval) | ||
80 | { | ||
81 | u8 o[2], gpio_state; | ||
82 | int rc; | ||
83 | |||
84 | o[0] = 0xff & ~changemask; /* mask of bits to keep */ | ||
85 | o[1] = newval & changemask; /* new values for bits */ | ||
86 | |||
87 | rc = cxusb_ctrl_msg(d, CMD_BLUEBIRD_GPIO_RW, o, 2, &gpio_state, 1); | ||
88 | if (rc < 0 || (gpio_state & changemask) != (newval & changemask)) | ||
89 | deb_info("bluebird_gpio_write failed.\n"); | ||
90 | |||
91 | return rc < 0 ? rc : gpio_state; | ||
92 | } | ||
93 | |||
94 | static void cxusb_bluebird_gpio_pulse(struct dvb_usb_device *d, u8 pin, int low) | ||
95 | { | ||
96 | cxusb_bluebird_gpio_rw(d, pin, low ? 0 : pin); | ||
97 | msleep(5); | ||
98 | cxusb_bluebird_gpio_rw(d, pin, low ? pin : 0); | ||
99 | } | ||
100 | |||
76 | /* I2C */ | 101 | /* I2C */ |
77 | static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | 102 | static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], |
78 | int num) | 103 | int num) |
@@ -210,6 +235,34 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) | |||
210 | return 0; | 235 | return 0; |
211 | } | 236 | } |
212 | 237 | ||
238 | static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event, | ||
239 | int *state) | ||
240 | { | ||
241 | struct dvb_usb_rc_key *keymap = d->props.rc_key_map; | ||
242 | u8 ircode[4]; | ||
243 | int i; | ||
244 | struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, | ||
245 | .buf = ircode, .len = 4 }; | ||
246 | |||
247 | *event = 0; | ||
248 | *state = REMOTE_NO_KEY_PRESSED; | ||
249 | |||
250 | if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1) | ||
251 | return 0; | ||
252 | |||
253 | for (i = 0; i < d->props.rc_key_map_size; i++) { | ||
254 | if (keymap[i].custom == ircode[1] && | ||
255 | keymap[i].data == ircode[2]) { | ||
256 | *event = keymap[i].event; | ||
257 | *state = REMOTE_KEY_PRESSED; | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
213 | static struct dvb_usb_rc_key dvico_mce_rc_keys[] = { | 266 | static struct dvb_usb_rc_key dvico_mce_rc_keys[] = { |
214 | { 0xfe, 0x02, KEY_TV }, | 267 | { 0xfe, 0x02, KEY_TV }, |
215 | { 0xfe, 0x0e, KEY_MP3 }, | 268 | { 0xfe, 0x0e, KEY_MP3 }, |
@@ -364,6 +417,13 @@ static struct mt352_config cxusb_mt352_config = { | |||
364 | .demod_init = cxusb_mt352_demod_init, | 417 | .demod_init = cxusb_mt352_demod_init, |
365 | }; | 418 | }; |
366 | 419 | ||
420 | static struct zl10353_config cxusb_zl10353_xc3028_config = { | ||
421 | .demod_address = 0x0f, | ||
422 | .if2 = 4560, | ||
423 | .no_tuner = 1, | ||
424 | .parallel_ts = 1, | ||
425 | }; | ||
426 | |||
367 | /* Callbacks for DVB USB */ | 427 | /* Callbacks for DVB USB */ |
368 | static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) | 428 | static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) |
369 | { | 429 | { |
@@ -399,6 +459,52 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) | |||
399 | return 0; | 459 | return 0; |
400 | } | 460 | } |
401 | 461 | ||
462 | static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg) | ||
463 | { | ||
464 | struct dvb_usb_device *d = ptr; | ||
465 | |||
466 | switch (command) { | ||
467 | case XC2028_TUNER_RESET: | ||
468 | deb_info("%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg); | ||
469 | cxusb_bluebird_gpio_pulse(d, 0x01, 1); | ||
470 | break; | ||
471 | case XC2028_RESET_CLK: | ||
472 | deb_info("%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg); | ||
473 | break; | ||
474 | default: | ||
475 | deb_info("%s: unknown command %d, arg %d\n", __FUNCTION__, | ||
476 | command, arg); | ||
477 | return -EINVAL; | ||
478 | } | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) | ||
484 | { | ||
485 | struct dvb_frontend *fe; | ||
486 | struct xc2028_config cfg = { | ||
487 | .i2c_adap = &adap->dev->i2c_adap, | ||
488 | .i2c_addr = 0x61, | ||
489 | .video_dev = adap->dev, | ||
490 | .callback = dvico_bluebird_xc2028_callback, | ||
491 | }; | ||
492 | static struct xc2028_ctrl ctl = { | ||
493 | .type = XC2028_FIRM_NORMAL, | ||
494 | .fname = "xc3028-dvico-au-01.fw", | ||
495 | .max_len = 64, | ||
496 | .scode_table = ZARLINK456, | ||
497 | }; | ||
498 | |||
499 | fe = dvb_attach(xc2028_attach, adap->fe, &cfg); | ||
500 | if (fe == NULL || fe->ops.tuner_ops.set_config == NULL) | ||
501 | return -EIO; | ||
502 | |||
503 | fe->ops.tuner_ops.set_config(fe, &ctl); | ||
504 | |||
505 | return 0; | ||
506 | } | ||
507 | |||
402 | static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) | 508 | static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) |
403 | { | 509 | { |
404 | u8 b; | 510 | u8 b; |
@@ -460,6 +566,46 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap) | |||
460 | return -EIO; | 566 | return -EIO; |
461 | } | 567 | } |
462 | 568 | ||
569 | static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap) | ||
570 | { | ||
571 | u8 ircode[4]; | ||
572 | int i; | ||
573 | struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, | ||
574 | .buf = ircode, .len = 4 }; | ||
575 | |||
576 | if (usb_set_interface(adap->dev->udev, 0, 1) < 0) | ||
577 | err("set interface failed"); | ||
578 | |||
579 | cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); | ||
580 | |||
581 | /* reset the tuner and demodulator */ | ||
582 | cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0); | ||
583 | cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); | ||
584 | cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); | ||
585 | |||
586 | if ((adap->fe = dvb_attach(zl10353_attach, | ||
587 | &cxusb_zl10353_xc3028_config, | ||
588 | &adap->dev->i2c_adap)) == NULL) | ||
589 | return -EIO; | ||
590 | |||
591 | /* try to determine if there is no IR decoder on the I2C bus */ | ||
592 | for (i = 0; adap->dev->props.rc_key_map != NULL && i < 5; i++) { | ||
593 | msleep(20); | ||
594 | if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1) | ||
595 | goto no_IR; | ||
596 | if (ircode[0] == 0 && ircode[1] == 0) | ||
597 | continue; | ||
598 | if (ircode[2] + ircode[3] != 0xff) { | ||
599 | no_IR: | ||
600 | adap->dev->props.rc_key_map = NULL; | ||
601 | info("No IR receiver detected on this device."); | ||
602 | break; | ||
603 | } | ||
604 | } | ||
605 | |||
606 | return 0; | ||
607 | } | ||
608 | |||
463 | /* | 609 | /* |
464 | * DViCO bluebird firmware needs the "warm" product ID to be patched into the | 610 | * DViCO bluebird firmware needs the "warm" product ID to be patched into the |
465 | * firmware file before download. | 611 | * firmware file before download. |
@@ -492,6 +638,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties; | |||
492 | static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties; | 638 | static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties; |
493 | static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties; | 639 | static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties; |
494 | static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; | 640 | static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; |
641 | static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties; | ||
495 | 642 | ||
496 | static int cxusb_probe(struct usb_interface *intf, | 643 | static int cxusb_probe(struct usb_interface *intf, |
497 | const struct usb_device_id *id) | 644 | const struct usb_device_id *id) |
@@ -500,7 +647,8 @@ static int cxusb_probe(struct usb_interface *intf, | |||
500 | dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 || | 647 | dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 || |
501 | dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0 || | 648 | dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0 || |
502 | dvb_usb_device_init(intf,&cxusb_bluebird_lgz201_properties,THIS_MODULE,NULL) == 0 || | 649 | dvb_usb_device_init(intf,&cxusb_bluebird_lgz201_properties,THIS_MODULE,NULL) == 0 || |
503 | dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0) { | 650 | dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0 || |
651 | dvb_usb_device_init(intf,&cxusb_bluebird_dualdig4_properties,THIS_MODULE,NULL) == 0) { | ||
504 | return 0; | 652 | return 0; |
505 | } | 653 | } |
506 | 654 | ||
@@ -521,6 +669,7 @@ static struct usb_device_id cxusb_table [] = { | |||
521 | { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) }, | 669 | { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) }, |
522 | { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) }, | 670 | { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) }, |
523 | { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) }, | 671 | { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) }, |
672 | { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) }, | ||
524 | {} /* Terminating entry */ | 673 | {} /* Terminating entry */ |
525 | }; | 674 | }; |
526 | MODULE_DEVICE_TABLE (usb, cxusb_table); | 675 | MODULE_DEVICE_TABLE (usb, cxusb_table); |
@@ -779,6 +928,53 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { | |||
779 | } | 928 | } |
780 | }; | 929 | }; |
781 | 930 | ||
931 | static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = { | ||
932 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
933 | |||
934 | .usb_ctrl = CYPRESS_FX2, | ||
935 | |||
936 | .size_of_priv = sizeof(struct cxusb_state), | ||
937 | |||
938 | .num_adapters = 1, | ||
939 | .adapter = { | ||
940 | { | ||
941 | .streaming_ctrl = cxusb_streaming_ctrl, | ||
942 | .frontend_attach = cxusb_dualdig4_frontend_attach, | ||
943 | .tuner_attach = cxusb_dvico_xc3028_tuner_attach, | ||
944 | /* parameter for the MPEG2-data transfer */ | ||
945 | .stream = { | ||
946 | .type = USB_BULK, | ||
947 | .count = 5, | ||
948 | .endpoint = 0x02, | ||
949 | .u = { | ||
950 | .bulk = { | ||
951 | .buffersize = 8192, | ||
952 | } | ||
953 | } | ||
954 | }, | ||
955 | }, | ||
956 | }, | ||
957 | |||
958 | .power_ctrl = cxusb_power_ctrl, | ||
959 | |||
960 | .i2c_algo = &cxusb_i2c_algo, | ||
961 | |||
962 | .generic_bulk_ctrl_endpoint = 0x01, | ||
963 | |||
964 | .rc_interval = 100, | ||
965 | .rc_key_map = dvico_mce_rc_keys, | ||
966 | .rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys), | ||
967 | .rc_query = cxusb_bluebird2_rc_query, | ||
968 | |||
969 | .num_device_descs = 1, | ||
970 | .devices = { | ||
971 | { "DViCO FusionHDTV DVB-T Dual Digital 4", | ||
972 | { NULL }, | ||
973 | { &cxusb_table[13], NULL }, | ||
974 | }, | ||
975 | } | ||
976 | }; | ||
977 | |||
782 | static struct usb_driver cxusb_driver = { | 978 | static struct usb_driver cxusb_driver = { |
783 | .name = "dvb_usb_cxusb", | 979 | .name = "dvb_usb_cxusb", |
784 | .probe = cxusb_probe, | 980 | .probe = cxusb_probe, |
diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h index 79ca7abb89a5..4768a2c35517 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.h +++ b/drivers/media/dvb/dvb-usb/cxusb.h | |||
@@ -5,6 +5,8 @@ | |||
5 | #include "dvb-usb.h" | 5 | #include "dvb-usb.h" |
6 | 6 | ||
7 | /* usb commands - some of it are guesses, don't have a reference yet */ | 7 | /* usb commands - some of it are guesses, don't have a reference yet */ |
8 | #define CMD_BLUEBIRD_GPIO_RW 0x05 | ||
9 | |||
8 | #define CMD_I2C_WRITE 0x08 | 10 | #define CMD_I2C_WRITE 0x08 |
9 | #define CMD_I2C_READ 0x09 | 11 | #define CMD_I2C_READ 0x09 |
10 | 12 | ||
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index d6d96308cbaa..6f14c853ffea 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h | |||
@@ -147,6 +147,7 @@ | |||
147 | #define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM 0xdb51 | 147 | #define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM 0xdb51 |
148 | #define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58 | 148 | #define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58 |
149 | #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59 | 149 | #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59 |
150 | #define USB_PID_DVICO_BLUEBIRD_DUAL_4 0xdb78 | ||
150 | #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54 | 151 | #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54 |
151 | #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM 0xdb55 | 152 | #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM 0xdb55 |
152 | #define USB_PID_MEDION_MD95700 0x0932 | 153 | #define USB_PID_MEDION_MD95700 0x0932 |