18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Thanks to Afatech who kindly provided information. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "af9015.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic int dvb_usb_af9015_remote; 138c2ecf20Sopenharmony_cimodule_param_named(remote, dvb_usb_af9015_remote, int, 0644); 148c2ecf20Sopenharmony_ciMODULE_PARM_DESC(remote, "select remote"); 158c2ecf20Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci#define REQ_HDR_LEN 8 /* send header size */ 208c2ecf20Sopenharmony_ci#define ACK_HDR_LEN 2 /* rece header size */ 218c2ecf20Sopenharmony_ci struct af9015_state *state = d_to_priv(d); 228c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 238c2ecf20Sopenharmony_ci int ret, wlen, rlen; 248c2ecf20Sopenharmony_ci u8 write = 1; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci mutex_lock(&d->usb_mutex); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci state->buf[0] = req->cmd; 298c2ecf20Sopenharmony_ci state->buf[1] = state->seq++; 308c2ecf20Sopenharmony_ci state->buf[2] = req->i2c_addr << 1; 318c2ecf20Sopenharmony_ci state->buf[3] = req->addr >> 8; 328c2ecf20Sopenharmony_ci state->buf[4] = req->addr & 0xff; 338c2ecf20Sopenharmony_ci state->buf[5] = req->mbox; 348c2ecf20Sopenharmony_ci state->buf[6] = req->addr_len; 358c2ecf20Sopenharmony_ci state->buf[7] = req->data_len; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci switch (req->cmd) { 388c2ecf20Sopenharmony_ci case GET_CONFIG: 398c2ecf20Sopenharmony_ci case READ_MEMORY: 408c2ecf20Sopenharmony_ci case RECONNECT_USB: 418c2ecf20Sopenharmony_ci write = 0; 428c2ecf20Sopenharmony_ci break; 438c2ecf20Sopenharmony_ci case READ_I2C: 448c2ecf20Sopenharmony_ci write = 0; 458c2ecf20Sopenharmony_ci state->buf[2] |= 0x01; /* set I2C direction */ 468c2ecf20Sopenharmony_ci fallthrough; 478c2ecf20Sopenharmony_ci case WRITE_I2C: 488c2ecf20Sopenharmony_ci state->buf[0] = READ_WRITE_I2C; 498c2ecf20Sopenharmony_ci break; 508c2ecf20Sopenharmony_ci case WRITE_MEMORY: 518c2ecf20Sopenharmony_ci if (((req->addr & 0xff00) == 0xff00) || 528c2ecf20Sopenharmony_ci ((req->addr & 0xff00) == 0xae00)) 538c2ecf20Sopenharmony_ci state->buf[0] = WRITE_VIRTUAL_MEMORY; 548c2ecf20Sopenharmony_ci case WRITE_VIRTUAL_MEMORY: 558c2ecf20Sopenharmony_ci case COPY_FIRMWARE: 568c2ecf20Sopenharmony_ci case DOWNLOAD_FIRMWARE: 578c2ecf20Sopenharmony_ci case BOOT: 588c2ecf20Sopenharmony_ci break; 598c2ecf20Sopenharmony_ci default: 608c2ecf20Sopenharmony_ci dev_err(&intf->dev, "unknown cmd %d\n", req->cmd); 618c2ecf20Sopenharmony_ci ret = -EIO; 628c2ecf20Sopenharmony_ci goto error; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* Buffer overflow check */ 668c2ecf20Sopenharmony_ci if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) || 678c2ecf20Sopenharmony_ci (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { 688c2ecf20Sopenharmony_ci dev_err(&intf->dev, "too much data, cmd %u, len %u\n", 698c2ecf20Sopenharmony_ci req->cmd, req->data_len); 708c2ecf20Sopenharmony_ci ret = -EINVAL; 718c2ecf20Sopenharmony_ci goto error; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* 758c2ecf20Sopenharmony_ci * Write receives seq + status = 2 bytes 768c2ecf20Sopenharmony_ci * Read receives seq + status + data = 2 + N bytes 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ci wlen = REQ_HDR_LEN; 798c2ecf20Sopenharmony_ci rlen = ACK_HDR_LEN; 808c2ecf20Sopenharmony_ci if (write) { 818c2ecf20Sopenharmony_ci wlen += req->data_len; 828c2ecf20Sopenharmony_ci memcpy(&state->buf[REQ_HDR_LEN], req->data, req->data_len); 838c2ecf20Sopenharmony_ci } else { 848c2ecf20Sopenharmony_ci rlen += req->data_len; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* no ack for these packets */ 888c2ecf20Sopenharmony_ci if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) 898c2ecf20Sopenharmony_ci rlen = 0; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci ret = dvb_usbv2_generic_rw_locked(d, state->buf, wlen, 928c2ecf20Sopenharmony_ci state->buf, rlen); 938c2ecf20Sopenharmony_ci if (ret) 948c2ecf20Sopenharmony_ci goto error; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* check status */ 978c2ecf20Sopenharmony_ci if (rlen && state->buf[1]) { 988c2ecf20Sopenharmony_ci dev_err(&intf->dev, "cmd failed %u\n", state->buf[1]); 998c2ecf20Sopenharmony_ci ret = -EIO; 1008c2ecf20Sopenharmony_ci goto error; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci /* read request, copy returned data to return buf */ 1048c2ecf20Sopenharmony_ci if (!write) 1058c2ecf20Sopenharmony_ci memcpy(req->data, &state->buf[ACK_HDR_LEN], req->data_len); 1068c2ecf20Sopenharmony_cierror: 1078c2ecf20Sopenharmony_ci mutex_unlock(&d->usb_mutex); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return ret; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, 1138c2ecf20Sopenharmony_ci u8 val) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct af9015_state *state = d_to_priv(d); 1168c2ecf20Sopenharmony_ci struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (addr == state->af9013_i2c_addr[0] || 1198c2ecf20Sopenharmony_ci addr == state->af9013_i2c_addr[1]) 1208c2ecf20Sopenharmony_ci req.addr_len = 3; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return af9015_ctrl_msg(d, &req); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, 1268c2ecf20Sopenharmony_ci u8 *val) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct af9015_state *state = d_to_priv(d); 1298c2ecf20Sopenharmony_ci struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (addr == state->af9013_i2c_addr[0] || 1328c2ecf20Sopenharmony_ci addr == state->af9013_i2c_addr[1]) 1338c2ecf20Sopenharmony_ci req.addr_len = 3; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return af9015_ctrl_msg(d, &req); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], 1398c2ecf20Sopenharmony_ci int num) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct dvb_usb_device *d = i2c_get_adapdata(adap); 1428c2ecf20Sopenharmony_ci struct af9015_state *state = d_to_priv(d); 1438c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 1448c2ecf20Sopenharmony_ci int ret; 1458c2ecf20Sopenharmony_ci u16 addr; 1468c2ecf20Sopenharmony_ci u8 mbox, addr_len; 1478c2ecf20Sopenharmony_ci struct req_t req; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* 1508c2ecf20Sopenharmony_ci * I2C multiplexing: 1518c2ecf20Sopenharmony_ci * There could be two tuners, both using same I2C address. Demodulator 1528c2ecf20Sopenharmony_ci * I2C-gate is only possibility to select correct tuner. 1538c2ecf20Sopenharmony_ci * 1548c2ecf20Sopenharmony_ci * ........................................... 1558c2ecf20Sopenharmony_ci * . AF9015 integrates AF9013 demodulator . 1568c2ecf20Sopenharmony_ci * . ____________ ____________ . ____________ 1578c2ecf20Sopenharmony_ci * .| USB IF | | demod |. | tuner | 1588c2ecf20Sopenharmony_ci * .|------------| |------------|. |------------| 1598c2ecf20Sopenharmony_ci * .| AF9015 | | AF9013 |. | MXL5003 | 1608c2ecf20Sopenharmony_ci * .| |--+--I2C-----|-----/ -----|.----I2C-----| | 1618c2ecf20Sopenharmony_ci * .| | | | addr 0x1c |. | addr 0x63 | 1628c2ecf20Sopenharmony_ci * .|____________| | |____________|. |____________| 1638c2ecf20Sopenharmony_ci * .................|......................... 1648c2ecf20Sopenharmony_ci * | ____________ ____________ 1658c2ecf20Sopenharmony_ci * | | demod | | tuner | 1668c2ecf20Sopenharmony_ci * | |------------| |------------| 1678c2ecf20Sopenharmony_ci * | | AF9013 | | MXL5003 | 1688c2ecf20Sopenharmony_ci * +--I2C-----|-----/ -----|-----I2C-----| | 1698c2ecf20Sopenharmony_ci * | addr 0x1d | | addr 0x63 | 1708c2ecf20Sopenharmony_ci * |____________| |____________| 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (msg[0].len == 0 || msg[0].flags & I2C_M_RD) { 1748c2ecf20Sopenharmony_ci addr = 0x0000; 1758c2ecf20Sopenharmony_ci mbox = 0; 1768c2ecf20Sopenharmony_ci addr_len = 0; 1778c2ecf20Sopenharmony_ci } else if (msg[0].len == 1) { 1788c2ecf20Sopenharmony_ci addr = msg[0].buf[0]; 1798c2ecf20Sopenharmony_ci mbox = 0; 1808c2ecf20Sopenharmony_ci addr_len = 1; 1818c2ecf20Sopenharmony_ci } else if (msg[0].len == 2) { 1828c2ecf20Sopenharmony_ci addr = msg[0].buf[0] << 8 | msg[0].buf[1] << 0; 1838c2ecf20Sopenharmony_ci mbox = 0; 1848c2ecf20Sopenharmony_ci addr_len = 2; 1858c2ecf20Sopenharmony_ci } else { 1868c2ecf20Sopenharmony_ci addr = msg[0].buf[0] << 8 | msg[0].buf[1] << 0; 1878c2ecf20Sopenharmony_ci mbox = msg[0].buf[2]; 1888c2ecf20Sopenharmony_ci addr_len = 3; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (num == 1 && !(msg[0].flags & I2C_M_RD)) { 1928c2ecf20Sopenharmony_ci /* i2c write */ 1938c2ecf20Sopenharmony_ci if (msg[0].len > 21) { 1948c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 1958c2ecf20Sopenharmony_ci goto err; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci if (msg[0].addr == state->af9013_i2c_addr[0]) 1988c2ecf20Sopenharmony_ci req.cmd = WRITE_MEMORY; 1998c2ecf20Sopenharmony_ci else 2008c2ecf20Sopenharmony_ci req.cmd = WRITE_I2C; 2018c2ecf20Sopenharmony_ci req.i2c_addr = msg[0].addr; 2028c2ecf20Sopenharmony_ci req.addr = addr; 2038c2ecf20Sopenharmony_ci req.mbox = mbox; 2048c2ecf20Sopenharmony_ci req.addr_len = addr_len; 2058c2ecf20Sopenharmony_ci req.data_len = msg[0].len - addr_len; 2068c2ecf20Sopenharmony_ci req.data = &msg[0].buf[addr_len]; 2078c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 2088c2ecf20Sopenharmony_ci } else if (num == 2 && !(msg[0].flags & I2C_M_RD) && 2098c2ecf20Sopenharmony_ci (msg[1].flags & I2C_M_RD)) { 2108c2ecf20Sopenharmony_ci /* i2c write + read */ 2118c2ecf20Sopenharmony_ci if (msg[0].len > 3 || msg[1].len > 61) { 2128c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 2138c2ecf20Sopenharmony_ci goto err; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci if (msg[0].addr == state->af9013_i2c_addr[0]) 2168c2ecf20Sopenharmony_ci req.cmd = READ_MEMORY; 2178c2ecf20Sopenharmony_ci else 2188c2ecf20Sopenharmony_ci req.cmd = READ_I2C; 2198c2ecf20Sopenharmony_ci req.i2c_addr = msg[0].addr; 2208c2ecf20Sopenharmony_ci req.addr = addr; 2218c2ecf20Sopenharmony_ci req.mbox = mbox; 2228c2ecf20Sopenharmony_ci req.addr_len = addr_len; 2238c2ecf20Sopenharmony_ci req.data_len = msg[1].len; 2248c2ecf20Sopenharmony_ci req.data = &msg[1].buf[0]; 2258c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 2268c2ecf20Sopenharmony_ci } else if (num == 1 && (msg[0].flags & I2C_M_RD)) { 2278c2ecf20Sopenharmony_ci /* i2c read */ 2288c2ecf20Sopenharmony_ci if (msg[0].len > 61) { 2298c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 2308c2ecf20Sopenharmony_ci goto err; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci if (msg[0].addr == state->af9013_i2c_addr[0]) { 2338c2ecf20Sopenharmony_ci ret = -EINVAL; 2348c2ecf20Sopenharmony_ci goto err; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci req.cmd = READ_I2C; 2378c2ecf20Sopenharmony_ci req.i2c_addr = msg[0].addr; 2388c2ecf20Sopenharmony_ci req.addr = addr; 2398c2ecf20Sopenharmony_ci req.mbox = mbox; 2408c2ecf20Sopenharmony_ci req.addr_len = addr_len; 2418c2ecf20Sopenharmony_ci req.data_len = msg[0].len; 2428c2ecf20Sopenharmony_ci req.data = &msg[0].buf[0]; 2438c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 2448c2ecf20Sopenharmony_ci } else { 2458c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 2468c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "unknown msg, num %u\n", num); 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci if (ret) 2498c2ecf20Sopenharmony_ci goto err; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return num; 2528c2ecf20Sopenharmony_cierr: 2538c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "failed %d\n", ret); 2548c2ecf20Sopenharmony_ci return ret; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic u32 af9015_i2c_func(struct i2c_adapter *adapter) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci return I2C_FUNC_I2C; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic struct i2c_algorithm af9015_i2c_algo = { 2638c2ecf20Sopenharmony_ci .master_xfer = af9015_i2c_xfer, 2648c2ecf20Sopenharmony_ci .functionality = af9015_i2c_func, 2658c2ecf20Sopenharmony_ci}; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic int af9015_identify_state(struct dvb_usb_device *d, const char **name) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 2708c2ecf20Sopenharmony_ci int ret; 2718c2ecf20Sopenharmony_ci u8 reply; 2728c2ecf20Sopenharmony_ci struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply}; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 2758c2ecf20Sopenharmony_ci if (ret) 2768c2ecf20Sopenharmony_ci return ret; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "reply %02x\n", reply); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (reply == 0x02) 2818c2ecf20Sopenharmony_ci ret = WARM; 2828c2ecf20Sopenharmony_ci else 2838c2ecf20Sopenharmony_ci ret = COLD; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci return ret; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic int af9015_download_firmware(struct dvb_usb_device *d, 2898c2ecf20Sopenharmony_ci const struct firmware *firmware) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct af9015_state *state = d_to_priv(d); 2928c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 2938c2ecf20Sopenharmony_ci int ret, i, rem; 2948c2ecf20Sopenharmony_ci struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; 2958c2ecf20Sopenharmony_ci u16 checksum; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "\n"); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* Calc checksum, we need it when copy firmware to slave demod */ 3008c2ecf20Sopenharmony_ci for (i = 0, checksum = 0; i < firmware->size; i++) 3018c2ecf20Sopenharmony_ci checksum += firmware->data[i]; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci state->firmware_size = firmware->size; 3048c2ecf20Sopenharmony_ci state->firmware_checksum = checksum; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci #define LEN_MAX (BUF_LEN - REQ_HDR_LEN) /* Max payload size */ 3078c2ecf20Sopenharmony_ci for (rem = firmware->size; rem > 0; rem -= LEN_MAX) { 3088c2ecf20Sopenharmony_ci req.data_len = min(LEN_MAX, rem); 3098c2ecf20Sopenharmony_ci req.data = (u8 *)&firmware->data[firmware->size - rem]; 3108c2ecf20Sopenharmony_ci req.addr = 0x5100 + firmware->size - rem; 3118c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 3128c2ecf20Sopenharmony_ci if (ret) { 3138c2ecf20Sopenharmony_ci dev_err(&intf->dev, "firmware download failed %d\n", 3148c2ecf20Sopenharmony_ci ret); 3158c2ecf20Sopenharmony_ci goto err; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci req.cmd = BOOT; 3208c2ecf20Sopenharmony_ci req.data_len = 0; 3218c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 3228c2ecf20Sopenharmony_ci if (ret) { 3238c2ecf20Sopenharmony_ci dev_err(&intf->dev, "firmware boot failed %d\n", ret); 3248c2ecf20Sopenharmony_ci goto err; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci return 0; 3288c2ecf20Sopenharmony_cierr: 3298c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "failed %d\n", ret); 3308c2ecf20Sopenharmony_ci return ret; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci#define AF9015_EEPROM_SIZE 256 3348c2ecf20Sopenharmony_ci/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */ 3358c2ecf20Sopenharmony_ci#define GOLDEN_RATIO_PRIME_32 0x9e370001UL 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci/* hash (and dump) eeprom */ 3388c2ecf20Sopenharmony_cistatic int af9015_eeprom_hash(struct dvb_usb_device *d) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci struct af9015_state *state = d_to_priv(d); 3418c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 3428c2ecf20Sopenharmony_ci int ret, i; 3438c2ecf20Sopenharmony_ci u8 buf[AF9015_EEPROM_SIZE]; 3448c2ecf20Sopenharmony_ci struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, NULL}; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* read eeprom */ 3478c2ecf20Sopenharmony_ci for (i = 0; i < AF9015_EEPROM_SIZE; i++) { 3488c2ecf20Sopenharmony_ci req.addr = i; 3498c2ecf20Sopenharmony_ci req.data = &buf[i]; 3508c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 3518c2ecf20Sopenharmony_ci if (ret < 0) 3528c2ecf20Sopenharmony_ci goto err; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* calculate checksum */ 3568c2ecf20Sopenharmony_ci for (i = 0; i < AF9015_EEPROM_SIZE / sizeof(u32); i++) { 3578c2ecf20Sopenharmony_ci state->eeprom_sum *= GOLDEN_RATIO_PRIME_32; 3588c2ecf20Sopenharmony_ci state->eeprom_sum += le32_to_cpu(((__le32 *)buf)[i]); 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci for (i = 0; i < AF9015_EEPROM_SIZE; i += 16) 3628c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "%*ph\n", 16, buf + i); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "eeprom sum %.8x\n", state->eeprom_sum); 3658c2ecf20Sopenharmony_ci return 0; 3668c2ecf20Sopenharmony_cierr: 3678c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "failed %d\n", ret); 3688c2ecf20Sopenharmony_ci return ret; 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic int af9015_read_config(struct dvb_usb_device *d) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci struct af9015_state *state = d_to_priv(d); 3748c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 3758c2ecf20Sopenharmony_ci int ret; 3768c2ecf20Sopenharmony_ci u8 val, i, offset = 0; 3778c2ecf20Sopenharmony_ci struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "\n"); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* IR remote controller */ 3828c2ecf20Sopenharmony_ci req.addr = AF9015_EEPROM_IR_MODE; 3838c2ecf20Sopenharmony_ci /* first message will timeout often due to possible hw bug */ 3848c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 3858c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 3868c2ecf20Sopenharmony_ci if (!ret) 3878c2ecf20Sopenharmony_ci break; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci if (ret) 3908c2ecf20Sopenharmony_ci goto error; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci ret = af9015_eeprom_hash(d); 3938c2ecf20Sopenharmony_ci if (ret) 3948c2ecf20Sopenharmony_ci goto error; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci state->ir_mode = val; 3978c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "ir mode %02x\n", val); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* TS mode - one or two receivers */ 4008c2ecf20Sopenharmony_ci req.addr = AF9015_EEPROM_TS_MODE; 4018c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 4028c2ecf20Sopenharmony_ci if (ret) 4038c2ecf20Sopenharmony_ci goto error; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci state->dual_mode = val; 4068c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "ts mode %02x\n", state->dual_mode); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci state->af9013_i2c_addr[0] = AF9015_I2C_DEMOD; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (state->dual_mode) { 4118c2ecf20Sopenharmony_ci /* read 2nd demodulator I2C address */ 4128c2ecf20Sopenharmony_ci req.addr = AF9015_EEPROM_DEMOD2_I2C; 4138c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 4148c2ecf20Sopenharmony_ci if (ret) 4158c2ecf20Sopenharmony_ci goto error; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci state->af9013_i2c_addr[1] = val >> 1; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci for (i = 0; i < state->dual_mode + 1; i++) { 4218c2ecf20Sopenharmony_ci if (i == 1) 4228c2ecf20Sopenharmony_ci offset = AF9015_EEPROM_OFFSET; 4238c2ecf20Sopenharmony_ci /* xtal */ 4248c2ecf20Sopenharmony_ci req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset; 4258c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 4268c2ecf20Sopenharmony_ci if (ret) 4278c2ecf20Sopenharmony_ci goto error; 4288c2ecf20Sopenharmony_ci switch (val) { 4298c2ecf20Sopenharmony_ci case 0: 4308c2ecf20Sopenharmony_ci state->af9013_pdata[i].clk = 28800000; 4318c2ecf20Sopenharmony_ci break; 4328c2ecf20Sopenharmony_ci case 1: 4338c2ecf20Sopenharmony_ci state->af9013_pdata[i].clk = 20480000; 4348c2ecf20Sopenharmony_ci break; 4358c2ecf20Sopenharmony_ci case 2: 4368c2ecf20Sopenharmony_ci state->af9013_pdata[i].clk = 28000000; 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci case 3: 4398c2ecf20Sopenharmony_ci state->af9013_pdata[i].clk = 25000000; 4408c2ecf20Sopenharmony_ci break; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "[%d] xtal %02x, clk %u\n", 4438c2ecf20Sopenharmony_ci i, val, state->af9013_pdata[i].clk); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* IF frequency */ 4468c2ecf20Sopenharmony_ci req.addr = AF9015_EEPROM_IF1H + offset; 4478c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 4488c2ecf20Sopenharmony_ci if (ret) 4498c2ecf20Sopenharmony_ci goto error; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci state->af9013_pdata[i].if_frequency = val << 8; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci req.addr = AF9015_EEPROM_IF1L + offset; 4548c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 4558c2ecf20Sopenharmony_ci if (ret) 4568c2ecf20Sopenharmony_ci goto error; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci state->af9013_pdata[i].if_frequency += val; 4598c2ecf20Sopenharmony_ci state->af9013_pdata[i].if_frequency *= 1000; 4608c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "[%d] if frequency %u\n", 4618c2ecf20Sopenharmony_ci i, state->af9013_pdata[i].if_frequency); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* MT2060 IF1 */ 4648c2ecf20Sopenharmony_ci req.addr = AF9015_EEPROM_MT2060_IF1H + offset; 4658c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 4668c2ecf20Sopenharmony_ci if (ret) 4678c2ecf20Sopenharmony_ci goto error; 4688c2ecf20Sopenharmony_ci state->mt2060_if1[i] = val << 8; 4698c2ecf20Sopenharmony_ci req.addr = AF9015_EEPROM_MT2060_IF1L + offset; 4708c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 4718c2ecf20Sopenharmony_ci if (ret) 4728c2ecf20Sopenharmony_ci goto error; 4738c2ecf20Sopenharmony_ci state->mt2060_if1[i] += val; 4748c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "[%d] MT2060 IF1 %u\n", 4758c2ecf20Sopenharmony_ci i, state->mt2060_if1[i]); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* tuner */ 4788c2ecf20Sopenharmony_ci req.addr = AF9015_EEPROM_TUNER_ID1 + offset; 4798c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 4808c2ecf20Sopenharmony_ci if (ret) 4818c2ecf20Sopenharmony_ci goto error; 4828c2ecf20Sopenharmony_ci switch (val) { 4838c2ecf20Sopenharmony_ci case AF9013_TUNER_ENV77H11D5: 4848c2ecf20Sopenharmony_ci case AF9013_TUNER_MT2060: 4858c2ecf20Sopenharmony_ci case AF9013_TUNER_QT1010: 4868c2ecf20Sopenharmony_ci case AF9013_TUNER_UNKNOWN: 4878c2ecf20Sopenharmony_ci case AF9013_TUNER_MT2060_2: 4888c2ecf20Sopenharmony_ci case AF9013_TUNER_TDA18271: 4898c2ecf20Sopenharmony_ci case AF9013_TUNER_QT1010A: 4908c2ecf20Sopenharmony_ci case AF9013_TUNER_TDA18218: 4918c2ecf20Sopenharmony_ci state->af9013_pdata[i].spec_inv = 1; 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci case AF9013_TUNER_MXL5003D: 4948c2ecf20Sopenharmony_ci case AF9013_TUNER_MXL5005D: 4958c2ecf20Sopenharmony_ci case AF9013_TUNER_MXL5005R: 4968c2ecf20Sopenharmony_ci case AF9013_TUNER_MXL5007T: 4978c2ecf20Sopenharmony_ci state->af9013_pdata[i].spec_inv = 0; 4988c2ecf20Sopenharmony_ci break; 4998c2ecf20Sopenharmony_ci case AF9013_TUNER_MC44S803: 5008c2ecf20Sopenharmony_ci state->af9013_pdata[i].gpio[1] = AF9013_GPIO_LO; 5018c2ecf20Sopenharmony_ci state->af9013_pdata[i].spec_inv = 1; 5028c2ecf20Sopenharmony_ci break; 5038c2ecf20Sopenharmony_ci default: 5048c2ecf20Sopenharmony_ci dev_err(&intf->dev, 5058c2ecf20Sopenharmony_ci "tuner id %02x not supported, please report!\n", 5068c2ecf20Sopenharmony_ci val); 5078c2ecf20Sopenharmony_ci return -ENODEV; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci state->af9013_pdata[i].tuner = val; 5118c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "[%d] tuner id %02x\n", i, val); 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cierror: 5158c2ecf20Sopenharmony_ci if (ret) 5168c2ecf20Sopenharmony_ci dev_err(&intf->dev, "eeprom read failed %d\n", ret); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* 5198c2ecf20Sopenharmony_ci * AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM 5208c2ecf20Sopenharmony_ci * content :-( Override some wrong values here. Ditto for the 5218c2ecf20Sopenharmony_ci * AVerTV Red HD+ (A850T) device. 5228c2ecf20Sopenharmony_ci */ 5238c2ecf20Sopenharmony_ci if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA && 5248c2ecf20Sopenharmony_ci ((le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_AVERMEDIA_A850) || 5258c2ecf20Sopenharmony_ci (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_AVERMEDIA_A850T))) { 5268c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "AverMedia A850: overriding config\n"); 5278c2ecf20Sopenharmony_ci /* disable dual mode */ 5288c2ecf20Sopenharmony_ci state->dual_mode = 0; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci /* set correct IF */ 5318c2ecf20Sopenharmony_ci state->af9013_pdata[0].if_frequency = 4570000; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci return ret; 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic int af9015_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, 5388c2ecf20Sopenharmony_ci struct usb_data_stream_properties *stream) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci struct dvb_usb_device *d = fe_to_d(fe); 5418c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "adap %u\n", fe_to_adap(fe)->id); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (d->udev->speed == USB_SPEED_FULL) 5468c2ecf20Sopenharmony_ci stream->u.bulk.buffersize = 5 * 188; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci return 0; 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic int af9015_streaming_ctrl(struct dvb_frontend *fe, int onoff) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci struct dvb_usb_device *d = fe_to_d(fe); 5548c2ecf20Sopenharmony_ci struct af9015_state *state = d_to_priv(d); 5558c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 5568c2ecf20Sopenharmony_ci int ret; 5578c2ecf20Sopenharmony_ci unsigned int utmp1, utmp2, reg1, reg2; 5588c2ecf20Sopenharmony_ci u8 buf[2]; 5598c2ecf20Sopenharmony_ci const unsigned int adap_id = fe_to_adap(fe)->id; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "adap id %d, onoff %d\n", adap_id, onoff); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (!state->usb_ts_if_configured[adap_id]) { 5648c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "set usb and ts interface\n"); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci /* USB IF stream settings */ 5678c2ecf20Sopenharmony_ci utmp1 = (d->udev->speed == USB_SPEED_FULL ? 5 : 87) * 188 / 4; 5688c2ecf20Sopenharmony_ci utmp2 = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci buf[0] = (utmp1 >> 0) & 0xff; 5718c2ecf20Sopenharmony_ci buf[1] = (utmp1 >> 8) & 0xff; 5728c2ecf20Sopenharmony_ci if (adap_id == 0) { 5738c2ecf20Sopenharmony_ci /* 1st USB IF (EP4) stream settings */ 5748c2ecf20Sopenharmony_ci reg1 = 0xdd88; 5758c2ecf20Sopenharmony_ci reg2 = 0xdd0c; 5768c2ecf20Sopenharmony_ci } else { 5778c2ecf20Sopenharmony_ci /* 2nd USB IF (EP5) stream settings */ 5788c2ecf20Sopenharmony_ci reg1 = 0xdd8a; 5798c2ecf20Sopenharmony_ci reg2 = 0xdd0d; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci ret = regmap_bulk_write(state->regmap, reg1, buf, 2); 5828c2ecf20Sopenharmony_ci if (ret) 5838c2ecf20Sopenharmony_ci goto err; 5848c2ecf20Sopenharmony_ci ret = regmap_write(state->regmap, reg2, utmp2); 5858c2ecf20Sopenharmony_ci if (ret) 5868c2ecf20Sopenharmony_ci goto err; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* TS IF settings */ 5898c2ecf20Sopenharmony_ci if (state->dual_mode) { 5908c2ecf20Sopenharmony_ci utmp1 = 0x01; 5918c2ecf20Sopenharmony_ci utmp2 = 0x10; 5928c2ecf20Sopenharmony_ci } else { 5938c2ecf20Sopenharmony_ci utmp1 = 0x00; 5948c2ecf20Sopenharmony_ci utmp2 = 0x00; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd50b, 0x01, utmp1); 5978c2ecf20Sopenharmony_ci if (ret) 5988c2ecf20Sopenharmony_ci goto err; 5998c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd520, 0x10, utmp2); 6008c2ecf20Sopenharmony_ci if (ret) 6018c2ecf20Sopenharmony_ci goto err; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci state->usb_ts_if_configured[adap_id] = true; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci if (adap_id == 0 && onoff) { 6078c2ecf20Sopenharmony_ci /* Adapter 0 stream on. EP4: clear NAK, enable, clear reset */ 6088c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xdd13, 0x20, 0x00); 6098c2ecf20Sopenharmony_ci if (ret) 6108c2ecf20Sopenharmony_ci goto err; 6118c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xdd11, 0x20, 0x20); 6128c2ecf20Sopenharmony_ci if (ret) 6138c2ecf20Sopenharmony_ci goto err; 6148c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd507, 0x04, 0x00); 6158c2ecf20Sopenharmony_ci if (ret) 6168c2ecf20Sopenharmony_ci goto err; 6178c2ecf20Sopenharmony_ci } else if (adap_id == 1 && onoff) { 6188c2ecf20Sopenharmony_ci /* Adapter 1 stream on. EP5: clear NAK, enable, clear reset */ 6198c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xdd13, 0x40, 0x00); 6208c2ecf20Sopenharmony_ci if (ret) 6218c2ecf20Sopenharmony_ci goto err; 6228c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xdd11, 0x40, 0x40); 6238c2ecf20Sopenharmony_ci if (ret) 6248c2ecf20Sopenharmony_ci goto err; 6258c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd50b, 0x02, 0x00); 6268c2ecf20Sopenharmony_ci if (ret) 6278c2ecf20Sopenharmony_ci goto err; 6288c2ecf20Sopenharmony_ci } else if (adap_id == 0 && !onoff) { 6298c2ecf20Sopenharmony_ci /* Adapter 0 stream off. EP4: set reset, disable, set NAK */ 6308c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd507, 0x04, 0x04); 6318c2ecf20Sopenharmony_ci if (ret) 6328c2ecf20Sopenharmony_ci goto err; 6338c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xdd11, 0x20, 0x00); 6348c2ecf20Sopenharmony_ci if (ret) 6358c2ecf20Sopenharmony_ci goto err; 6368c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xdd13, 0x20, 0x20); 6378c2ecf20Sopenharmony_ci if (ret) 6388c2ecf20Sopenharmony_ci goto err; 6398c2ecf20Sopenharmony_ci } else if (adap_id == 1 && !onoff) { 6408c2ecf20Sopenharmony_ci /* Adapter 1 stream off. EP5: set reset, disable, set NAK */ 6418c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xd50b, 0x02, 0x02); 6428c2ecf20Sopenharmony_ci if (ret) 6438c2ecf20Sopenharmony_ci goto err; 6448c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xdd11, 0x40, 0x00); 6458c2ecf20Sopenharmony_ci if (ret) 6468c2ecf20Sopenharmony_ci goto err; 6478c2ecf20Sopenharmony_ci ret = regmap_update_bits(state->regmap, 0xdd13, 0x40, 0x40); 6488c2ecf20Sopenharmony_ci if (ret) 6498c2ecf20Sopenharmony_ci goto err; 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci return 0; 6538c2ecf20Sopenharmony_cierr: 6548c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "failed %d\n", ret); 6558c2ecf20Sopenharmony_ci return ret; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic int af9015_get_adapter_count(struct dvb_usb_device *d) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci struct af9015_state *state = d_to_priv(d); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci return state->dual_mode + 1; 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci/* override demod callbacks for resource locking */ 6668c2ecf20Sopenharmony_cistatic int af9015_af9013_set_frontend(struct dvb_frontend *fe) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci int ret; 6698c2ecf20Sopenharmony_ci struct af9015_state *state = fe_to_priv(fe); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->fe_mutex)) 6728c2ecf20Sopenharmony_ci return -EAGAIN; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci ret = state->set_frontend[fe_to_adap(fe)->id](fe); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci mutex_unlock(&state->fe_mutex); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci return ret; 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci/* override demod callbacks for resource locking */ 6828c2ecf20Sopenharmony_cistatic int af9015_af9013_read_status(struct dvb_frontend *fe, 6838c2ecf20Sopenharmony_ci enum fe_status *status) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci int ret; 6868c2ecf20Sopenharmony_ci struct af9015_state *state = fe_to_priv(fe); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->fe_mutex)) 6898c2ecf20Sopenharmony_ci return -EAGAIN; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci ret = state->read_status[fe_to_adap(fe)->id](fe, status); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci mutex_unlock(&state->fe_mutex); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci return ret; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci/* override demod callbacks for resource locking */ 6998c2ecf20Sopenharmony_cistatic int af9015_af9013_init(struct dvb_frontend *fe) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci int ret; 7028c2ecf20Sopenharmony_ci struct af9015_state *state = fe_to_priv(fe); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->fe_mutex)) 7058c2ecf20Sopenharmony_ci return -EAGAIN; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci ret = state->init[fe_to_adap(fe)->id](fe); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci mutex_unlock(&state->fe_mutex); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci return ret; 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci/* override demod callbacks for resource locking */ 7158c2ecf20Sopenharmony_cistatic int af9015_af9013_sleep(struct dvb_frontend *fe) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci int ret; 7188c2ecf20Sopenharmony_ci struct af9015_state *state = fe_to_priv(fe); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->fe_mutex)) 7218c2ecf20Sopenharmony_ci return -EAGAIN; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci ret = state->sleep[fe_to_adap(fe)->id](fe); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci mutex_unlock(&state->fe_mutex); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci return ret; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci/* override tuner callbacks for resource locking */ 7318c2ecf20Sopenharmony_cistatic int af9015_tuner_init(struct dvb_frontend *fe) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci int ret; 7348c2ecf20Sopenharmony_ci struct af9015_state *state = fe_to_priv(fe); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->fe_mutex)) 7378c2ecf20Sopenharmony_ci return -EAGAIN; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci ret = state->tuner_init[fe_to_adap(fe)->id](fe); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci mutex_unlock(&state->fe_mutex); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci return ret; 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci/* override tuner callbacks for resource locking */ 7478c2ecf20Sopenharmony_cistatic int af9015_tuner_sleep(struct dvb_frontend *fe) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci int ret; 7508c2ecf20Sopenharmony_ci struct af9015_state *state = fe_to_priv(fe); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->fe_mutex)) 7538c2ecf20Sopenharmony_ci return -EAGAIN; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci ret = state->tuner_sleep[fe_to_adap(fe)->id](fe); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci mutex_unlock(&state->fe_mutex); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci return ret; 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistatic int af9015_copy_firmware(struct dvb_usb_device *d) 7638c2ecf20Sopenharmony_ci{ 7648c2ecf20Sopenharmony_ci struct af9015_state *state = d_to_priv(d); 7658c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 7668c2ecf20Sopenharmony_ci int ret; 7678c2ecf20Sopenharmony_ci unsigned long timeout; 7688c2ecf20Sopenharmony_ci u8 val, firmware_info[4]; 7698c2ecf20Sopenharmony_ci struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, 4, firmware_info}; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "\n"); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci firmware_info[0] = (state->firmware_size >> 8) & 0xff; 7748c2ecf20Sopenharmony_ci firmware_info[1] = (state->firmware_size >> 0) & 0xff; 7758c2ecf20Sopenharmony_ci firmware_info[2] = (state->firmware_checksum >> 8) & 0xff; 7768c2ecf20Sopenharmony_ci firmware_info[3] = (state->firmware_checksum >> 0) & 0xff; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci /* Check whether firmware is already running */ 7798c2ecf20Sopenharmony_ci ret = af9015_read_reg_i2c(d, state->af9013_i2c_addr[1], 0x98be, &val); 7808c2ecf20Sopenharmony_ci if (ret) 7818c2ecf20Sopenharmony_ci goto err; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "firmware status %02x\n", val); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (val == 0x0c) 7868c2ecf20Sopenharmony_ci return 0; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci /* Set i2c clock to 625kHz to speed up firmware copy */ 7898c2ecf20Sopenharmony_ci ret = regmap_write(state->regmap, 0xd416, 0x04); 7908c2ecf20Sopenharmony_ci if (ret) 7918c2ecf20Sopenharmony_ci goto err; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci /* Copy firmware from master demod to slave demod */ 7948c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 7958c2ecf20Sopenharmony_ci if (ret) { 7968c2ecf20Sopenharmony_ci dev_err(&intf->dev, "firmware copy cmd failed %d\n", ret); 7978c2ecf20Sopenharmony_ci goto err; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci /* Set i2c clock to 125kHz */ 8018c2ecf20Sopenharmony_ci ret = regmap_write(state->regmap, 0xd416, 0x14); 8028c2ecf20Sopenharmony_ci if (ret) 8038c2ecf20Sopenharmony_ci goto err; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci /* Boot firmware */ 8068c2ecf20Sopenharmony_ci ret = af9015_write_reg_i2c(d, state->af9013_i2c_addr[1], 0xe205, 0x01); 8078c2ecf20Sopenharmony_ci if (ret) 8088c2ecf20Sopenharmony_ci goto err; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci /* Poll firmware ready */ 8118c2ecf20Sopenharmony_ci for (val = 0x00, timeout = jiffies + msecs_to_jiffies(1000); 8128c2ecf20Sopenharmony_ci !time_after(jiffies, timeout) && val != 0x0c && val != 0x04;) { 8138c2ecf20Sopenharmony_ci msleep(20); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci /* Check firmware status. 0c=OK, 04=fail */ 8168c2ecf20Sopenharmony_ci ret = af9015_read_reg_i2c(d, state->af9013_i2c_addr[1], 8178c2ecf20Sopenharmony_ci 0x98be, &val); 8188c2ecf20Sopenharmony_ci if (ret) 8198c2ecf20Sopenharmony_ci goto err; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "firmware status %02x\n", val); 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "firmware boot took %u ms\n", 8258c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies) - (jiffies_to_msecs(timeout) - 1000)); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci if (val == 0x04) { 8288c2ecf20Sopenharmony_ci ret = -ENODEV; 8298c2ecf20Sopenharmony_ci dev_err(&intf->dev, "firmware did not run\n"); 8308c2ecf20Sopenharmony_ci goto err; 8318c2ecf20Sopenharmony_ci } else if (val != 0x0c) { 8328c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 8338c2ecf20Sopenharmony_ci dev_err(&intf->dev, "firmware boot timeout\n"); 8348c2ecf20Sopenharmony_ci goto err; 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci return 0; 8388c2ecf20Sopenharmony_cierr: 8398c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "failed %d\n", ret); 8408c2ecf20Sopenharmony_ci return ret; 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci struct af9015_state *state = adap_to_priv(adap); 8468c2ecf20Sopenharmony_ci struct dvb_usb_device *d = adap_to_d(adap); 8478c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 8488c2ecf20Sopenharmony_ci struct i2c_client *client; 8498c2ecf20Sopenharmony_ci int ret; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "adap id %u\n", adap->id); 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci if (adap->id == 0) { 8548c2ecf20Sopenharmony_ci state->af9013_pdata[0].ts_mode = AF9013_TS_MODE_USB; 8558c2ecf20Sopenharmony_ci memcpy(state->af9013_pdata[0].api_version, "\x0\x1\x9\x0", 4); 8568c2ecf20Sopenharmony_ci state->af9013_pdata[0].gpio[0] = AF9013_GPIO_HI; 8578c2ecf20Sopenharmony_ci state->af9013_pdata[0].gpio[3] = AF9013_GPIO_TUNER_ON; 8588c2ecf20Sopenharmony_ci } else if (adap->id == 1) { 8598c2ecf20Sopenharmony_ci state->af9013_pdata[1].ts_mode = AF9013_TS_MODE_SERIAL; 8608c2ecf20Sopenharmony_ci state->af9013_pdata[1].ts_output_pin = 7; 8618c2ecf20Sopenharmony_ci memcpy(state->af9013_pdata[1].api_version, "\x0\x1\x9\x0", 4); 8628c2ecf20Sopenharmony_ci state->af9013_pdata[1].gpio[0] = AF9013_GPIO_TUNER_ON; 8638c2ecf20Sopenharmony_ci state->af9013_pdata[1].gpio[1] = AF9013_GPIO_LO; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci /* copy firmware to 2nd demodulator */ 8668c2ecf20Sopenharmony_ci if (state->dual_mode) { 8678c2ecf20Sopenharmony_ci /* Wait 2nd demodulator ready */ 8688c2ecf20Sopenharmony_ci msleep(100); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci ret = af9015_copy_firmware(adap_to_d(adap)); 8718c2ecf20Sopenharmony_ci if (ret) { 8728c2ecf20Sopenharmony_ci dev_err(&intf->dev, 8738c2ecf20Sopenharmony_ci "firmware copy to 2nd frontend failed, will disable it\n"); 8748c2ecf20Sopenharmony_ci state->dual_mode = 0; 8758c2ecf20Sopenharmony_ci goto err; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci } else { 8788c2ecf20Sopenharmony_ci ret = -ENODEV; 8798c2ecf20Sopenharmony_ci goto err; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci /* Add I2C demod */ 8848c2ecf20Sopenharmony_ci client = dvb_module_probe("af9013", NULL, &d->i2c_adap, 8858c2ecf20Sopenharmony_ci state->af9013_i2c_addr[adap->id], 8868c2ecf20Sopenharmony_ci &state->af9013_pdata[adap->id]); 8878c2ecf20Sopenharmony_ci if (!client) { 8888c2ecf20Sopenharmony_ci ret = -ENODEV; 8898c2ecf20Sopenharmony_ci goto err; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci adap->fe[0] = state->af9013_pdata[adap->id].get_dvb_frontend(client); 8928c2ecf20Sopenharmony_ci state->demod_i2c_client[adap->id] = client; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* 8958c2ecf20Sopenharmony_ci * AF9015 firmware does not like if it gets interrupted by I2C adapter 8968c2ecf20Sopenharmony_ci * request on some critical phases. During normal operation I2C adapter 8978c2ecf20Sopenharmony_ci * is used only 2nd demodulator and tuner on dual tuner devices. 8988c2ecf20Sopenharmony_ci * Override demodulator callbacks and use mutex for limit access to 8998c2ecf20Sopenharmony_ci * those "critical" paths to keep AF9015 happy. 9008c2ecf20Sopenharmony_ci */ 9018c2ecf20Sopenharmony_ci if (adap->fe[0]) { 9028c2ecf20Sopenharmony_ci state->set_frontend[adap->id] = adap->fe[0]->ops.set_frontend; 9038c2ecf20Sopenharmony_ci adap->fe[0]->ops.set_frontend = af9015_af9013_set_frontend; 9048c2ecf20Sopenharmony_ci state->read_status[adap->id] = adap->fe[0]->ops.read_status; 9058c2ecf20Sopenharmony_ci adap->fe[0]->ops.read_status = af9015_af9013_read_status; 9068c2ecf20Sopenharmony_ci state->init[adap->id] = adap->fe[0]->ops.init; 9078c2ecf20Sopenharmony_ci adap->fe[0]->ops.init = af9015_af9013_init; 9088c2ecf20Sopenharmony_ci state->sleep[adap->id] = adap->fe[0]->ops.sleep; 9098c2ecf20Sopenharmony_ci adap->fe[0]->ops.sleep = af9015_af9013_sleep; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci return 0; 9138c2ecf20Sopenharmony_cierr: 9148c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "failed %d\n", ret); 9158c2ecf20Sopenharmony_ci return ret; 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_cistatic int af9015_frontend_detach(struct dvb_usb_adapter *adap) 9198c2ecf20Sopenharmony_ci{ 9208c2ecf20Sopenharmony_ci struct af9015_state *state = adap_to_priv(adap); 9218c2ecf20Sopenharmony_ci struct dvb_usb_device *d = adap_to_d(adap); 9228c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 9238c2ecf20Sopenharmony_ci struct i2c_client *client; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "adap id %u\n", adap->id); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci /* Remove I2C demod */ 9288c2ecf20Sopenharmony_ci client = state->demod_i2c_client[adap->id]; 9298c2ecf20Sopenharmony_ci dvb_module_release(client); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci return 0; 9328c2ecf20Sopenharmony_ci} 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_cistatic struct mt2060_config af9015_mt2060_config = { 9358c2ecf20Sopenharmony_ci .i2c_address = 0x60, 9368c2ecf20Sopenharmony_ci .clock_out = 0, 9378c2ecf20Sopenharmony_ci}; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_cistatic struct qt1010_config af9015_qt1010_config = { 9408c2ecf20Sopenharmony_ci .i2c_address = 0x62, 9418c2ecf20Sopenharmony_ci}; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_cistatic struct tda18271_config af9015_tda18271_config = { 9448c2ecf20Sopenharmony_ci .gate = TDA18271_GATE_DIGITAL, 9458c2ecf20Sopenharmony_ci .small_i2c = TDA18271_16_BYTE_CHUNK_INIT, 9468c2ecf20Sopenharmony_ci}; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic struct mxl5005s_config af9015_mxl5003_config = { 9498c2ecf20Sopenharmony_ci .i2c_address = 0x63, 9508c2ecf20Sopenharmony_ci .if_freq = IF_FREQ_4570000HZ, 9518c2ecf20Sopenharmony_ci .xtal_freq = CRYSTAL_FREQ_16000000HZ, 9528c2ecf20Sopenharmony_ci .agc_mode = MXL_SINGLE_AGC, 9538c2ecf20Sopenharmony_ci .tracking_filter = MXL_TF_DEFAULT, 9548c2ecf20Sopenharmony_ci .rssi_enable = MXL_RSSI_ENABLE, 9558c2ecf20Sopenharmony_ci .cap_select = MXL_CAP_SEL_ENABLE, 9568c2ecf20Sopenharmony_ci .div_out = MXL_DIV_OUT_4, 9578c2ecf20Sopenharmony_ci .clock_out = MXL_CLOCK_OUT_DISABLE, 9588c2ecf20Sopenharmony_ci .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, 9598c2ecf20Sopenharmony_ci .top = MXL5005S_TOP_25P2, 9608c2ecf20Sopenharmony_ci .mod_mode = MXL_DIGITAL_MODE, 9618c2ecf20Sopenharmony_ci .if_mode = MXL_ZERO_IF, 9628c2ecf20Sopenharmony_ci .AgcMasterByte = 0x00, 9638c2ecf20Sopenharmony_ci}; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_cistatic struct mxl5005s_config af9015_mxl5005_config = { 9668c2ecf20Sopenharmony_ci .i2c_address = 0x63, 9678c2ecf20Sopenharmony_ci .if_freq = IF_FREQ_4570000HZ, 9688c2ecf20Sopenharmony_ci .xtal_freq = CRYSTAL_FREQ_16000000HZ, 9698c2ecf20Sopenharmony_ci .agc_mode = MXL_SINGLE_AGC, 9708c2ecf20Sopenharmony_ci .tracking_filter = MXL_TF_OFF, 9718c2ecf20Sopenharmony_ci .rssi_enable = MXL_RSSI_ENABLE, 9728c2ecf20Sopenharmony_ci .cap_select = MXL_CAP_SEL_ENABLE, 9738c2ecf20Sopenharmony_ci .div_out = MXL_DIV_OUT_4, 9748c2ecf20Sopenharmony_ci .clock_out = MXL_CLOCK_OUT_DISABLE, 9758c2ecf20Sopenharmony_ci .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, 9768c2ecf20Sopenharmony_ci .top = MXL5005S_TOP_25P2, 9778c2ecf20Sopenharmony_ci .mod_mode = MXL_DIGITAL_MODE, 9788c2ecf20Sopenharmony_ci .if_mode = MXL_ZERO_IF, 9798c2ecf20Sopenharmony_ci .AgcMasterByte = 0x00, 9808c2ecf20Sopenharmony_ci}; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_cistatic struct mc44s803_config af9015_mc44s803_config = { 9838c2ecf20Sopenharmony_ci .i2c_address = 0x60, 9848c2ecf20Sopenharmony_ci .dig_out = 1, 9858c2ecf20Sopenharmony_ci}; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_cistatic struct tda18218_config af9015_tda18218_config = { 9888c2ecf20Sopenharmony_ci .i2c_address = 0x60, 9898c2ecf20Sopenharmony_ci .i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */ 9908c2ecf20Sopenharmony_ci}; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_cistatic struct mxl5007t_config af9015_mxl5007t_config = { 9938c2ecf20Sopenharmony_ci .xtal_freq_hz = MxL_XTAL_24_MHZ, 9948c2ecf20Sopenharmony_ci .if_freq_hz = MxL_IF_4_57_MHZ, 9958c2ecf20Sopenharmony_ci}; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_cistatic int af9015_tuner_attach(struct dvb_usb_adapter *adap) 9988c2ecf20Sopenharmony_ci{ 9998c2ecf20Sopenharmony_ci struct dvb_usb_device *d = adap_to_d(adap); 10008c2ecf20Sopenharmony_ci struct af9015_state *state = d_to_priv(d); 10018c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 10028c2ecf20Sopenharmony_ci struct i2c_client *client; 10038c2ecf20Sopenharmony_ci struct i2c_adapter *adapter; 10048c2ecf20Sopenharmony_ci int ret; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "adap id %u\n", adap->id); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci client = state->demod_i2c_client[adap->id]; 10098c2ecf20Sopenharmony_ci adapter = state->af9013_pdata[adap->id].get_i2c_adapter(client); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci switch (state->af9013_pdata[adap->id].tuner) { 10128c2ecf20Sopenharmony_ci case AF9013_TUNER_MT2060: 10138c2ecf20Sopenharmony_ci case AF9013_TUNER_MT2060_2: 10148c2ecf20Sopenharmony_ci ret = dvb_attach(mt2060_attach, adap->fe[0], adapter, 10158c2ecf20Sopenharmony_ci &af9015_mt2060_config, 10168c2ecf20Sopenharmony_ci state->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; 10178c2ecf20Sopenharmony_ci break; 10188c2ecf20Sopenharmony_ci case AF9013_TUNER_QT1010: 10198c2ecf20Sopenharmony_ci case AF9013_TUNER_QT1010A: 10208c2ecf20Sopenharmony_ci ret = dvb_attach(qt1010_attach, adap->fe[0], adapter, 10218c2ecf20Sopenharmony_ci &af9015_qt1010_config) == NULL ? -ENODEV : 0; 10228c2ecf20Sopenharmony_ci break; 10238c2ecf20Sopenharmony_ci case AF9013_TUNER_TDA18271: 10248c2ecf20Sopenharmony_ci ret = dvb_attach(tda18271_attach, adap->fe[0], 0x60, adapter, 10258c2ecf20Sopenharmony_ci &af9015_tda18271_config) == NULL ? -ENODEV : 0; 10268c2ecf20Sopenharmony_ci break; 10278c2ecf20Sopenharmony_ci case AF9013_TUNER_TDA18218: 10288c2ecf20Sopenharmony_ci ret = dvb_attach(tda18218_attach, adap->fe[0], adapter, 10298c2ecf20Sopenharmony_ci &af9015_tda18218_config) == NULL ? -ENODEV : 0; 10308c2ecf20Sopenharmony_ci break; 10318c2ecf20Sopenharmony_ci case AF9013_TUNER_MXL5003D: 10328c2ecf20Sopenharmony_ci ret = dvb_attach(mxl5005s_attach, adap->fe[0], adapter, 10338c2ecf20Sopenharmony_ci &af9015_mxl5003_config) == NULL ? -ENODEV : 0; 10348c2ecf20Sopenharmony_ci break; 10358c2ecf20Sopenharmony_ci case AF9013_TUNER_MXL5005D: 10368c2ecf20Sopenharmony_ci case AF9013_TUNER_MXL5005R: 10378c2ecf20Sopenharmony_ci ret = dvb_attach(mxl5005s_attach, adap->fe[0], adapter, 10388c2ecf20Sopenharmony_ci &af9015_mxl5005_config) == NULL ? -ENODEV : 0; 10398c2ecf20Sopenharmony_ci break; 10408c2ecf20Sopenharmony_ci case AF9013_TUNER_ENV77H11D5: 10418c2ecf20Sopenharmony_ci ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, adapter, 10428c2ecf20Sopenharmony_ci DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; 10438c2ecf20Sopenharmony_ci break; 10448c2ecf20Sopenharmony_ci case AF9013_TUNER_MC44S803: 10458c2ecf20Sopenharmony_ci ret = dvb_attach(mc44s803_attach, adap->fe[0], adapter, 10468c2ecf20Sopenharmony_ci &af9015_mc44s803_config) == NULL ? -ENODEV : 0; 10478c2ecf20Sopenharmony_ci break; 10488c2ecf20Sopenharmony_ci case AF9013_TUNER_MXL5007T: 10498c2ecf20Sopenharmony_ci ret = dvb_attach(mxl5007t_attach, adap->fe[0], adapter, 10508c2ecf20Sopenharmony_ci 0x60, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; 10518c2ecf20Sopenharmony_ci break; 10528c2ecf20Sopenharmony_ci case AF9013_TUNER_UNKNOWN: 10538c2ecf20Sopenharmony_ci default: 10548c2ecf20Sopenharmony_ci dev_err(&intf->dev, "unknown tuner, tuner id %02x\n", 10558c2ecf20Sopenharmony_ci state->af9013_pdata[adap->id].tuner); 10568c2ecf20Sopenharmony_ci ret = -ENODEV; 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci if (adap->fe[0]->ops.tuner_ops.init) { 10608c2ecf20Sopenharmony_ci state->tuner_init[adap->id] = 10618c2ecf20Sopenharmony_ci adap->fe[0]->ops.tuner_ops.init; 10628c2ecf20Sopenharmony_ci adap->fe[0]->ops.tuner_ops.init = af9015_tuner_init; 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci if (adap->fe[0]->ops.tuner_ops.sleep) { 10668c2ecf20Sopenharmony_ci state->tuner_sleep[adap->id] = 10678c2ecf20Sopenharmony_ci adap->fe[0]->ops.tuner_ops.sleep; 10688c2ecf20Sopenharmony_ci adap->fe[0]->ops.tuner_ops.sleep = af9015_tuner_sleep; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci return ret; 10728c2ecf20Sopenharmony_ci} 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_cistatic int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) 10758c2ecf20Sopenharmony_ci{ 10768c2ecf20Sopenharmony_ci struct af9015_state *state = adap_to_priv(adap); 10778c2ecf20Sopenharmony_ci struct af9013_platform_data *pdata = &state->af9013_pdata[adap->id]; 10788c2ecf20Sopenharmony_ci int ret; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci mutex_lock(&state->fe_mutex); 10818c2ecf20Sopenharmony_ci ret = pdata->pid_filter_ctrl(adap->fe[0], onoff); 10828c2ecf20Sopenharmony_ci mutex_unlock(&state->fe_mutex); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci return ret; 10858c2ecf20Sopenharmony_ci} 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_cistatic int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, 10888c2ecf20Sopenharmony_ci u16 pid, int onoff) 10898c2ecf20Sopenharmony_ci{ 10908c2ecf20Sopenharmony_ci struct af9015_state *state = adap_to_priv(adap); 10918c2ecf20Sopenharmony_ci struct af9013_platform_data *pdata = &state->af9013_pdata[adap->id]; 10928c2ecf20Sopenharmony_ci int ret; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci mutex_lock(&state->fe_mutex); 10958c2ecf20Sopenharmony_ci ret = pdata->pid_filter(adap->fe[0], index, pid, onoff); 10968c2ecf20Sopenharmony_ci mutex_unlock(&state->fe_mutex); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci return ret; 10998c2ecf20Sopenharmony_ci} 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_cistatic int af9015_init(struct dvb_usb_device *d) 11028c2ecf20Sopenharmony_ci{ 11038c2ecf20Sopenharmony_ci struct af9015_state *state = d_to_priv(d); 11048c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 11058c2ecf20Sopenharmony_ci int ret; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "\n"); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci mutex_init(&state->fe_mutex); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci /* init RC canary */ 11128c2ecf20Sopenharmony_ci ret = regmap_write(state->regmap, 0x98e9, 0xff); 11138c2ecf20Sopenharmony_ci if (ret) 11148c2ecf20Sopenharmony_ci goto error; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_cierror: 11178c2ecf20Sopenharmony_ci return ret; 11188c2ecf20Sopenharmony_ci} 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_RC_CORE) 11218c2ecf20Sopenharmony_cistruct af9015_rc_setup { 11228c2ecf20Sopenharmony_ci unsigned int id; 11238c2ecf20Sopenharmony_ci char *rc_codes; 11248c2ecf20Sopenharmony_ci}; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cistatic char *af9015_rc_setup_match(unsigned int id, 11278c2ecf20Sopenharmony_ci const struct af9015_rc_setup *table) 11288c2ecf20Sopenharmony_ci{ 11298c2ecf20Sopenharmony_ci for (; table->rc_codes; table++) 11308c2ecf20Sopenharmony_ci if (table->id == id) 11318c2ecf20Sopenharmony_ci return table->rc_codes; 11328c2ecf20Sopenharmony_ci return NULL; 11338c2ecf20Sopenharmony_ci} 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_cistatic const struct af9015_rc_setup af9015_rc_setup_modparam[] = { 11368c2ecf20Sopenharmony_ci { AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M }, 11378c2ecf20Sopenharmony_ci { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II }, 11388c2ecf20Sopenharmony_ci { AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND }, 11398c2ecf20Sopenharmony_ci { AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE }, 11408c2ecf20Sopenharmony_ci { AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS }, 11418c2ecf20Sopenharmony_ci { } 11428c2ecf20Sopenharmony_ci}; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_cistatic const struct af9015_rc_setup af9015_rc_setup_hashes[] = { 11458c2ecf20Sopenharmony_ci { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II }, 11468c2ecf20Sopenharmony_ci { 0xa3703d00, RC_MAP_ALINK_DTU_M }, 11478c2ecf20Sopenharmony_ci { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */ 11488c2ecf20Sopenharmony_ci { 0x5d49e3db, RC_MAP_DIGITTRADE }, /* LC-Power LC-USB-DVBT */ 11498c2ecf20Sopenharmony_ci { } 11508c2ecf20Sopenharmony_ci}; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_cistatic int af9015_rc_query(struct dvb_usb_device *d) 11538c2ecf20Sopenharmony_ci{ 11548c2ecf20Sopenharmony_ci struct af9015_state *state = d_to_priv(d); 11558c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 11568c2ecf20Sopenharmony_ci int ret; 11578c2ecf20Sopenharmony_ci u8 buf[17]; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci /* read registers needed to detect remote controller code */ 11608c2ecf20Sopenharmony_ci ret = regmap_bulk_read(state->regmap, 0x98d9, buf, sizeof(buf)); 11618c2ecf20Sopenharmony_ci if (ret) 11628c2ecf20Sopenharmony_ci goto error; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci /* If any of these are non-zero, assume invalid data */ 11658c2ecf20Sopenharmony_ci if (buf[1] || buf[2] || buf[3]) { 11668c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "invalid data\n"); 11678c2ecf20Sopenharmony_ci return ret; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci /* Check for repeat of previous code */ 11718c2ecf20Sopenharmony_ci if ((state->rc_repeat != buf[6] || buf[0]) && 11728c2ecf20Sopenharmony_ci !memcmp(&buf[12], state->rc_last, 4)) { 11738c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "key repeated\n"); 11748c2ecf20Sopenharmony_ci rc_repeat(d->rc_dev); 11758c2ecf20Sopenharmony_ci state->rc_repeat = buf[6]; 11768c2ecf20Sopenharmony_ci return ret; 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci /* Only process key if canary killed */ 11808c2ecf20Sopenharmony_ci if (buf[16] != 0xff && buf[0] != 0x01) { 11818c2ecf20Sopenharmony_ci enum rc_proto proto; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "key pressed %*ph\n", 4, buf + 12); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci /* Reset the canary */ 11868c2ecf20Sopenharmony_ci ret = regmap_write(state->regmap, 0x98e9, 0xff); 11878c2ecf20Sopenharmony_ci if (ret) 11888c2ecf20Sopenharmony_ci goto error; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci /* Remember this key */ 11918c2ecf20Sopenharmony_ci memcpy(state->rc_last, &buf[12], 4); 11928c2ecf20Sopenharmony_ci if (buf[14] == (u8)~buf[15]) { 11938c2ecf20Sopenharmony_ci if (buf[12] == (u8)~buf[13]) { 11948c2ecf20Sopenharmony_ci /* NEC */ 11958c2ecf20Sopenharmony_ci state->rc_keycode = RC_SCANCODE_NEC(buf[12], 11968c2ecf20Sopenharmony_ci buf[14]); 11978c2ecf20Sopenharmony_ci proto = RC_PROTO_NEC; 11988c2ecf20Sopenharmony_ci } else { 11998c2ecf20Sopenharmony_ci /* NEC extended*/ 12008c2ecf20Sopenharmony_ci state->rc_keycode = RC_SCANCODE_NECX(buf[12] << 8 | 12018c2ecf20Sopenharmony_ci buf[13], 12028c2ecf20Sopenharmony_ci buf[14]); 12038c2ecf20Sopenharmony_ci proto = RC_PROTO_NECX; 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci } else { 12068c2ecf20Sopenharmony_ci /* 32 bit NEC */ 12078c2ecf20Sopenharmony_ci state->rc_keycode = RC_SCANCODE_NEC32(buf[12] << 24 | 12088c2ecf20Sopenharmony_ci buf[13] << 16 | 12098c2ecf20Sopenharmony_ci buf[14] << 8 | 12108c2ecf20Sopenharmony_ci buf[15]); 12118c2ecf20Sopenharmony_ci proto = RC_PROTO_NEC32; 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci rc_keydown(d->rc_dev, proto, state->rc_keycode, 0); 12148c2ecf20Sopenharmony_ci } else { 12158c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "no key press\n"); 12168c2ecf20Sopenharmony_ci /* Invalidate last keypress */ 12178c2ecf20Sopenharmony_ci /* Not really needed, but helps with debug */ 12188c2ecf20Sopenharmony_ci state->rc_last[2] = state->rc_last[3]; 12198c2ecf20Sopenharmony_ci } 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci state->rc_repeat = buf[6]; 12228c2ecf20Sopenharmony_ci state->rc_failed = false; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_cierror: 12258c2ecf20Sopenharmony_ci if (ret) { 12268c2ecf20Sopenharmony_ci dev_warn(&intf->dev, "rc query failed %d\n", ret); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci /* allow random errors as dvb-usb will stop polling on error */ 12298c2ecf20Sopenharmony_ci if (!state->rc_failed) 12308c2ecf20Sopenharmony_ci ret = 0; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci state->rc_failed = true; 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci return ret; 12368c2ecf20Sopenharmony_ci} 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_cistatic int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) 12398c2ecf20Sopenharmony_ci{ 12408c2ecf20Sopenharmony_ci struct af9015_state *state = d_to_priv(d); 12418c2ecf20Sopenharmony_ci u16 vid = le16_to_cpu(d->udev->descriptor.idVendor); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci if (state->ir_mode == AF9015_IR_MODE_DISABLED) 12448c2ecf20Sopenharmony_ci return 0; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci /* try to load remote based module param */ 12478c2ecf20Sopenharmony_ci if (!rc->map_name) 12488c2ecf20Sopenharmony_ci rc->map_name = af9015_rc_setup_match(dvb_usb_af9015_remote, 12498c2ecf20Sopenharmony_ci af9015_rc_setup_modparam); 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci /* try to load remote based eeprom hash */ 12528c2ecf20Sopenharmony_ci if (!rc->map_name) 12538c2ecf20Sopenharmony_ci rc->map_name = af9015_rc_setup_match(state->eeprom_sum, 12548c2ecf20Sopenharmony_ci af9015_rc_setup_hashes); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci /* try to load remote based USB iManufacturer string */ 12578c2ecf20Sopenharmony_ci if (!rc->map_name && vid == USB_VID_AFATECH) { 12588c2ecf20Sopenharmony_ci /* 12598c2ecf20Sopenharmony_ci * Check USB manufacturer and product strings and try 12608c2ecf20Sopenharmony_ci * to determine correct remote in case of chip vendor 12618c2ecf20Sopenharmony_ci * reference IDs are used. 12628c2ecf20Sopenharmony_ci * DO NOT ADD ANYTHING NEW HERE. Use hashes instead. 12638c2ecf20Sopenharmony_ci */ 12648c2ecf20Sopenharmony_ci char manufacturer[10]; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci memset(manufacturer, 0, sizeof(manufacturer)); 12678c2ecf20Sopenharmony_ci usb_string(d->udev, d->udev->descriptor.iManufacturer, 12688c2ecf20Sopenharmony_ci manufacturer, sizeof(manufacturer)); 12698c2ecf20Sopenharmony_ci if (!strcmp("MSI", manufacturer)) { 12708c2ecf20Sopenharmony_ci /* 12718c2ecf20Sopenharmony_ci * iManufacturer 1 MSI 12728c2ecf20Sopenharmony_ci * iProduct 2 MSI K-VOX 12738c2ecf20Sopenharmony_ci */ 12748c2ecf20Sopenharmony_ci rc->map_name = af9015_rc_setup_match(AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, 12758c2ecf20Sopenharmony_ci af9015_rc_setup_modparam); 12768c2ecf20Sopenharmony_ci } 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci /* load empty to enable rc */ 12808c2ecf20Sopenharmony_ci if (!rc->map_name) 12818c2ecf20Sopenharmony_ci rc->map_name = RC_MAP_EMPTY; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci rc->allowed_protos = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | 12848c2ecf20Sopenharmony_ci RC_PROTO_BIT_NEC32; 12858c2ecf20Sopenharmony_ci rc->query = af9015_rc_query; 12868c2ecf20Sopenharmony_ci rc->interval = 500; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci return 0; 12898c2ecf20Sopenharmony_ci} 12908c2ecf20Sopenharmony_ci#else 12918c2ecf20Sopenharmony_ci #define af9015_get_rc_config NULL 12928c2ecf20Sopenharmony_ci#endif 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_cistatic int af9015_regmap_write(void *context, const void *data, size_t count) 12958c2ecf20Sopenharmony_ci{ 12968c2ecf20Sopenharmony_ci struct dvb_usb_device *d = context; 12978c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 12988c2ecf20Sopenharmony_ci int ret; 12998c2ecf20Sopenharmony_ci u16 reg = ((u8 *)data)[0] << 8 | ((u8 *)data)[1] << 0; 13008c2ecf20Sopenharmony_ci u8 *val = &((u8 *)data)[2]; 13018c2ecf20Sopenharmony_ci const unsigned int len = count - 2; 13028c2ecf20Sopenharmony_ci struct req_t req = {WRITE_MEMORY, 0, reg, 0, 0, len, val}; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 13058c2ecf20Sopenharmony_ci if (ret) 13068c2ecf20Sopenharmony_ci goto err; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci return 0; 13098c2ecf20Sopenharmony_cierr: 13108c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "failed %d\n", ret); 13118c2ecf20Sopenharmony_ci return ret; 13128c2ecf20Sopenharmony_ci} 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_cistatic int af9015_regmap_read(void *context, const void *reg_buf, 13158c2ecf20Sopenharmony_ci size_t reg_size, void *val_buf, size_t val_size) 13168c2ecf20Sopenharmony_ci{ 13178c2ecf20Sopenharmony_ci struct dvb_usb_device *d = context; 13188c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 13198c2ecf20Sopenharmony_ci int ret; 13208c2ecf20Sopenharmony_ci u16 reg = ((u8 *)reg_buf)[0] << 8 | ((u8 *)reg_buf)[1] << 0; 13218c2ecf20Sopenharmony_ci u8 *val = &((u8 *)val_buf)[0]; 13228c2ecf20Sopenharmony_ci const unsigned int len = val_size; 13238c2ecf20Sopenharmony_ci struct req_t req = {READ_MEMORY, 0, reg, 0, 0, len, val}; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci ret = af9015_ctrl_msg(d, &req); 13268c2ecf20Sopenharmony_ci if (ret) 13278c2ecf20Sopenharmony_ci goto err; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci return 0; 13308c2ecf20Sopenharmony_cierr: 13318c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "failed %d\n", ret); 13328c2ecf20Sopenharmony_ci return ret; 13338c2ecf20Sopenharmony_ci} 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_cistatic int af9015_probe(struct dvb_usb_device *d) 13368c2ecf20Sopenharmony_ci{ 13378c2ecf20Sopenharmony_ci struct af9015_state *state = d_to_priv(d); 13388c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 13398c2ecf20Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(intf); 13408c2ecf20Sopenharmony_ci int ret; 13418c2ecf20Sopenharmony_ci char manufacturer[sizeof("ITE Technologies, Inc.")]; 13428c2ecf20Sopenharmony_ci static const struct regmap_config regmap_config = { 13438c2ecf20Sopenharmony_ci .reg_bits = 16, 13448c2ecf20Sopenharmony_ci .val_bits = 8, 13458c2ecf20Sopenharmony_ci }; 13468c2ecf20Sopenharmony_ci static const struct regmap_bus regmap_bus = { 13478c2ecf20Sopenharmony_ci .read = af9015_regmap_read, 13488c2ecf20Sopenharmony_ci .write = af9015_regmap_write, 13498c2ecf20Sopenharmony_ci }; 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "\n"); 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci memset(manufacturer, 0, sizeof(manufacturer)); 13548c2ecf20Sopenharmony_ci usb_string(udev, udev->descriptor.iManufacturer, 13558c2ecf20Sopenharmony_ci manufacturer, sizeof(manufacturer)); 13568c2ecf20Sopenharmony_ci /* 13578c2ecf20Sopenharmony_ci * There is two devices having same ID but different chipset. One uses 13588c2ecf20Sopenharmony_ci * AF9015 and the other IT9135 chipset. Only difference seen on lsusb 13598c2ecf20Sopenharmony_ci * is iManufacturer string. 13608c2ecf20Sopenharmony_ci * 13618c2ecf20Sopenharmony_ci * idVendor 0x0ccd TerraTec Electronic GmbH 13628c2ecf20Sopenharmony_ci * idProduct 0x0099 13638c2ecf20Sopenharmony_ci * bcdDevice 2.00 13648c2ecf20Sopenharmony_ci * iManufacturer 1 Afatech 13658c2ecf20Sopenharmony_ci * iProduct 2 DVB-T 2 13668c2ecf20Sopenharmony_ci * 13678c2ecf20Sopenharmony_ci * idVendor 0x0ccd TerraTec Electronic GmbH 13688c2ecf20Sopenharmony_ci * idProduct 0x0099 13698c2ecf20Sopenharmony_ci * bcdDevice 2.00 13708c2ecf20Sopenharmony_ci * iManufacturer 1 ITE Technologies, Inc. 13718c2ecf20Sopenharmony_ci * iProduct 2 DVB-T TV Stick 13728c2ecf20Sopenharmony_ci */ 13738c2ecf20Sopenharmony_ci if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VID_TERRATEC) && 13748c2ecf20Sopenharmony_ci (le16_to_cpu(udev->descriptor.idProduct) == 0x0099)) { 13758c2ecf20Sopenharmony_ci if (!strcmp("ITE Technologies, Inc.", manufacturer)) { 13768c2ecf20Sopenharmony_ci ret = -ENODEV; 13778c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "rejecting device\n"); 13788c2ecf20Sopenharmony_ci goto err; 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci } 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci state->regmap = regmap_init(&intf->dev, ®map_bus, d, ®map_config); 13838c2ecf20Sopenharmony_ci if (IS_ERR(state->regmap)) { 13848c2ecf20Sopenharmony_ci ret = PTR_ERR(state->regmap); 13858c2ecf20Sopenharmony_ci goto err; 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci return 0; 13898c2ecf20Sopenharmony_cierr: 13908c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "failed %d\n", ret); 13918c2ecf20Sopenharmony_ci return ret; 13928c2ecf20Sopenharmony_ci} 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_cistatic void af9015_disconnect(struct dvb_usb_device *d) 13958c2ecf20Sopenharmony_ci{ 13968c2ecf20Sopenharmony_ci struct af9015_state *state = d_to_priv(d); 13978c2ecf20Sopenharmony_ci struct usb_interface *intf = d->intf; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci dev_dbg(&intf->dev, "\n"); 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci regmap_exit(state->regmap); 14028c2ecf20Sopenharmony_ci} 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci/* 14058c2ecf20Sopenharmony_ci * Interface 0 is used by DVB-T receiver and 14068c2ecf20Sopenharmony_ci * interface 1 is for remote controller (HID) 14078c2ecf20Sopenharmony_ci */ 14088c2ecf20Sopenharmony_cistatic const struct dvb_usb_device_properties af9015_props = { 14098c2ecf20Sopenharmony_ci .driver_name = KBUILD_MODNAME, 14108c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 14118c2ecf20Sopenharmony_ci .adapter_nr = adapter_nr, 14128c2ecf20Sopenharmony_ci .size_of_priv = sizeof(struct af9015_state), 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci .generic_bulk_ctrl_endpoint = 0x02, 14158c2ecf20Sopenharmony_ci .generic_bulk_ctrl_endpoint_response = 0x81, 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci .probe = af9015_probe, 14188c2ecf20Sopenharmony_ci .disconnect = af9015_disconnect, 14198c2ecf20Sopenharmony_ci .identify_state = af9015_identify_state, 14208c2ecf20Sopenharmony_ci .firmware = AF9015_FIRMWARE, 14218c2ecf20Sopenharmony_ci .download_firmware = af9015_download_firmware, 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci .i2c_algo = &af9015_i2c_algo, 14248c2ecf20Sopenharmony_ci .read_config = af9015_read_config, 14258c2ecf20Sopenharmony_ci .frontend_attach = af9015_af9013_frontend_attach, 14268c2ecf20Sopenharmony_ci .frontend_detach = af9015_frontend_detach, 14278c2ecf20Sopenharmony_ci .tuner_attach = af9015_tuner_attach, 14288c2ecf20Sopenharmony_ci .init = af9015_init, 14298c2ecf20Sopenharmony_ci .get_rc_config = af9015_get_rc_config, 14308c2ecf20Sopenharmony_ci .get_stream_config = af9015_get_stream_config, 14318c2ecf20Sopenharmony_ci .streaming_ctrl = af9015_streaming_ctrl, 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci .get_adapter_count = af9015_get_adapter_count, 14348c2ecf20Sopenharmony_ci .adapter = { 14358c2ecf20Sopenharmony_ci { 14368c2ecf20Sopenharmony_ci .caps = DVB_USB_ADAP_HAS_PID_FILTER | 14378c2ecf20Sopenharmony_ci DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, 14388c2ecf20Sopenharmony_ci .pid_filter_count = 32, 14398c2ecf20Sopenharmony_ci .pid_filter = af9015_pid_filter, 14408c2ecf20Sopenharmony_ci .pid_filter_ctrl = af9015_pid_filter_ctrl, 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), 14438c2ecf20Sopenharmony_ci }, { 14448c2ecf20Sopenharmony_ci .caps = DVB_USB_ADAP_HAS_PID_FILTER | 14458c2ecf20Sopenharmony_ci DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, 14468c2ecf20Sopenharmony_ci .pid_filter_count = 32, 14478c2ecf20Sopenharmony_ci .pid_filter = af9015_pid_filter, 14488c2ecf20Sopenharmony_ci .pid_filter_ctrl = af9015_pid_filter_ctrl, 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), 14518c2ecf20Sopenharmony_ci }, 14528c2ecf20Sopenharmony_ci }, 14538c2ecf20Sopenharmony_ci}; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_cistatic const struct usb_device_id af9015_id_table[] = { 14568c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015, 14578c2ecf20Sopenharmony_ci &af9015_props, "Afatech AF9015 reference design", NULL) }, 14588c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016, 14598c2ecf20Sopenharmony_ci &af9015_props, "Afatech AF9015 reference design", NULL) }, 14608c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD, 14618c2ecf20Sopenharmony_ci &af9015_props, "Leadtek WinFast DTV Dongle Gold", RC_MAP_LEADTEK_Y04G0051) }, 14628c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E, 14638c2ecf20Sopenharmony_ci &af9015_props, "Pinnacle PCTV 71e", NULL) }, 14648c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U, 14658c2ecf20Sopenharmony_ci &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) }, 14668c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN, 14678c2ecf20Sopenharmony_ci &af9015_props, "DigitalNow TinyTwin", RC_MAP_AZUREWAVE_AD_TU700) }, 14688c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700, 14698c2ecf20Sopenharmony_ci &af9015_props, "TwinHan AzureWave AD-TU700(704J)", RC_MAP_AZUREWAVE_AD_TU700) }, 14708c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2, 14718c2ecf20Sopenharmony_ci &af9015_props, "TerraTec Cinergy T USB XE", NULL) }, 14728c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T, 14738c2ecf20Sopenharmony_ci &af9015_props, "KWorld PlusTV Dual DVB-T PCI (DVB-T PC160-2T)", NULL) }, 14748c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X, 14758c2ecf20Sopenharmony_ci &af9015_props, "AVerMedia AVerTV DVB-T Volar X", RC_MAP_AVERMEDIA_M135A) }, 14768c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380, 14778c2ecf20Sopenharmony_ci &af9015_props, "Xtensions XD-380", NULL) }, 14788c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO, 14798c2ecf20Sopenharmony_ci &af9015_props, "MSI DIGIVOX Duo", RC_MAP_MSI_DIGIVOX_III) }, 14808c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2, 14818c2ecf20Sopenharmony_ci &af9015_props, "Fujitsu-Siemens Slim Mobile USB DVB-T", NULL) }, 14828c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2, 14838c2ecf20Sopenharmony_ci &af9015_props, "Telestar Starstick 2", NULL) }, 14848c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309, 14858c2ecf20Sopenharmony_ci &af9015_props, "AVerMedia A309", NULL) }, 14868c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III, 14878c2ecf20Sopenharmony_ci &af9015_props, "MSI Digi VOX mini III", RC_MAP_MSI_DIGIVOX_III) }, 14888c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U, 14898c2ecf20Sopenharmony_ci &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, 14908c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2, 14918c2ecf20Sopenharmony_ci &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, 14928c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3, 14938c2ecf20Sopenharmony_ci &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, 14948c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT, 14958c2ecf20Sopenharmony_ci &af9015_props, "TrekStor DVB-T USB Stick", RC_MAP_TREKSTOR) }, 14968c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850, 14978c2ecf20Sopenharmony_ci &af9015_props, "AverMedia AVerTV Volar Black HD (A850)", NULL) }, 14988c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805, 14998c2ecf20Sopenharmony_ci &af9015_props, "AverMedia AVerTV Volar GPS 805 (A805)", NULL) }, 15008c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU, 15018c2ecf20Sopenharmony_ci &af9015_props, "Conceptronic USB2.0 DVB-T CTVDIGRCU V3.0", NULL) }, 15028c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810, 15038c2ecf20Sopenharmony_ci &af9015_props, "KWorld Digital MC-810", NULL) }, 15048c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03, 15058c2ecf20Sopenharmony_ci &af9015_props, "Genius TVGo DVB-T03", NULL) }, 15068c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2, 15078c2ecf20Sopenharmony_ci &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) }, 15088c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T, 15098c2ecf20Sopenharmony_ci &af9015_props, "KWorld PlusTV DVB-T PCI Pro Card (DVB-T PC160-T)", NULL) }, 15108c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20, 15118c2ecf20Sopenharmony_ci &af9015_props, "Sveon STV20 Tuner USB DVB-T HDTV", NULL) }, 15128c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2, 15138c2ecf20Sopenharmony_ci &af9015_props, "DigitalNow TinyTwin v2", RC_MAP_DIGITALNOW_TINYTWIN) }, 15148c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS, 15158c2ecf20Sopenharmony_ci &af9015_props, "Leadtek WinFast DTV2000DS", RC_MAP_LEADTEK_Y04G0051) }, 15168c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T, 15178c2ecf20Sopenharmony_ci &af9015_props, "KWorld USB DVB-T Stick Mobile (UB383-T)", NULL) }, 15188c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4, 15198c2ecf20Sopenharmony_ci &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, 15208c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M, 15218c2ecf20Sopenharmony_ci &af9015_props, "AverMedia AVerTV Volar M (A815Mac)", NULL) }, 15228c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC, 15238c2ecf20Sopenharmony_ci &af9015_props, "TerraTec Cinergy T Stick RC", RC_MAP_TERRATEC_SLIM_2) }, 15248c2ecf20Sopenharmony_ci /* XXX: that same ID [0ccd:0099] is used by af9035 driver too */ 15258c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC, 15268c2ecf20Sopenharmony_ci &af9015_props, "TerraTec Cinergy T Stick Dual RC", RC_MAP_TERRATEC_SLIM) }, 15278c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T, 15288c2ecf20Sopenharmony_ci &af9015_props, "AverMedia AVerTV Red HD+ (A850T)", NULL) }, 15298c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3, 15308c2ecf20Sopenharmony_ci &af9015_props, "DigitalNow TinyTwin v3", RC_MAP_DIGITALNOW_TINYTWIN) }, 15318c2ecf20Sopenharmony_ci { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22, 15328c2ecf20Sopenharmony_ci &af9015_props, "Sveon STV22 Dual USB DVB-T Tuner HDTV", RC_MAP_MSI_DIGIVOX_III) }, 15338c2ecf20Sopenharmony_ci { } 15348c2ecf20Sopenharmony_ci}; 15358c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, af9015_id_table); 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci/* usb specific object needed to register this driver with the usb subsystem */ 15388c2ecf20Sopenharmony_cistatic struct usb_driver af9015_usb_driver = { 15398c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 15408c2ecf20Sopenharmony_ci .id_table = af9015_id_table, 15418c2ecf20Sopenharmony_ci .probe = dvb_usbv2_probe, 15428c2ecf20Sopenharmony_ci .disconnect = dvb_usbv2_disconnect, 15438c2ecf20Sopenharmony_ci .suspend = dvb_usbv2_suspend, 15448c2ecf20Sopenharmony_ci .resume = dvb_usbv2_resume, 15458c2ecf20Sopenharmony_ci .reset_resume = dvb_usbv2_reset_resume, 15468c2ecf20Sopenharmony_ci .no_dynamic_id = 1, 15478c2ecf20Sopenharmony_ci .soft_unbind = 1, 15488c2ecf20Sopenharmony_ci}; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_cimodule_usb_driver(af9015_usb_driver); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ciMODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 15538c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Afatech AF9015 driver"); 15548c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 15558c2ecf20Sopenharmony_ciMODULE_FIRMWARE(AF9015_FIRMWARE); 1556