diff options
author | Igor M. Liplianin <liplianin@me.by> | 2009-06-14 19:51:45 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-06-16 18:07:48 -0400 |
commit | 1dac77c9d82f344b21c1d962d79875ec331f83cc (patch) | |
tree | eb4c8c782935dd79e37d039cdeec13e90ce8ac99 | |
parent | b42e1d71f52995f0a25f2b593fdb166326db3fd4 (diff) |
V4L/DVB (11983): Add support for DVBWorld DVB-C USB Cable card.
DVBWorld DVB-C USB Cable card contains TUA6034 tuner,
TDA10023 demod and Cypress FX-2 controller.
http://www.worlddvb.com/product/htm/usbc.htm
Signed-off-by: Igor M. Liplianin <liplianin@me.by>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/dvb/dvb-usb/dw2102.c | 176 |
1 files changed, 165 insertions, 11 deletions
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 06a0aa1ae2cb..75de49c0d943 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* DVB USB framework compliant Linux driver for the | 1 | /* DVB USB framework compliant Linux driver for the |
2 | * DVBWorld DVB-S 2101, 2102, DVB-S2 2104 Card | 2 | * DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101, |
3 | * | 3 | * TeVii S600, S650 Cards |
4 | * Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) | 4 | * Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the | 7 | * under the terms of the GNU General Public License as published by the |
@@ -17,6 +17,7 @@ | |||
17 | #include "stb6000.h" | 17 | #include "stb6000.h" |
18 | #include "eds1547.h" | 18 | #include "eds1547.h" |
19 | #include "cx24116.h" | 19 | #include "cx24116.h" |
20 | #include "tda1002x.h" | ||
20 | 21 | ||
21 | #ifndef USB_PID_DW2102 | 22 | #ifndef USB_PID_DW2102 |
22 | #define USB_PID_DW2102 0x2102 | 23 | #define USB_PID_DW2102 0x2102 |
@@ -26,10 +27,18 @@ | |||
26 | #define USB_PID_DW2104 0x2104 | 27 | #define USB_PID_DW2104 0x2104 |
27 | #endif | 28 | #endif |
28 | 29 | ||
30 | #ifndef USB_PID_DW3101 | ||
31 | #define USB_PID_DW3101 0x3101 | ||
32 | #endif | ||
33 | |||
29 | #ifndef USB_PID_CINERGY_S | 34 | #ifndef USB_PID_CINERGY_S |
30 | #define USB_PID_CINERGY_S 0x0064 | 35 | #define USB_PID_CINERGY_S 0x0064 |
31 | #endif | 36 | #endif |
32 | 37 | ||
38 | #ifndef USB_PID_TEVII_S650 | ||
39 | #define USB_PID_TEVII_S650 0xd650 | ||
40 | #endif | ||
41 | |||
33 | #define DW210X_READ_MSG 0 | 42 | #define DW210X_READ_MSG 0 |
34 | #define DW210X_WRITE_MSG 1 | 43 | #define DW210X_WRITE_MSG 1 |
35 | 44 | ||
@@ -82,7 +91,7 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value, | |||
82 | static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | 91 | static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], |
83 | int num) | 92 | int num) |
84 | { | 93 | { |
85 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | 94 | struct dvb_usb_device *d = i2c_get_adapdata(adap); |
86 | int i = 0, ret = 0; | 95 | int i = 0, ret = 0; |
87 | u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0}; | 96 | u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0}; |
88 | u16 value; | 97 | u16 value; |
@@ -208,6 +217,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, | |||
208 | mutex_unlock(&d->i2c_mutex); | 217 | mutex_unlock(&d->i2c_mutex); |
209 | return num; | 218 | return num; |
210 | } | 219 | } |
220 | |||
211 | static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) | 221 | static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) |
212 | { | 222 | { |
213 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | 223 | struct dvb_usb_device *d = i2c_get_adapdata(adap); |
@@ -222,7 +232,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms | |||
222 | case 2: { | 232 | case 2: { |
223 | /* read */ | 233 | /* read */ |
224 | /* first write first register number */ | 234 | /* first write first register number */ |
225 | u8 ibuf [msg[1].len + 2], obuf[3]; | 235 | u8 ibuf[msg[1].len + 2], obuf[3]; |
226 | obuf[0] = 0xd0; | 236 | obuf[0] = 0xd0; |
227 | obuf[1] = msg[0].len; | 237 | obuf[1] = msg[0].len; |
228 | obuf[2] = msg[0].buf[0]; | 238 | obuf[2] = msg[0].buf[0]; |
@@ -296,7 +306,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i | |||
296 | case 2: { | 306 | case 2: { |
297 | /* read */ | 307 | /* read */ |
298 | /* first write first register number */ | 308 | /* first write first register number */ |
299 | u8 ibuf [msg[1].len + 2], obuf[3]; | 309 | u8 ibuf[msg[1].len + 2], obuf[3]; |
300 | obuf[0] = 0xaa; | 310 | obuf[0] = 0xaa; |
301 | obuf[1] = msg[0].len; | 311 | obuf[1] = msg[0].len; |
302 | obuf[2] = msg[0].buf[0]; | 312 | obuf[2] = msg[0].buf[0]; |
@@ -363,6 +373,69 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i | |||
363 | return num; | 373 | return num; |
364 | } | 374 | } |
365 | 375 | ||
376 | static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | ||
377 | int num) | ||
378 | { | ||
379 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
380 | int ret = 0, i; | ||
381 | |||
382 | if (!d) | ||
383 | return -ENODEV; | ||
384 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
385 | return -EAGAIN; | ||
386 | |||
387 | switch (num) { | ||
388 | case 2: { | ||
389 | /* read */ | ||
390 | /* first write first register number */ | ||
391 | u8 ibuf[msg[1].len + 2], obuf[3]; | ||
392 | obuf[0] = msg[0].addr << 1; | ||
393 | obuf[1] = msg[0].len; | ||
394 | obuf[2] = msg[0].buf[0]; | ||
395 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
396 | obuf, msg[0].len + 2, DW210X_WRITE_MSG); | ||
397 | /* second read registers */ | ||
398 | ret = dw210x_op_rw(d->udev, 0xc3, 0x19 , 0, | ||
399 | ibuf, msg[1].len + 2, DW210X_READ_MSG); | ||
400 | memcpy(msg[1].buf, ibuf + 2, msg[1].len); | ||
401 | |||
402 | break; | ||
403 | } | ||
404 | case 1: | ||
405 | switch (msg[0].addr) { | ||
406 | case 0x60: | ||
407 | case 0x0c: { | ||
408 | /* write to register */ | ||
409 | u8 obuf[msg[0].len + 2]; | ||
410 | obuf[0] = msg[0].addr << 1; | ||
411 | obuf[1] = msg[0].len; | ||
412 | memcpy(obuf + 2, msg[0].buf, msg[0].len); | ||
413 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
414 | obuf, msg[0].len + 2, DW210X_WRITE_MSG); | ||
415 | break; | ||
416 | } | ||
417 | case(DW2102_RC_QUERY): { | ||
418 | u8 ibuf[2]; | ||
419 | ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, | ||
420 | ibuf, 2, DW210X_READ_MSG); | ||
421 | memcpy(msg[0].buf, ibuf , 2); | ||
422 | break; | ||
423 | } | ||
424 | } | ||
425 | |||
426 | break; | ||
427 | } | ||
428 | |||
429 | for (i = 0; i < num; i++) { | ||
430 | deb_xfer("%02x:%02x: %s ", i, msg[i].addr, | ||
431 | msg[i].flags == 0 ? ">>>" : "<<<"); | ||
432 | debug_dump(msg[i].buf, msg[i].len, deb_xfer); | ||
433 | } | ||
434 | |||
435 | mutex_unlock(&d->i2c_mutex); | ||
436 | return num; | ||
437 | } | ||
438 | |||
366 | static u32 dw210x_i2c_func(struct i2c_adapter *adapter) | 439 | static u32 dw210x_i2c_func(struct i2c_adapter *adapter) |
367 | { | 440 | { |
368 | return I2C_FUNC_I2C; | 441 | return I2C_FUNC_I2C; |
@@ -388,6 +461,11 @@ static struct i2c_algorithm dw2104_i2c_algo = { | |||
388 | .functionality = dw210x_i2c_func, | 461 | .functionality = dw210x_i2c_func, |
389 | }; | 462 | }; |
390 | 463 | ||
464 | static struct i2c_algorithm dw3101_i2c_algo = { | ||
465 | .master_xfer = dw3101_i2c_transfer, | ||
466 | .functionality = dw210x_i2c_func, | ||
467 | }; | ||
468 | |||
391 | static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) | 469 | static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) |
392 | { | 470 | { |
393 | int i; | 471 | int i; |
@@ -407,6 +485,7 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) | |||
407 | debug_dump(eepromline, 16, deb_xfer); | 485 | debug_dump(eepromline, 16, deb_xfer); |
408 | } | 486 | } |
409 | } | 487 | } |
488 | |||
410 | memcpy(mac, eeprom + 8, 6); | 489 | memcpy(mac, eeprom + 8, 6); |
411 | return 0; | 490 | return 0; |
412 | }; | 491 | }; |
@@ -451,6 +530,11 @@ static struct si21xx_config serit_sp1511lhb_config = { | |||
451 | 530 | ||
452 | }; | 531 | }; |
453 | 532 | ||
533 | static struct tda10023_config dw3101_tda10023_config = { | ||
534 | .demod_address = 0x0c, | ||
535 | .invert = 1, | ||
536 | }; | ||
537 | |||
454 | static int dw2104_frontend_attach(struct dvb_usb_adapter *d) | 538 | static int dw2104_frontend_attach(struct dvb_usb_adapter *d) |
455 | { | 539 | { |
456 | if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config, | 540 | if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config, |
@@ -501,6 +585,17 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) | |||
501 | return -EIO; | 585 | return -EIO; |
502 | } | 586 | } |
503 | 587 | ||
588 | static int dw3101_frontend_attach(struct dvb_usb_adapter *d) | ||
589 | { | ||
590 | d->fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config, | ||
591 | &d->dev->i2c_adap, 0x48); | ||
592 | if (d->fe != NULL) { | ||
593 | info("Attached tda10023!\n"); | ||
594 | return 0; | ||
595 | } | ||
596 | return -EIO; | ||
597 | } | ||
598 | |||
504 | static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) | 599 | static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) |
505 | { | 600 | { |
506 | dvb_attach(dvb_pll_attach, adap->fe, 0x60, | 601 | dvb_attach(dvb_pll_attach, adap->fe, 0x60, |
@@ -516,6 +611,14 @@ static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap) | |||
516 | return 0; | 611 | return 0; |
517 | } | 612 | } |
518 | 613 | ||
614 | static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) | ||
615 | { | ||
616 | dvb_attach(dvb_pll_attach, adap->fe, 0x60, | ||
617 | &adap->dev->i2c_adap, DVB_PLL_TUA6034); | ||
618 | |||
619 | return 0; | ||
620 | } | ||
621 | |||
519 | static struct dvb_usb_rc_key dw210x_rc_keys[] = { | 622 | static struct dvb_usb_rc_key dw210x_rc_keys[] = { |
520 | { 0xf8, 0x0a, KEY_Q }, /*power*/ | 623 | { 0xf8, 0x0a, KEY_Q }, /*power*/ |
521 | { 0xf8, 0x0c, KEY_M }, /*mute*/ | 624 | { 0xf8, 0x0c, KEY_M }, /*mute*/ |
@@ -685,9 +788,10 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) | |||
685 | static struct usb_device_id dw2102_table[] = { | 788 | static struct usb_device_id dw2102_table[] = { |
686 | {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, | 789 | {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, |
687 | {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, | 790 | {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, |
688 | {USB_DEVICE(USB_VID_CYPRESS, 0x2104)}, | 791 | {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)}, |
689 | {USB_DEVICE(0x9022, 0xd650)}, | 792 | {USB_DEVICE(0x9022, USB_PID_TEVII_S650)}, |
690 | {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, | 793 | {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, |
794 | {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, | ||
691 | { } | 795 | { } |
692 | }; | 796 | }; |
693 | 797 | ||
@@ -748,7 +852,7 @@ static int dw2102_load_firmware(struct usb_device *dev, | |||
748 | } | 852 | } |
749 | /* init registers */ | 853 | /* init registers */ |
750 | switch (dev->descriptor.idProduct) { | 854 | switch (dev->descriptor.idProduct) { |
751 | case 0xd650: | 855 | case USB_PID_TEVII_S650: |
752 | dw2104_properties.rc_key_map = tevii_rc_keys; | 856 | dw2104_properties.rc_key_map = tevii_rc_keys; |
753 | dw2104_properties.rc_key_map_size = | 857 | dw2104_properties.rc_key_map_size = |
754 | ARRAY_SIZE(tevii_rc_keys); | 858 | ARRAY_SIZE(tevii_rc_keys); |
@@ -756,6 +860,8 @@ static int dw2102_load_firmware(struct usb_device *dev, | |||
756 | reset = 1; | 860 | reset = 1; |
757 | dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, | 861 | dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, |
758 | DW210X_WRITE_MSG); | 862 | DW210X_WRITE_MSG); |
863 | /* break omitted intentionally */ | ||
864 | case USB_PID_DW3101: | ||
759 | reset = 0; | 865 | reset = 0; |
760 | dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, | 866 | dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, |
761 | DW210X_WRITE_MSG); | 867 | DW210X_WRITE_MSG); |
@@ -799,6 +905,7 @@ static int dw2102_load_firmware(struct usb_device *dev, | |||
799 | DW210X_READ_MSG); | 905 | DW210X_READ_MSG); |
800 | break; | 906 | break; |
801 | } | 907 | } |
908 | |||
802 | msleep(100); | 909 | msleep(100); |
803 | kfree(p); | 910 | kfree(p); |
804 | } | 911 | } |
@@ -822,7 +929,7 @@ static struct dvb_usb_device_properties dw2102_properties = { | |||
822 | .num_adapters = 1, | 929 | .num_adapters = 1, |
823 | .download_firmware = dw2102_load_firmware, | 930 | .download_firmware = dw2102_load_firmware, |
824 | .read_mac_address = dw210x_read_mac_address, | 931 | .read_mac_address = dw210x_read_mac_address, |
825 | .adapter = { | 932 | .adapter = { |
826 | { | 933 | { |
827 | .frontend_attach = dw2102_frontend_attach, | 934 | .frontend_attach = dw2102_frontend_attach, |
828 | .streaming_ctrl = NULL, | 935 | .streaming_ctrl = NULL, |
@@ -903,12 +1010,57 @@ static struct dvb_usb_device_properties dw2104_properties = { | |||
903 | } | 1010 | } |
904 | }; | 1011 | }; |
905 | 1012 | ||
1013 | static struct dvb_usb_device_properties dw3101_properties = { | ||
1014 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
1015 | .usb_ctrl = DEVICE_SPECIFIC, | ||
1016 | .firmware = "dvb-usb-dw3101.fw", | ||
1017 | .no_reconnect = 1, | ||
1018 | |||
1019 | .i2c_algo = &dw3101_i2c_algo, | ||
1020 | .rc_key_map = dw210x_rc_keys, | ||
1021 | .rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys), | ||
1022 | .rc_interval = 150, | ||
1023 | .rc_query = dw2102_rc_query, | ||
1024 | |||
1025 | .generic_bulk_ctrl_endpoint = 0x81, | ||
1026 | /* parameter for the MPEG2-data transfer */ | ||
1027 | .num_adapters = 1, | ||
1028 | .download_firmware = dw2102_load_firmware, | ||
1029 | .read_mac_address = dw210x_read_mac_address, | ||
1030 | .adapter = { | ||
1031 | { | ||
1032 | .frontend_attach = dw3101_frontend_attach, | ||
1033 | .streaming_ctrl = NULL, | ||
1034 | .tuner_attach = dw3101_tuner_attach, | ||
1035 | .stream = { | ||
1036 | .type = USB_BULK, | ||
1037 | .count = 8, | ||
1038 | .endpoint = 0x82, | ||
1039 | .u = { | ||
1040 | .bulk = { | ||
1041 | .buffersize = 4096, | ||
1042 | } | ||
1043 | } | ||
1044 | }, | ||
1045 | } | ||
1046 | }, | ||
1047 | .num_device_descs = 1, | ||
1048 | .devices = { | ||
1049 | { "DVBWorld DVB-C 3101 USB2.0", | ||
1050 | {&dw2102_table[5], NULL}, | ||
1051 | {NULL}, | ||
1052 | }, | ||
1053 | } | ||
1054 | }; | ||
1055 | |||
906 | static int dw2102_probe(struct usb_interface *intf, | 1056 | static int dw2102_probe(struct usb_interface *intf, |
907 | const struct usb_device_id *id) | 1057 | const struct usb_device_id *id) |
908 | { | 1058 | { |
909 | if (0 == dvb_usb_device_init(intf, &dw2102_properties, | 1059 | if (0 == dvb_usb_device_init(intf, &dw2102_properties, |
910 | THIS_MODULE, NULL, adapter_nr) || | 1060 | THIS_MODULE, NULL, adapter_nr) || |
911 | 0 == dvb_usb_device_init(intf, &dw2104_properties, | 1061 | 0 == dvb_usb_device_init(intf, &dw2104_properties, |
1062 | THIS_MODULE, NULL, adapter_nr) || | ||
1063 | 0 == dvb_usb_device_init(intf, &dw3101_properties, | ||
912 | THIS_MODULE, NULL, adapter_nr)) { | 1064 | THIS_MODULE, NULL, adapter_nr)) { |
913 | return 0; | 1065 | return 0; |
914 | } | 1066 | } |
@@ -940,6 +1092,8 @@ module_init(dw2102_module_init); | |||
940 | module_exit(dw2102_module_exit); | 1092 | module_exit(dw2102_module_exit); |
941 | 1093 | ||
942 | MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); | 1094 | MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); |
943 | MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104 USB2.0 device"); | 1095 | MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," |
1096 | " DVB-C 3101 USB2.0," | ||
1097 | " TeVii S600, S650 USB2.0 devices"); | ||
944 | MODULE_VERSION("0.1"); | 1098 | MODULE_VERSION("0.1"); |
945 | MODULE_LICENSE("GPL"); | 1099 | MODULE_LICENSE("GPL"); |