diff options
author | Igor M. Liplianin <liplianin@me.by> | 2009-06-20 08:54:18 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-09-12 11:18:56 -0400 |
commit | d0a1ddad1c9723f4a61e9b216c4c34ac03344fdd (patch) | |
tree | 3c4865541b68e280d5866b1b149c46a8a9c02ec4 | |
parent | 2ccf5a9906564cd06facc846c32d065752268dcf (diff) |
V4L/DVB (12462): Add TeVii S630 USB DVB-S card support.
The card includes Intel ce5039(Zarlink zl10039) tuner
and Intel ce6313 (Zarlink zl10313) demod.
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/Kconfig | 6 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/dw2102.c | 181 |
2 files changed, 182 insertions, 5 deletions
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 496c1a37034c..8b8bc04ee980 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig | |||
@@ -253,7 +253,7 @@ config DVB_USB_AF9005_REMOTE | |||
253 | Afatech AF9005 based receiver. | 253 | Afatech AF9005 based receiver. |
254 | 254 | ||
255 | config DVB_USB_DW2102 | 255 | config DVB_USB_DW2102 |
256 | tristate "DvbWorld DVB-S/S2 USB2.0 support" | 256 | tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support" |
257 | depends on DVB_USB | 257 | depends on DVB_USB |
258 | select DVB_PLL if !DVB_FE_CUSTOMISE | 258 | select DVB_PLL if !DVB_FE_CUSTOMISE |
259 | select DVB_STV0299 if !DVB_FE_CUSTOMISE | 259 | select DVB_STV0299 if !DVB_FE_CUSTOMISE |
@@ -262,9 +262,11 @@ config DVB_USB_DW2102 | |||
262 | select DVB_CX24116 if !DVB_FE_CUSTOMISE | 262 | select DVB_CX24116 if !DVB_FE_CUSTOMISE |
263 | select DVB_SI21XX if !DVB_FE_CUSTOMISE | 263 | select DVB_SI21XX if !DVB_FE_CUSTOMISE |
264 | select DVB_TDA10021 if !DVB_FE_CUSTOMISE | 264 | select DVB_TDA10021 if !DVB_FE_CUSTOMISE |
265 | select DVB_MT312 if !DVB_FE_CUSTOMISE | ||
266 | select DVB_ZL10039 if !DVB_FE_CUSTOMISE | ||
265 | help | 267 | help |
266 | Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers | 268 | Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers |
267 | and the TeVii S650. | 269 | and the TeVii S650, S630. |
268 | 270 | ||
269 | config DVB_USB_CINERGY_T2 | 271 | config DVB_USB_CINERGY_T2 |
270 | tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver" | 272 | tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver" |
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 75de49c0d943..d9424c31472a 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c | |||
@@ -1,6 +1,6 @@ | |||
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, DVB-C 3101, | 2 | * DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101, |
3 | * TeVii S600, S650 Cards | 3 | * TeVii S600, S630, S650 Cards |
4 | * Copyright (C) 2008,2009 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 |
@@ -18,6 +18,8 @@ | |||
18 | #include "eds1547.h" | 18 | #include "eds1547.h" |
19 | #include "cx24116.h" | 19 | #include "cx24116.h" |
20 | #include "tda1002x.h" | 20 | #include "tda1002x.h" |
21 | #include "mt312.h" | ||
22 | #include "zl10039.h" | ||
21 | 23 | ||
22 | #ifndef USB_PID_DW2102 | 24 | #ifndef USB_PID_DW2102 |
23 | #define USB_PID_DW2102 0x2102 | 25 | #define USB_PID_DW2102 0x2102 |
@@ -39,6 +41,10 @@ | |||
39 | #define USB_PID_TEVII_S650 0xd650 | 41 | #define USB_PID_TEVII_S650 0xd650 |
40 | #endif | 42 | #endif |
41 | 43 | ||
44 | #ifndef USB_PID_TEVII_S630 | ||
45 | #define USB_PID_TEVII_S630 0xd630 | ||
46 | #endif | ||
47 | |||
42 | #define DW210X_READ_MSG 0 | 48 | #define DW210X_READ_MSG 0 |
43 | #define DW210X_WRITE_MSG 1 | 49 | #define DW210X_WRITE_MSG 1 |
44 | 50 | ||
@@ -436,6 +442,69 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
436 | return num; | 442 | return num; |
437 | } | 443 | } |
438 | 444 | ||
445 | static int s630_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | ||
446 | int num) | ||
447 | { | ||
448 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
449 | int ret = 0; | ||
450 | |||
451 | if (!d) | ||
452 | return -ENODEV; | ||
453 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
454 | return -EAGAIN; | ||
455 | |||
456 | switch (num) { | ||
457 | case 2: { /* read */ | ||
458 | u8 ibuf[msg[1].len], obuf[3]; | ||
459 | obuf[0] = msg[1].len; | ||
460 | obuf[1] = (msg[0].addr << 1); | ||
461 | obuf[2] = msg[0].buf[0]; | ||
462 | |||
463 | ret = dw210x_op_rw(d->udev, 0x90, 0, 0, | ||
464 | obuf, 3, DW210X_WRITE_MSG); | ||
465 | msleep(5); | ||
466 | ret = dw210x_op_rw(d->udev, 0x91, 0, 0, | ||
467 | ibuf, msg[1].len, DW210X_READ_MSG); | ||
468 | memcpy(msg[1].buf, ibuf, msg[1].len); | ||
469 | break; | ||
470 | } | ||
471 | case 1: | ||
472 | switch (msg[0].addr) { | ||
473 | case 0x60: | ||
474 | case 0x0e: { | ||
475 | /* write to zl10313, zl10039 register, */ | ||
476 | u8 obuf[msg[0].len + 2]; | ||
477 | obuf[0] = msg[0].len + 1; | ||
478 | obuf[1] = (msg[0].addr << 1); | ||
479 | memcpy(obuf + 2, msg[0].buf, msg[0].len); | ||
480 | ret = dw210x_op_rw(d->udev, 0x80, 0, 0, | ||
481 | obuf, msg[0].len + 2, DW210X_WRITE_MSG); | ||
482 | break; | ||
483 | } | ||
484 | case (DW2102_RC_QUERY): { | ||
485 | u8 ibuf[4]; | ||
486 | ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, | ||
487 | ibuf, 4, DW210X_READ_MSG); | ||
488 | msg[0].buf[0] = ibuf[3]; | ||
489 | break; | ||
490 | } | ||
491 | case (DW2102_VOLTAGE_CTRL): { | ||
492 | u8 obuf[2]; | ||
493 | obuf[0] = 0x03; | ||
494 | obuf[1] = msg[0].buf[0]; | ||
495 | ret = dw210x_op_rw(d->udev, 0x8a, 0, 0, | ||
496 | obuf, 2, DW210X_WRITE_MSG); | ||
497 | break; | ||
498 | } | ||
499 | } | ||
500 | |||
501 | break; | ||
502 | } | ||
503 | |||
504 | mutex_unlock(&d->i2c_mutex); | ||
505 | return num; | ||
506 | } | ||
507 | |||
439 | static u32 dw210x_i2c_func(struct i2c_adapter *adapter) | 508 | static u32 dw210x_i2c_func(struct i2c_adapter *adapter) |
440 | { | 509 | { |
441 | return I2C_FUNC_I2C; | 510 | return I2C_FUNC_I2C; |
@@ -466,6 +535,11 @@ static struct i2c_algorithm dw3101_i2c_algo = { | |||
466 | .functionality = dw210x_i2c_func, | 535 | .functionality = dw210x_i2c_func, |
467 | }; | 536 | }; |
468 | 537 | ||
538 | static struct i2c_algorithm s630_i2c_algo = { | ||
539 | .master_xfer = s630_i2c_transfer, | ||
540 | .functionality = dw210x_i2c_func, | ||
541 | }; | ||
542 | |||
469 | static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) | 543 | static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) |
470 | { | 544 | { |
471 | int i; | 545 | int i; |
@@ -490,6 +564,37 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) | |||
490 | return 0; | 564 | return 0; |
491 | }; | 565 | }; |
492 | 566 | ||
567 | static int s630_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) | ||
568 | { | ||
569 | int i, ret; | ||
570 | u8 buf[3], eeprom[256], eepromline[16]; | ||
571 | |||
572 | for (i = 0; i < 256; i++) { | ||
573 | buf[0] = 1; | ||
574 | buf[1] = 0xa0; | ||
575 | buf[2] = i; | ||
576 | ret = dw210x_op_rw(d->udev, 0x90, 0, 0, | ||
577 | buf, 3, DW210X_WRITE_MSG); | ||
578 | ret = dw210x_op_rw(d->udev, 0x91, 0, 0, | ||
579 | buf, 1, DW210X_READ_MSG); | ||
580 | if (ret < 0) { | ||
581 | err("read eeprom failed."); | ||
582 | return -1; | ||
583 | } else { | ||
584 | eepromline[i % 16] = buf[0]; | ||
585 | eeprom[i] = buf[0]; | ||
586 | } | ||
587 | |||
588 | if ((i % 16) == 15) { | ||
589 | deb_xfer("%02x: ", i - 15); | ||
590 | debug_dump(eepromline, 16, deb_xfer); | ||
591 | } | ||
592 | } | ||
593 | |||
594 | memcpy(mac, eeprom + 16, 6); | ||
595 | return 0; | ||
596 | }; | ||
597 | |||
493 | static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | 598 | static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) |
494 | { | 599 | { |
495 | static u8 command_13v[1] = {0x00}; | 600 | static u8 command_13v[1] = {0x00}; |
@@ -535,6 +640,10 @@ static struct tda10023_config dw3101_tda10023_config = { | |||
535 | .invert = 1, | 640 | .invert = 1, |
536 | }; | 641 | }; |
537 | 642 | ||
643 | static struct mt312_config zl313_config = { | ||
644 | .demod_address = 0x0e, | ||
645 | }; | ||
646 | |||
538 | static int dw2104_frontend_attach(struct dvb_usb_adapter *d) | 647 | static int dw2104_frontend_attach(struct dvb_usb_adapter *d) |
539 | { | 648 | { |
540 | if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config, | 649 | if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config, |
@@ -596,6 +705,18 @@ static int dw3101_frontend_attach(struct dvb_usb_adapter *d) | |||
596 | return -EIO; | 705 | return -EIO; |
597 | } | 706 | } |
598 | 707 | ||
708 | static int s630_frontend_attach(struct dvb_usb_adapter *d) | ||
709 | { | ||
710 | d->fe = dvb_attach(mt312_attach, &zl313_config, | ||
711 | &d->dev->i2c_adap); | ||
712 | if (d->fe != NULL) { | ||
713 | d->fe->ops.set_voltage = dw210x_set_voltage; | ||
714 | info("Attached zl10313!\n"); | ||
715 | return 0; | ||
716 | } | ||
717 | return -EIO; | ||
718 | } | ||
719 | |||
599 | static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) | 720 | static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) |
600 | { | 721 | { |
601 | dvb_attach(dvb_pll_attach, adap->fe, 0x60, | 722 | dvb_attach(dvb_pll_attach, adap->fe, 0x60, |
@@ -619,6 +740,14 @@ static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) | |||
619 | return 0; | 740 | return 0; |
620 | } | 741 | } |
621 | 742 | ||
743 | static int s630_zl10039_tuner_attach(struct dvb_usb_adapter *adap) | ||
744 | { | ||
745 | dvb_attach(zl10039_attach, adap->fe, 0x60, | ||
746 | &adap->dev->i2c_adap); | ||
747 | |||
748 | return 0; | ||
749 | } | ||
750 | |||
622 | static struct dvb_usb_rc_key dw210x_rc_keys[] = { | 751 | static struct dvb_usb_rc_key dw210x_rc_keys[] = { |
623 | { 0xf8, 0x0a, KEY_Q }, /*power*/ | 752 | { 0xf8, 0x0a, KEY_Q }, /*power*/ |
624 | { 0xf8, 0x0c, KEY_M }, /*mute*/ | 753 | { 0xf8, 0x0c, KEY_M }, /*mute*/ |
@@ -763,7 +892,7 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) | |||
763 | } | 892 | } |
764 | 893 | ||
765 | *state = REMOTE_NO_KEY_PRESSED; | 894 | *state = REMOTE_NO_KEY_PRESSED; |
766 | if (dw2102_i2c_transfer(&d->i2c_adap, &msg, 1) == 1) { | 895 | if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) { |
767 | for (i = 0; i < keymap_size ; i++) { | 896 | for (i = 0; i < keymap_size ; i++) { |
768 | if (keymap[i].data == msg.buf[0]) { | 897 | if (keymap[i].data == msg.buf[0]) { |
769 | *state = REMOTE_KEY_PRESSED; | 898 | *state = REMOTE_KEY_PRESSED; |
@@ -792,6 +921,7 @@ static struct usb_device_id dw2102_table[] = { | |||
792 | {USB_DEVICE(0x9022, USB_PID_TEVII_S650)}, | 921 | {USB_DEVICE(0x9022, USB_PID_TEVII_S650)}, |
793 | {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, | 922 | {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, |
794 | {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, | 923 | {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, |
924 | {USB_DEVICE(0x9022, USB_PID_TEVII_S630)}, | ||
795 | { } | 925 | { } |
796 | }; | 926 | }; |
797 | 927 | ||
@@ -806,6 +936,7 @@ static int dw2102_load_firmware(struct usb_device *dev, | |||
806 | u8 reset16[] = {0, 0, 0, 0, 0, 0, 0}; | 936 | u8 reset16[] = {0, 0, 0, 0, 0, 0, 0}; |
807 | const struct firmware *fw; | 937 | const struct firmware *fw; |
808 | const char *filename = "dvb-usb-dw2101.fw"; | 938 | const char *filename = "dvb-usb-dw2101.fw"; |
939 | |||
809 | switch (dev->descriptor.idProduct) { | 940 | switch (dev->descriptor.idProduct) { |
810 | case 0x2101: | 941 | case 0x2101: |
811 | ret = request_firmware(&fw, filename, &dev->dev); | 942 | ret = request_firmware(&fw, filename, &dev->dev); |
@@ -1053,6 +1184,48 @@ static struct dvb_usb_device_properties dw3101_properties = { | |||
1053 | } | 1184 | } |
1054 | }; | 1185 | }; |
1055 | 1186 | ||
1187 | static struct dvb_usb_device_properties s630_properties = { | ||
1188 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
1189 | .usb_ctrl = DEVICE_SPECIFIC, | ||
1190 | .firmware = "dvb-usb-s630.fw", | ||
1191 | .no_reconnect = 1, | ||
1192 | |||
1193 | .i2c_algo = &s630_i2c_algo, | ||
1194 | .rc_key_map = tevii_rc_keys, | ||
1195 | .rc_key_map_size = ARRAY_SIZE(tevii_rc_keys), | ||
1196 | .rc_interval = 150, | ||
1197 | .rc_query = dw2102_rc_query, | ||
1198 | |||
1199 | .generic_bulk_ctrl_endpoint = 0x81, | ||
1200 | .num_adapters = 1, | ||
1201 | .download_firmware = dw2102_load_firmware, | ||
1202 | .read_mac_address = s630_read_mac_address, | ||
1203 | .adapter = { | ||
1204 | { | ||
1205 | .frontend_attach = s630_frontend_attach, | ||
1206 | .streaming_ctrl = NULL, | ||
1207 | .tuner_attach = s630_zl10039_tuner_attach, | ||
1208 | .stream = { | ||
1209 | .type = USB_BULK, | ||
1210 | .count = 8, | ||
1211 | .endpoint = 0x82, | ||
1212 | .u = { | ||
1213 | .bulk = { | ||
1214 | .buffersize = 4096, | ||
1215 | } | ||
1216 | } | ||
1217 | }, | ||
1218 | } | ||
1219 | }, | ||
1220 | .num_device_descs = 1, | ||
1221 | .devices = { | ||
1222 | {"TeVii S630 USB", | ||
1223 | {&dw2102_table[6], NULL}, | ||
1224 | {NULL}, | ||
1225 | }, | ||
1226 | } | ||
1227 | }; | ||
1228 | |||
1056 | static int dw2102_probe(struct usb_interface *intf, | 1229 | static int dw2102_probe(struct usb_interface *intf, |
1057 | const struct usb_device_id *id) | 1230 | const struct usb_device_id *id) |
1058 | { | 1231 | { |
@@ -1061,6 +1234,8 @@ static int dw2102_probe(struct usb_interface *intf, | |||
1061 | 0 == dvb_usb_device_init(intf, &dw2104_properties, | 1234 | 0 == dvb_usb_device_init(intf, &dw2104_properties, |
1062 | THIS_MODULE, NULL, adapter_nr) || | 1235 | THIS_MODULE, NULL, adapter_nr) || |
1063 | 0 == dvb_usb_device_init(intf, &dw3101_properties, | 1236 | 0 == dvb_usb_device_init(intf, &dw3101_properties, |
1237 | THIS_MODULE, NULL, adapter_nr) || | ||
1238 | 0 == dvb_usb_device_init(intf, &s630_properties, | ||
1064 | THIS_MODULE, NULL, adapter_nr)) { | 1239 | THIS_MODULE, NULL, adapter_nr)) { |
1065 | return 0; | 1240 | return 0; |
1066 | } | 1241 | } |
@@ -1094,6 +1269,6 @@ module_exit(dw2102_module_exit); | |||
1094 | MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); | 1269 | MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); |
1095 | MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," | 1270 | MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," |
1096 | " DVB-C 3101 USB2.0," | 1271 | " DVB-C 3101 USB2.0," |
1097 | " TeVii S600, S650 USB2.0 devices"); | 1272 | " TeVii S600, S630, S650 USB2.0 devices"); |
1098 | MODULE_VERSION("0.1"); | 1273 | MODULE_VERSION("0.1"); |
1099 | MODULE_LICENSE("GPL"); | 1274 | MODULE_LICENSE("GPL"); |