diff options
Diffstat (limited to 'drivers/media/usb/dvb-usb/cxusb.c')
-rw-r--r-- | drivers/media/usb/dvb-usb/cxusb.c | 130 |
1 files changed, 128 insertions, 2 deletions
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 16bc579d140..356abb369c2 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -44,6 +44,7 @@ #include "atbm8830.h" #include "si2168.h" #include "si2157.h" +#include "sp2.h" /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 80 @@ -175,7 +176,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], for (i = 0; i < num; i++) { - if (d->udev->descriptor.idVendor == USB_VID_MEDION) + if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_MEDION) switch (msg[i].addr) { case 0x63: cxusb_gpio_tuner(d, 0); @@ -672,6 +673,70 @@ static struct rc_map_table rc_map_d680_dmb_table[] = { { 0x0025, KEY_POWER }, }; +static int cxusb_tt_ct2_4400_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +{ + u8 wbuf[2]; + u8 rbuf[6]; + int ret; + struct i2c_msg msg[] = { + { + .addr = 0x51, + .flags = 0, + .buf = wbuf, + .len = 2, + }, { + .addr = 0x51, + .flags = I2C_M_RD, + .buf = rbuf, + .len = 6, + } + }; + + wbuf[0] = 0x1e; + wbuf[1] = 0x00; + ret = cxusb_i2c_xfer(&d->i2c_adap, msg, 2); + + if (ret == 2) { + memcpy(mac, rbuf, 6); + return 0; + } else { + if (ret < 0) + return ret; + return -EIO; + } +} + +static int cxusb_tt_ct2_4650_ci_ctrl(void *priv, u8 read, int addr, + u8 data, int *mem) +{ + struct dvb_usb_device *d = priv; + u8 wbuf[3]; + u8 rbuf[2]; + int ret; + + wbuf[0] = (addr >> 8) & 0xff; + wbuf[1] = addr & 0xff; + + if (read) { + ret = cxusb_ctrl_msg(d, CMD_SP2_CI_READ, wbuf, 2, rbuf, 2); + } else { + wbuf[2] = data; + ret = cxusb_ctrl_msg(d, CMD_SP2_CI_WRITE, wbuf, 3, rbuf, 1); + } + + if (ret) + goto err; + + if (read) + *mem = rbuf[1]; + + return 0; +err: + deb_info("%s: ci usb write returned %d\n", __func__, ret); + return ret; + +} + static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) { static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 }; @@ -1350,9 +1415,12 @@ static int cxusb_tt_ct2_4400_attach(struct dvb_usb_adapter *adap) struct i2c_adapter *adapter; struct i2c_client *client_demod; struct i2c_client *client_tuner; + struct i2c_client *client_ci; struct i2c_board_info info; struct si2168_config si2168_config; struct si2157_config si2157_config; + struct sp2_config sp2_config; + u8 o[2], i; /* reset the tuner */ if (cxusb_tt_ct2_4400_gpio_tuner(d, 0) < 0) { @@ -1369,6 +1437,7 @@ static int cxusb_tt_ct2_4400_attach(struct dvb_usb_adapter *adap) /* attach frontend */ si2168_config.i2c_adapter = &adapter; si2168_config.fe = &adap->fe_adap[0].fe; + si2168_config.ts_mode = SI2168_TS_PARALLEL; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2168", I2C_NAME_SIZE); info.addr = 0x64; @@ -1408,6 +1477,48 @@ static int cxusb_tt_ct2_4400_attach(struct dvb_usb_adapter *adap) st->i2c_client_tuner = client_tuner; + /* initialize CI */ + if (d->udev->descriptor.idProduct == + USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI) { + + memcpy(o, "\xc0\x01", 2); + cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); + msleep(100); + + memcpy(o, "\xc0\x00", 2); + cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); + msleep(100); + + memset(&sp2_config, 0, sizeof(sp2_config)); + sp2_config.dvb_adap = &adap->dvb_adap; + sp2_config.priv = d; + sp2_config.ci_control = cxusb_tt_ct2_4650_ci_ctrl; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "sp2", I2C_NAME_SIZE); + info.addr = 0x40; + info.platform_data = &sp2_config; + request_module(info.type); + client_ci = i2c_new_device(&d->i2c_adap, &info); + if (client_ci == NULL || client_ci->dev.driver == NULL) { + module_put(client_tuner->dev.driver->owner); + i2c_unregister_device(client_tuner); + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + return -ENODEV; + } + if (!try_module_get(client_ci->dev.driver->owner)) { + i2c_unregister_device(client_ci); + module_put(client_tuner->dev.driver->owner); + i2c_unregister_device(client_tuner); + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + return -ENODEV; + } + + st->i2c_client_ci = client_ci; + + } + return 0; } @@ -1537,6 +1648,13 @@ static void cxusb_disconnect(struct usb_interface *intf) struct cxusb_state *st = d->priv; struct i2c_client *client; + /* remove I2C client for CI */ + client = st->i2c_client_ci; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + /* remove I2C client for tuner */ client = st->i2c_client_tuner; if (client) { @@ -1576,6 +1694,7 @@ static struct usb_device_id cxusb_table [] = { { USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) }, { USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) }, { USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_TVSTICK_CT2_4400) }, + { USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); @@ -2230,6 +2349,8 @@ static struct dvb_usb_device_properties cxusb_tt_ct2_4400_properties = { .size_of_priv = sizeof(struct cxusb_state), .num_adapters = 1, + .read_mac_address = cxusb_tt_ct2_4400_read_mac_address, + .adapter = { { .num_frontends = 1, @@ -2265,13 +2386,18 @@ static struct dvb_usb_device_properties cxusb_tt_ct2_4400_properties = { .rc_interval = 150, }, - .num_device_descs = 1, + .num_device_descs = 2, .devices = { { "TechnoTrend TVStick CT2-4400", { NULL }, { &cxusb_table[20], NULL }, }, + { + "TechnoTrend TT-connect CT2-4650 CI", + { NULL }, + { &cxusb_table[21], NULL }, + }, } }; |