From: Antti Palosaari Date: Mon, 9 Jul 2012 17:59:28 +0000 (-0300) Subject: [media] dvb_usb_v2: move from dvb-usb to dvb-usb-v2 X-Git-Tag: firefly_0821_release~3680^2~275^2~1608 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=ad6b9e517b39acec98862e7f9bddefe1b275445b;p=firefly-linux-kernel-4.4.55.git [media] dvb_usb_v2: move from dvb-usb to dvb-usb-v2 Move to own directory. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index f6e40b3a44cc..3a6ccbc02add 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -44,6 +44,7 @@ source "drivers/media/dvb/ttpci/Kconfig" comment "Supported USB Adapters" depends on DVB_CORE && USB && I2C source "drivers/media/dvb/dvb-usb/Kconfig" +source "drivers/media/dvb/dvb-usb-v2/Kconfig" source "drivers/media/dvb/ttusb-budget/Kconfig" source "drivers/media/dvb/ttusb-dec/Kconfig" source "drivers/media/dvb/siano/Kconfig" diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index b2cefe637a64..8f7e0129d70e 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile @@ -10,6 +10,7 @@ obj-y := dvb-core/ \ b2c2/ \ bt8xx/ \ dvb-usb/ \ + dvb-usb-v2/ \ pluto2/ \ siano/ \ dm1105/ \ diff --git a/drivers/media/dvb/dvb-usb-v2/Kconfig b/drivers/media/dvb/dvb-usb-v2/Kconfig new file mode 100644 index 000000000000..bef2ffa18130 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/Kconfig @@ -0,0 +1,104 @@ +config DVB_USB_V2 + tristate "Support for various USB DVB devices v2" + depends on DVB_CORE && USB && I2C && RC_CORE + help + By enabling this you will be able to choose the various supported + USB1.1 and USB2.0 DVB devices. + + Almost every USB device needs a firmware, please look into + . + + For a complete list of supported USB devices see the LinuxTV DVB Wiki: + + + Say Y if you own a USB DVB device. + +config DVB_USB_FIRMWARE + tristate "Firmware helper routines" + depends on DVB_USB_V2 + +config DVB_USB_AF9015 + tristate "Afatech AF9015 DVB-T USB2.0 support" + depends on DVB_USB_V2 + select DVB_AF9013 + select DVB_PLL if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver + +config DVB_USB_AF9035 + tristate "Afatech AF9035 DVB-T USB2.0 support" + depends on DVB_USB_V2 + select DVB_AF9033 + select MEDIA_TUNER_TUA9001 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_FC0011 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Afatech AF9035 based DVB USB receiver. + +config DVB_USB_ANYSEE + tristate "Anysee DVB-T/C USB2.0 support" + depends on DVB_USB_V2 + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA18212 if !MEDIA_TUNER_CUSTOMISE + select DVB_CX24116 if !DVB_FE_CUSTOMISE + select DVB_STV0900 if !DVB_FE_CUSTOMISE + select DVB_STV6110 if !DVB_FE_CUSTOMISE + select DVB_ISL6423 if !DVB_FE_CUSTOMISE + select DVB_CXD2820R if !DVB_FE_CUSTOMISE + help + Say Y here to support the Anysee E30, Anysee E30 Plus or + Anysee E30 C Plus DVB USB2.0 receiver. + +config DVB_USB_AU6610 + tristate "Alcor Micro AU6610 USB2.0 support" + depends on DVB_USB_V2 + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver. + +config DVB_USB_CE6230 + tristate "Intel CE6230 DVB-T USB2.0 support" + depends on DVB_USB_V2 + select DVB_ZL10353 + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver + +config DVB_USB_EC168 + tristate "E3C EC168 DVB-T USB2.0 support" + depends on DVB_USB_V2 + select DVB_EC100 + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the E3C EC168 DVB-T USB2.0 receiver. + +config DVB_USB_GL861 + tristate "Genesys Logic GL861 USB2.0 support" + depends on DVB_USB_V2 + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0 + receiver with USB ID 0db0:5581. + +config DVB_USB_MXL111SF + tristate "MxL111SF DTV USB2.0 support" + depends on DVB_USB_V2 + select DVB_LGDT3305 if !DVB_FE_CUSTOMISE + select DVB_LG2160 if !DVB_FE_CUSTOMISE + select VIDEO_TVEEPROM + help + Say Y here to support the MxL111SF USB2.0 DTV receiver. + diff --git a/drivers/media/dvb/dvb-usb-v2/Makefile b/drivers/media/dvb/dvb-usb-v2/Makefile new file mode 100644 index 000000000000..6080ec89577f --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/Makefile @@ -0,0 +1,35 @@ +dvb_usbv2-objs = dvb_usb_core.o dvb_usb_urb.o usb_urb.o +obj-$(CONFIG_DVB_USB_V2) += dvb_usbv2.o + +obj-$(CONFIG_DVB_USB_FIRMWARE) += dvb_usb_firmware.o + +dvb-usb-af9015-objs = af9015.o +obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o + +dvb-usb-af9035-objs = af9035.o +obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o + +dvb-usb-anysee-objs = anysee.o +obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o + +dvb-usb-au6610-objs = au6610.o +obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o + +dvb-usb-ce6230-objs = ce6230.o +obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o + +dvb-usb-ec168-objs = ec168.o +obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o + +dvb-usb-gl861-objs = gl861.o +obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o + +dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o +obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o +obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o +obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o + +ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core +ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/ +ccflags-y += -I$(srctree)/drivers/media/common/tuners + diff --git a/drivers/media/dvb/dvb-usb-v2/af9015.c b/drivers/media/dvb/dvb-usb-v2/af9015.c new file mode 100644 index 000000000000..bbe1d3382195 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/af9015.c @@ -0,0 +1,1426 @@ +/* + * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari + * + * Thanks to Afatech who kindly provided information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "af9015.h" + +static int dvb_usb_af9015_debug; +module_param_named(debug, dvb_usb_af9015_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); +static int dvb_usb_af9015_remote; +module_param_named(remote, dvb_usb_af9015_remote, int, 0644); +MODULE_PARM_DESC(remote, "select remote"); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) +{ +#define BUF_LEN 63 +#define REQ_HDR_LEN 8 /* send header size */ +#define ACK_HDR_LEN 2 /* rece header size */ + struct af9015_state *state = d_to_priv(d); + int ret, wlen, rlen; + u8 buf[BUF_LEN]; + u8 write = 1; + + buf[0] = req->cmd; + buf[1] = state->seq++; + buf[2] = req->i2c_addr; + buf[3] = req->addr >> 8; + buf[4] = req->addr & 0xff; + buf[5] = req->mbox; + buf[6] = req->addr_len; + buf[7] = req->data_len; + + switch (req->cmd) { + case GET_CONFIG: + case READ_MEMORY: + case RECONNECT_USB: + write = 0; + break; + case READ_I2C: + write = 0; + buf[2] |= 0x01; /* set I2C direction */ + case WRITE_I2C: + buf[0] = READ_WRITE_I2C; + break; + case WRITE_MEMORY: + if (((req->addr & 0xff00) == 0xff00) || + ((req->addr & 0xff00) == 0xae00)) + buf[0] = WRITE_VIRTUAL_MEMORY; + case WRITE_VIRTUAL_MEMORY: + case COPY_FIRMWARE: + case DOWNLOAD_FIRMWARE: + case BOOT: + break; + default: + err("unknown command:%d", req->cmd); + ret = -1; + goto error; + } + + /* buffer overflow check */ + if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) || + (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { + err("too much data; cmd:%d len:%d", req->cmd, req->data_len); + ret = -EINVAL; + goto error; + } + + /* write receives seq + status = 2 bytes + read receives seq + status + data = 2 + N bytes */ + wlen = REQ_HDR_LEN; + rlen = ACK_HDR_LEN; + if (write) { + wlen += req->data_len; + memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len); + } else { + rlen += req->data_len; + } + + /* no ack for these packets */ + if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) + rlen = 0; + + ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen); + if (ret) + goto error; + + /* check status */ + if (rlen && buf[1]) { + err("command failed:%d", buf[1]); + ret = -1; + goto error; + } + + /* read request, copy returned data to return buf */ + if (!write) + memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len); +error: + return ret; +} + +static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val, + u8 len) +{ + struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, + val}; + return af9015_ctrl_msg(d, &req); +} + +static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len) +{ + struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, + val}; + return af9015_ctrl_msg(d, &req); +} + +static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val) +{ + return af9015_write_regs(d, addr, &val, 1); +} + +static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val) +{ + return af9015_read_regs(d, addr, val, 1); +} + +static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, + u8 val) +{ + struct af9015_state *state = d_to_priv(d); + struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; + + if (addr == state->af9013_config[0].i2c_addr || + addr == state->af9013_config[1].i2c_addr) + req.addr_len = 3; + + return af9015_ctrl_msg(d, &req); +} + +static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, + u8 *val) +{ + struct af9015_state *state = d_to_priv(d); + struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; + + if (addr == state->af9013_config[0].i2c_addr || + addr == state->af9013_config[1].i2c_addr) + req.addr_len = 3; + + return af9015_ctrl_msg(d, &req); +} + +static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op) +{ + int ret; + u8 val, mask = 0x01; + + ret = af9015_read_reg(d, addr, &val); + if (ret) + return ret; + + mask <<= bit; + if (op) { + /* set bit */ + val |= mask; + } else { + /* clear bit */ + mask ^= 0xff; + val &= mask; + } + + return af9015_write_reg(d, addr, val); +} + +static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) +{ + return af9015_do_reg_bit(d, addr, bit, 1); +} + +static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) +{ + return af9015_do_reg_bit(d, addr, bit, 0); +} + +static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct af9015_state *state = d_to_priv(d); + int ret = 0, i = 0; + u16 addr; + u8 uninitialized_var(mbox), addr_len; + struct req_t req; + +/* +The bus lock is needed because there is two tuners both using same I2C-address. +Due to that the only way to select correct tuner is use demodulator I2C-gate. + +................................................ +. AF9015 includes integrated AF9013 demodulator. +. ____________ ____________ . ____________ +.| uC | | demod | . | tuner | +.|------------| |------------| . |------------| +.| AF9015 | | AF9013/5 | . | MXL5003 | +.| |--+----I2C-------|-----/ -----|-.-----I2C-------| | +.| | | | addr 0x38 | . | addr 0xc6 | +.|____________| | |____________| . |____________| +.................|.............................. + | ____________ ____________ + | | demod | | tuner | + | |------------| |------------| + | | AF9013 | | MXL5003 | + +----I2C-------|-----/ -----|-------I2C-------| | + | addr 0x3a | | addr 0xc6 | + |____________| |____________| +*/ + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + while (i < num) { + if (msg[i].addr == state->af9013_config[0].i2c_addr || + msg[i].addr == state->af9013_config[1].i2c_addr) { + addr = msg[i].buf[0] << 8; + addr += msg[i].buf[1]; + mbox = msg[i].buf[2]; + addr_len = 3; + } else { + addr = msg[i].buf[0]; + addr_len = 1; + /* mbox is don't care in that case */ + } + + if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { + if (msg[i].len > 3 || msg[i+1].len > 61) { + ret = -EOPNOTSUPP; + goto error; + } + if (msg[i].addr == state->af9013_config[0].i2c_addr) + req.cmd = READ_MEMORY; + else + req.cmd = READ_I2C; + req.i2c_addr = msg[i].addr; + req.addr = addr; + req.mbox = mbox; + req.addr_len = addr_len; + req.data_len = msg[i+1].len; + req.data = &msg[i+1].buf[0]; + ret = af9015_ctrl_msg(d, &req); + i += 2; + } else if (msg[i].flags & I2C_M_RD) { + if (msg[i].len > 61) { + ret = -EOPNOTSUPP; + goto error; + } + if (msg[i].addr == state->af9013_config[0].i2c_addr) { + ret = -EINVAL; + goto error; + } + req.cmd = READ_I2C; + req.i2c_addr = msg[i].addr; + req.addr = addr; + req.mbox = mbox; + req.addr_len = addr_len; + req.data_len = msg[i].len; + req.data = &msg[i].buf[0]; + ret = af9015_ctrl_msg(d, &req); + i += 1; + } else { + if (msg[i].len > 21) { + ret = -EOPNOTSUPP; + goto error; + } + if (msg[i].addr == state->af9013_config[0].i2c_addr) + req.cmd = WRITE_MEMORY; + else + req.cmd = WRITE_I2C; + req.i2c_addr = msg[i].addr; + req.addr = addr; + req.mbox = mbox; + req.addr_len = addr_len; + req.data_len = msg[i].len-addr_len; + req.data = &msg[i].buf[addr_len]; + ret = af9015_ctrl_msg(d, &req); + i += 1; + } + if (ret) + goto error; + + } + ret = i; + +error: + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static u32 af9015_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm af9015_i2c_algo = { + .master_xfer = af9015_i2c_xfer, + .functionality = af9015_i2c_func, +}; + +static int af9015_identify_state(struct dvb_usb_device *d, const char **name) +{ + int ret; + u8 reply; + struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply}; + + ret = af9015_ctrl_msg(d, &req); + if (ret) + return ret; + + deb_info("%s: reply:%02x\n", __func__, reply); + if (reply == 0x02) + ret = WARM; + else + ret = COLD; + + return ret; +} + +static int af9015_download_firmware(struct dvb_usb_device *d, + const struct firmware *fw) +{ + struct af9015_state *state = d_to_priv(d); + int i, len, remaining, ret; + struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; + u16 checksum = 0; + + deb_info("%s:\n", __func__); + + /* calc checksum */ + for (i = 0; i < fw->size; i++) + checksum += fw->data[i]; + + state->firmware_size = fw->size; + state->firmware_checksum = checksum; + + #define FW_ADDR 0x5100 /* firmware start address */ + #define LEN_MAX 55 /* max packet size */ + for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { + len = remaining; + if (len > LEN_MAX) + len = LEN_MAX; + + req.data_len = len; + req.data = (u8 *) &fw->data[fw->size - remaining]; + req.addr = FW_ADDR + fw->size - remaining; + + ret = af9015_ctrl_msg(d, &req); + if (ret) { + err("firmware download failed:%d", ret); + goto error; + } + } + + /* firmware loaded, request boot */ + req.cmd = BOOT; + req.data_len = 0; + ret = af9015_ctrl_msg(d, &req); + if (ret) { + err("firmware boot failed:%d", ret); + goto error; + } + +error: + return ret; +} + +/* hash (and dump) eeprom */ +static int af9015_eeprom_hash(struct dvb_usb_device *d) +{ + struct af9015_state *state = d_to_priv(d); + int ret; + static const unsigned int eeprom_size = 256; + unsigned int reg; + u8 val, *eeprom; + struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; + + eeprom = kmalloc(eeprom_size, GFP_KERNEL); + if (eeprom == NULL) + return -ENOMEM; + + for (reg = 0; reg < eeprom_size; reg++) { + req.addr = reg; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto free; + + eeprom[reg] = val; + } + + if (dvb_usb_af9015_debug & 0x01) + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, eeprom, + eeprom_size); + + BUG_ON(eeprom_size % 4); + + state->eeprom_sum = 0; + for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) { + state->eeprom_sum *= GOLDEN_RATIO_PRIME_32; + state->eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]); + } + + deb_info("%s: eeprom sum=%.8x\n", __func__, state->eeprom_sum); + + ret = 0; +free: + kfree(eeprom); + return ret; +} + +static int af9015_read_config(struct dvb_usb_device *d) +{ + struct af9015_state *state = d_to_priv(d); + int ret; + u8 val, i, offset = 0; + struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; + + deb_info("%s:\n", __func__); + + /* IR remote controller */ + req.addr = AF9015_EEPROM_IR_MODE; + /* first message will timeout often due to possible hw bug */ + for (i = 0; i < 4; i++) { + ret = af9015_ctrl_msg(d, &req); + if (!ret) + break; + } + if (ret) + goto error; + + ret = af9015_eeprom_hash(d); + if (ret) + goto error; + + deb_info("%s: IR mode=%d\n", __func__, val); + state->ir_mode = val; + + /* TS mode - one or two receivers */ + req.addr = AF9015_EEPROM_TS_MODE; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + + state->dual_mode = val; + deb_info("%s: TS mode=%d\n", __func__, state->dual_mode); + + /* disable 2nd adapter because we don't have PID-filters */ + if (d->udev->speed == USB_SPEED_FULL) + state->dual_mode = 0; + + if (state->dual_mode) { + /* read 2nd demodulator I2C address */ + req.addr = AF9015_EEPROM_DEMOD2_I2C; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + + state->af9013_config[1].i2c_addr = val; + } + + for (i = 0; i < state->dual_mode + 1; i++) { + if (i == 1) + offset = AF9015_EEPROM_OFFSET; + /* xtal */ + req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + switch (val) { + case 0: + state->af9013_config[i].clock = 28800000; + break; + case 1: + state->af9013_config[i].clock = 20480000; + break; + case 2: + state->af9013_config[i].clock = 28000000; + break; + case 3: + state->af9013_config[i].clock = 25000000; + break; + }; + deb_info("%s: [%d] xtal=%d set clock=%d\n", __func__, i, + val, state->af9013_config[i].clock); + + /* IF frequency */ + req.addr = AF9015_EEPROM_IF1H + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + + state->af9013_config[i].if_frequency = val << 8; + + req.addr = AF9015_EEPROM_IF1L + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + + state->af9013_config[i].if_frequency += val; + state->af9013_config[i].if_frequency *= 1000; + deb_info("%s: [%d] IF frequency=%d\n", __func__, i, + state->af9013_config[i].if_frequency); + + /* MT2060 IF1 */ + req.addr = AF9015_EEPROM_MT2060_IF1H + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + state->mt2060_if1[i] = val << 8; + req.addr = AF9015_EEPROM_MT2060_IF1L + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + state->mt2060_if1[i] += val; + deb_info("%s: [%d] MT2060 IF1=%d\n", __func__, i, + state->mt2060_if1[i]); + + /* tuner */ + req.addr = AF9015_EEPROM_TUNER_ID1 + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + switch (val) { + case AF9013_TUNER_ENV77H11D5: + case AF9013_TUNER_MT2060: + case AF9013_TUNER_QT1010: + case AF9013_TUNER_UNKNOWN: + case AF9013_TUNER_MT2060_2: + case AF9013_TUNER_TDA18271: + case AF9013_TUNER_QT1010A: + case AF9013_TUNER_TDA18218: + state->af9013_config[i].spec_inv = 1; + break; + case AF9013_TUNER_MXL5003D: + case AF9013_TUNER_MXL5005D: + case AF9013_TUNER_MXL5005R: + case AF9013_TUNER_MXL5007T: + state->af9013_config[i].spec_inv = 0; + break; + case AF9013_TUNER_MC44S803: + state->af9013_config[i].gpio[1] = AF9013_GPIO_LO; + state->af9013_config[i].spec_inv = 1; + break; + default: + warn("tuner id=%d not supported, please report!", val); + return -ENODEV; + }; + + state->af9013_config[i].tuner = val; + deb_info("%s: [%d] tuner id=%d\n", __func__, i, val); + } + +error: + if (ret) + err("eeprom read failed=%d", ret); + + /* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM + content :-( Override some wrong values here. Ditto for the + AVerTV Red HD+ (A850T) device. */ + if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA && + ((le16_to_cpu(d->udev->descriptor.idProduct) == + USB_PID_AVERMEDIA_A850) || + (le16_to_cpu(d->udev->descriptor.idProduct) == + USB_PID_AVERMEDIA_A850T))) { + deb_info("%s: AverMedia A850: overriding config\n", __func__); + /* disable dual mode */ + state->dual_mode = 0; + + /* set correct IF */ + state->af9013_config[0].if_frequency = 4570000; + } + + return ret; +} + +static int af9015_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, + struct usb_data_stream_properties *stream) +{ + deb_info("%s: adap=%d\n", __func__, fe_to_adap(fe)->id); + + if (fe_to_d(fe)->udev->speed == USB_SPEED_FULL) + stream->u.bulk.buffersize = TS_USB11_FRAME_SIZE; + + return 0; +} + +static int af9015_get_adapter_count(struct dvb_usb_device *d) +{ + struct af9015_state *state = d_to_priv(d); + return state->dual_mode + 1; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_set_frontend(struct dvb_frontend *fe) +{ + int ret; + struct af9015_state *state = fe_to_priv(fe); + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->set_frontend[fe_to_adap(fe)->id](fe); + + mutex_unlock(&state->fe_mutex); + + return ret; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_read_status(struct dvb_frontend *fe, + fe_status_t *status) +{ + int ret; + struct af9015_state *state = fe_to_priv(fe); + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->read_status[fe_to_adap(fe)->id](fe, status); + + mutex_unlock(&state->fe_mutex); + + return ret; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_init(struct dvb_frontend *fe) +{ + int ret; + struct af9015_state *state = fe_to_priv(fe); + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->init[fe_to_adap(fe)->id](fe); + + mutex_unlock(&state->fe_mutex); + + return ret; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_sleep(struct dvb_frontend *fe) +{ + int ret; + struct af9015_state *state = fe_to_priv(fe); + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->sleep[fe_to_adap(fe)->id](fe); + + mutex_unlock(&state->fe_mutex); + + return ret; +} + +/* override tuner callbacks for resource locking */ +static int af9015_tuner_init(struct dvb_frontend *fe) +{ + int ret; + struct af9015_state *state = fe_to_priv(fe); + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->tuner_init[fe_to_adap(fe)->id](fe); + + mutex_unlock(&state->fe_mutex); + + return ret; +} + +/* override tuner callbacks for resource locking */ +static int af9015_tuner_sleep(struct dvb_frontend *fe) +{ + int ret; + struct af9015_state *state = fe_to_priv(fe); + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->tuner_sleep[fe_to_adap(fe)->id](fe); + + mutex_unlock(&state->fe_mutex); + + return ret; +} + +static int af9015_copy_firmware(struct dvb_usb_device *d) +{ + struct af9015_state *state = d_to_priv(d); + int ret; + u8 fw_params[4]; + u8 val, i; + struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params), + fw_params }; + deb_info("%s:\n", __func__); + + fw_params[0] = state->firmware_size >> 8; + fw_params[1] = state->firmware_size & 0xff; + fw_params[2] = state->firmware_checksum >> 8; + fw_params[3] = state->firmware_checksum & 0xff; + + /* wait 2nd demodulator ready */ + msleep(100); + + ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr, + 0x98be, &val); + if (ret) + goto error; + else + deb_info("%s: firmware status:%02x\n", __func__, val); + + if (val == 0x0c) /* fw is running, no need for download */ + goto exit; + + /* set I2C master clock to fast (to speed up firmware copy) */ + ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */ + if (ret) + goto error; + + msleep(50); + + /* copy firmware */ + ret = af9015_ctrl_msg(d, &req); + if (ret) + err("firmware copy cmd failed:%d", ret); + deb_info("%s: firmware copy done\n", __func__); + + /* set I2C master clock back to normal */ + ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */ + if (ret) + goto error; + + /* request boot firmware */ + ret = af9015_write_reg_i2c(d, state->af9013_config[1].i2c_addr, + 0xe205, 1); + deb_info("%s: firmware boot cmd status:%d\n", __func__, ret); + if (ret) + goto error; + + for (i = 0; i < 15; i++) { + msleep(100); + + /* check firmware status */ + ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr, + 0x98be, &val); + deb_info("%s: firmware status cmd status:%d fw status:%02x\n", + __func__, ret, val); + if (ret) + goto error; + + if (val == 0x0c || val == 0x04) /* success or fail */ + break; + } + + if (val == 0x04) { + err("firmware did not run"); + ret = -1; + } else if (val != 0x0c) { + err("firmware boot timeout"); + ret = -1; + } + +error: +exit: + return ret; +} + +static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) +{ + int ret; + struct af9015_state *state = adap_to_priv(adap); + + if (adap->id == 0) { + state->af9013_config[0].ts_mode = AF9013_TS_USB; + memcpy(state->af9013_config[0].api_version, "\x0\x1\x9\x0", 4); + state->af9013_config[0].gpio[0] = AF9013_GPIO_HI; + state->af9013_config[0].gpio[3] = AF9013_GPIO_TUNER_ON; + } else if (adap->id == 1) { + state->af9013_config[1].ts_mode = AF9013_TS_SERIAL; + memcpy(state->af9013_config[1].api_version, "\x0\x1\x9\x0", 4); + state->af9013_config[1].gpio[0] = AF9013_GPIO_TUNER_ON; + state->af9013_config[1].gpio[1] = AF9013_GPIO_LO; + + /* copy firmware to 2nd demodulator */ + if (state->dual_mode) { + ret = af9015_copy_firmware(adap_to_d(adap)); + if (ret) { + err("firmware copy to 2nd frontend " \ + "failed, will disable it"); + state->dual_mode = 0; + return -ENODEV; + } + } else { + return -ENODEV; + } + } + + /* attach demodulator */ + adap->fe[0] = dvb_attach(af9013_attach, + &state->af9013_config[adap->id], &adap_to_d(adap)->i2c_adap); + + /* + * AF9015 firmware does not like if it gets interrupted by I2C adapter + * request on some critical phases. During normal operation I2C adapter + * is used only 2nd demodulator and tuner on dual tuner devices. + * Override demodulator callbacks and use mutex for limit access to + * those "critical" paths to keep AF9015 happy. + */ + if (adap->fe[0]) { + state->set_frontend[adap->id] = + adap->fe[0]->ops.set_frontend; + adap->fe[0]->ops.set_frontend = + af9015_af9013_set_frontend; + + state->read_status[adap->id] = + adap->fe[0]->ops.read_status; + adap->fe[0]->ops.read_status = + af9015_af9013_read_status; + + state->init[adap->id] = adap->fe[0]->ops.init; + adap->fe[0]->ops.init = af9015_af9013_init; + + state->sleep[adap->id] = adap->fe[0]->ops.sleep; + adap->fe[0]->ops.sleep = af9015_af9013_sleep; + } + + return adap->fe[0] == NULL ? -ENODEV : 0; +} + +static struct mt2060_config af9015_mt2060_config = { + .i2c_address = 0xc0, + .clock_out = 0, +}; + +static struct qt1010_config af9015_qt1010_config = { + .i2c_address = 0xc4, +}; + +static struct tda18271_config af9015_tda18271_config = { + .gate = TDA18271_GATE_DIGITAL, + .small_i2c = TDA18271_16_BYTE_CHUNK_INIT, +}; + +static struct mxl5005s_config af9015_mxl5003_config = { + .i2c_address = 0xc6, + .if_freq = IF_FREQ_4570000HZ, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_DEFAULT, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +static struct mxl5005s_config af9015_mxl5005_config = { + .i2c_address = 0xc6, + .if_freq = IF_FREQ_4570000HZ, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_OFF, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +static struct mc44s803_config af9015_mc44s803_config = { + .i2c_address = 0xc0, + .dig_out = 1, +}; + +static struct tda18218_config af9015_tda18218_config = { + .i2c_address = 0xc0, + .i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */ +}; + +static struct mxl5007t_config af9015_mxl5007t_config = { + .xtal_freq_hz = MxL_XTAL_24_MHZ, + .if_freq_hz = MxL_IF_4_57_MHZ, +}; + +static int af9015_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct af9015_state *state = adap_to_priv(adap); + int ret; + deb_info("%s:\n", __func__); + + switch (state->af9013_config[adap->id].tuner) { + case AF9013_TUNER_MT2060: + case AF9013_TUNER_MT2060_2: + ret = dvb_attach(mt2060_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, &af9015_mt2060_config, + state->mt2060_if1[adap->id]) + == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_QT1010: + case AF9013_TUNER_QT1010A: + ret = dvb_attach(qt1010_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + &af9015_qt1010_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_TDA18271: + ret = dvb_attach(tda18271_attach, adap->fe[0], 0xc0, + &adap_to_d(adap)->i2c_adap, + &af9015_tda18271_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_TDA18218: + ret = dvb_attach(tda18218_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + &af9015_tda18218_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_MXL5003D: + ret = dvb_attach(mxl5005s_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + &af9015_mxl5003_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_MXL5005D: + case AF9013_TUNER_MXL5005R: + ret = dvb_attach(mxl5005s_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + &af9015_mxl5005_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_ENV77H11D5: + ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0xc0, + &adap_to_d(adap)->i2c_adap, + DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_MC44S803: + ret = dvb_attach(mc44s803_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + &af9015_mc44s803_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_MXL5007T: + ret = dvb_attach(mxl5007t_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_UNKNOWN: + default: + ret = -ENODEV; + err("Unknown tuner id:%d", + state->af9013_config[adap->id].tuner); + } + + if (adap->fe[0]->ops.tuner_ops.init) { + state->tuner_init[adap->id] = + adap->fe[0]->ops.tuner_ops.init; + adap->fe[0]->ops.tuner_ops.init = af9015_tuner_init; + } + + if (adap->fe[0]->ops.tuner_ops.sleep) { + state->tuner_sleep[adap->id] = + adap->fe[0]->ops.tuner_ops.sleep; + adap->fe[0]->ops.tuner_ops.sleep = af9015_tuner_sleep; + } + + return ret; +} + +static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + int ret; + deb_info("%s: onoff:%d\n", __func__, onoff); + + if (onoff) + ret = af9015_set_reg_bit(adap_to_d(adap), 0xd503, 0); + else + ret = af9015_clear_reg_bit(adap_to_d(adap), 0xd503, 0); + + return ret; +} + +static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, + int onoff) +{ + int ret; + u8 idx; + + deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n", + __func__, index, pid, onoff); + + ret = af9015_write_reg(adap_to_d(adap), 0xd505, (pid & 0xff)); + if (ret) + goto error; + + ret = af9015_write_reg(adap_to_d(adap), 0xd506, (pid >> 8)); + if (ret) + goto error; + + idx = ((index & 0x1f) | (1 << 5)); + ret = af9015_write_reg(adap_to_d(adap), 0xd504, idx); + +error: + return ret; +} + +static int af9015_init_endpoint(struct dvb_usb_device *d) +{ + struct af9015_state *state = d_to_priv(d); + int ret; + u16 frame_size; + u8 packet_size; + deb_info("%s: USB speed:%d\n", __func__, d->udev->speed); + + if (d->udev->speed == USB_SPEED_FULL) { + frame_size = TS_USB11_FRAME_SIZE/4; + packet_size = TS_USB11_MAX_PACKET_SIZE/4; + } else { + frame_size = TS_USB20_FRAME_SIZE/4; + packet_size = TS_USB20_MAX_PACKET_SIZE/4; + } + + ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */ + if (ret) + goto error; + ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */ + if (ret) + goto error; + ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */ + if (ret) + goto error; + if (state->dual_mode) { + ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */ + if (ret) + goto error; + } + ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */ + if (ret) + goto error; + if (state->dual_mode) { + ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */ + if (ret) + goto error; + } + /* EP4 xfer length */ + ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd89, frame_size >> 8); + if (ret) + goto error; + /* EP5 xfer length */ + ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */ + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */ + if (ret) + goto error; + if (state->dual_mode) { + ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */ + if (ret) + goto error; + } + + /* enable / disable mp2if2 */ + if (state->dual_mode) + ret = af9015_set_reg_bit(d, 0xd50b, 0); + else + ret = af9015_clear_reg_bit(d, 0xd50b, 0); + +error: + if (ret) + err("endpoint init failed:%d", ret); + return ret; +} + +static int af9015_init(struct dvb_usb_device *d) +{ + struct af9015_state *state = d_to_priv(d); + int ret; + deb_info("%s:\n", __func__); + + mutex_init(&state->fe_mutex); + + /* init RC canary */ + ret = af9015_write_reg(d, 0x98e9, 0xff); + if (ret) + goto error; + + ret = af9015_init_endpoint(d); + if (ret) + goto error; + +error: + return ret; +} + +struct af9015_rc_setup { + unsigned int id; + char *rc_codes; +}; + +static char *af9015_rc_setup_match(unsigned int id, + const struct af9015_rc_setup *table) +{ + for (; table->rc_codes; table++) + if (table->id == id) + return table->rc_codes; + return NULL; +} + +static const struct af9015_rc_setup af9015_rc_setup_modparam[] = { + { AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M }, + { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II }, + { AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND }, + { AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE }, + { AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS }, + { } +}; + +static const struct af9015_rc_setup af9015_rc_setup_hashes[] = { + { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II }, + { 0xa3703d00, RC_MAP_ALINK_DTU_M }, + { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */ + { 0x5d49e3db, RC_MAP_DIGITTRADE }, /* LC-Power LC-USB-DVBT */ + { } +}; + +static int af9015_rc_query(struct dvb_usb_device *d) +{ + struct af9015_state *state = d_to_priv(d); + int ret; + u8 buf[17]; + + deb_info("%s:\n", __func__); + + /* read registers needed to detect remote controller code */ + ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf)); + if (ret) + goto error; + + /* If any of these are non-zero, assume invalid data */ + if (buf[1] || buf[2] || buf[3]) + return ret; + + /* Check for repeat of previous code */ + if ((state->rc_repeat != buf[6] || buf[0]) && + !memcmp(&buf[12], state->rc_last, 4)) { + deb_rc("%s: key repeated\n", __func__); + rc_keydown(d->rc_dev, state->rc_keycode, 0); + state->rc_repeat = buf[6]; + return ret; + } + + /* Only process key if canary killed */ + if (buf[16] != 0xff && buf[0] != 0x01) { + deb_rc("%s: key pressed %02x %02x %02x %02x\n", __func__, + buf[12], buf[13], buf[14], buf[15]); + + /* Reset the canary */ + ret = af9015_write_reg(d, 0x98e9, 0xff); + if (ret) + goto error; + + /* Remember this key */ + memcpy(state->rc_last, &buf[12], 4); + if (buf[14] == (u8) ~buf[15]) { + if (buf[12] == (u8) ~buf[13]) { + /* NEC */ + state->rc_keycode = buf[12] << 8 | buf[14]; + } else { + /* NEC extended*/ + state->rc_keycode = buf[12] << 16 | + buf[13] << 8 | buf[14]; + } + } else { + /* 32 bit NEC */ + state->rc_keycode = buf[12] << 24 | buf[13] << 16 | + buf[14] << 8 | buf[15]; + } + rc_keydown(d->rc_dev, state->rc_keycode, 0); + } else { + deb_rc("%s: no key press\n", __func__); + /* Invalidate last keypress */ + /* Not really needed, but helps with debug */ + state->rc_last[2] = state->rc_last[3]; + } + + state->rc_repeat = buf[6]; + +error: + if (ret) + err("%s: failed:%d", __func__, ret); + + return ret; +} + +static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) +{ + struct af9015_state *state = d_to_priv(d); + u16 vid = le16_to_cpu(d->udev->descriptor.idVendor); + + if (state->ir_mode == AF9015_IR_MODE_DISABLED) + return 0; + + /* try to load remote based module param */ + rc->map_name = af9015_rc_setup_match(dvb_usb_af9015_remote, + af9015_rc_setup_modparam); + + /* try to load remote based eeprom hash */ + if (!rc->map_name) + rc->map_name = af9015_rc_setup_match(state->eeprom_sum, + af9015_rc_setup_hashes); + + /* try to load remote based USB iManufacturer string */ + if (!rc->map_name && vid == USB_VID_AFATECH) { + /* Check USB manufacturer and product strings and try + to determine correct remote in case of chip vendor + reference IDs are used. + DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */ + char manufacturer[10]; + memset(manufacturer, 0, sizeof(manufacturer)); + usb_string(d->udev, d->udev->descriptor.iManufacturer, + manufacturer, sizeof(manufacturer)); + if (!strcmp("MSI", manufacturer)) { + /* iManufacturer 1 MSI + iProduct 2 MSI K-VOX */ + rc->map_name = af9015_rc_setup_match( + AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, + af9015_rc_setup_modparam); + } + } + + /* load empty to enable rc */ + if (!rc->map_name) + rc->map_name = RC_MAP_EMPTY; + + rc->allowed_protos = RC_TYPE_NEC; + rc->query = af9015_rc_query; + rc->interval = 500; + + return 0; +} + +/* interface 0 is used by DVB-T receiver and + interface 1 is for remote controller (HID) */ +static struct dvb_usb_device_properties af9015_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct af9015_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .identify_state = af9015_identify_state, + .firmware = "dvb-usb-af9015.fw", + .download_firmware = af9015_download_firmware, + + .i2c_algo = &af9015_i2c_algo, + .read_config = af9015_read_config, + .frontend_attach = af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .init = af9015_init, + .get_rc_config = af9015_get_rc_config, + .get_stream_config = af9015_get_stream_config, + + .get_adapter_count = af9015_get_adapter_count, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = af9015_pid_filter, + .pid_filter_ctrl = af9015_pid_filter_ctrl, + + .stream = DVB_USB_STREAM_BULK(0x84, 8, TS_USB20_FRAME_SIZE), + }, { + .stream = DVB_USB_STREAM_BULK(0x85, 8, TS_USB20_FRAME_SIZE), + }, + }, +}; + +static const struct usb_device_id af9015_id_table[] = { + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015, + &af9015_props, "Afatech AF9015 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016, + &af9015_props, "Afatech AF9015 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD, + &af9015_props, "Leadtek WinFast DTV Dongle Gold", RC_MAP_LEADTEK_Y04G0051) }, + { DVB_USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E, + &af9015_props, "Pinnacle PCTV 71e", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U, + &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN, + &af9015_props, "DigitalNow TinyTwin", RC_MAP_AZUREWAVE_AD_TU700) }, + { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700, + &af9015_props, "TwinHan AzureWave AD-TU700(704J)", RC_MAP_AZUREWAVE_AD_TU700) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2, + &af9015_props, "TerraTec Cinergy T USB XE", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T, + &af9015_props, "KWorld PlusTV Dual DVB-T PCI (DVB-T PC160-2T)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X, + &af9015_props, "AVerMedia AVerTV DVB-T Volar X", RC_MAP_AVERMEDIA_M135A) }, + { DVB_USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380, + &af9015_props, "Xtensions XD-380", NULL) }, + { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO, + &af9015_props, "MSI DIGIVOX Duo", RC_MAP_MSI_DIGIVOX_III) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2, + &af9015_props, "Fujitsu-Siemens Slim Mobile USB DVB-T", NULL) }, + { DVB_USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2, + &af9015_props, "Telestar Starstick 2", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309, + &af9015_props, "AVerMedia A309", NULL) }, + { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III, + &af9015_props, "MSI Digi VOX mini III", RC_MAP_MSI_DIGIVOX_III) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U, + &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2, + &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3, + &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT, + &af9015_props, "TrekStor DVB-T USB Stick", RC_MAP_TREKSTOR) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850, + &af9015_props, "AverMedia AVerTV Volar Black HD (A850)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805, + &af9015_props, "AverMedia AVerTV Volar GPS 805 (A805)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU, + &af9015_props, "Conceptronic USB2.0 DVB-T CTVDIGRCU V3.0", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810, + &af9015_props, "KWorld Digial MC-810", NULL) }, + { DVB_USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03, + &af9015_props, "Genius TVGo DVB-T03", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2, + &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T, + &af9015_props, "KWorld PlusTV DVB-T PCI Pro Card (DVB-T PC160-T)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20, + &af9015_props, "Sveon STV20 Tuner USB DVB-T HDTV", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2, + &af9015_props, "DigitalNow TinyTwin v2", RC_MAP_DIGITALNOW_TINYTWIN) }, + { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS, + &af9015_props, "Leadtek WinFast DTV2000DS", RC_MAP_LEADTEK_Y04G0051) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T, + &af9015_props, "KWorld USB DVB-T Stick Mobile (UB383-T)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4, + &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M, + &af9015_props, "AverMedia AVerTV Volar M (A815Mac)", NULL) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC, + &af9015_props, "TerraTec Cinergy T Stick RC", RC_MAP_TERRATEC_SLIM_2) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC, + &af9015_props, "TerraTec Cinergy T Stick Dual RC", RC_MAP_TERRATEC_SLIM) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T, + &af9015_props, "AverMedia AVerTV Red HD+ (A850T)", NULL) }, + { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3, + &af9015_props, "DigitalNow TinyTwin v3", RC_MAP_DIGITALNOW_TINYTWIN) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22, + &af9015_props, "Sveon STV22 Dual USB DVB-T Tuner HDTV", RC_MAP_MSI_DIGIVOX_III) }, + { } +}; +MODULE_DEVICE_TABLE(usb, af9015_id_table); + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver af9015_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = af9015_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(af9015_usb_driver); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Afatech AF9015 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/af9015.h b/drivers/media/dvb/dvb-usb-v2/af9015.h new file mode 100644 index 000000000000..b41ee73b26dc --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/af9015.h @@ -0,0 +1,169 @@ +/* + * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari + * + * Thanks to Afatech who kindly provided information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef AF9015_H +#define AF9015_H + +#include +#include "dvb_usb.h" +#include "af9013.h" +#include "dvb-pll.h" +#include "mt2060.h" +#include "qt1010.h" +#include "tda18271.h" +#include "mxl5005s.h" +#include "mc44s803.h" +#include "tda18218.h" +#include "mxl5007t.h" + +#define DVB_USB_LOG_PREFIX "af9015" + +#ifdef CONFIG_DVB_USB_DEBUG +#define dprintk(var, level, args...) \ + do { if ((var & level)) printk(args); } while (0) +#define DVB_USB_DEBUG_STATUS +#else +#define dprintk(args...) +#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" +#endif + +#define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args) +#define deb_rc(args...) dprintk(dvb_usb_af9015_debug, 0x02, args) + +#undef err +#define err(format, arg...) \ + printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#undef warn +#define warn(format, arg...) \ + printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) + +/* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0. + We use smaller - about 1/4 from the original, 5 and 87. */ +#define TS_PACKET_SIZE 188 + +#define TS_USB20_PACKET_COUNT 87 +#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT) + +#define TS_USB11_PACKET_COUNT 5 +#define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT) + +#define TS_USB20_MAX_PACKET_SIZE 512 +#define TS_USB11_MAX_PACKET_SIZE 64 + +#define AF9015_I2C_EEPROM 0xa0 +#define AF9015_I2C_DEMOD 0x38 +#define AF9015_USB_TIMEOUT 2000 + +/* EEPROM locations */ +#define AF9015_EEPROM_IR_MODE 0x18 +#define AF9015_EEPROM_IR_REMOTE_TYPE 0x34 +#define AF9015_EEPROM_TS_MODE 0x31 +#define AF9015_EEPROM_DEMOD2_I2C 0x32 + +#define AF9015_EEPROM_SAW_BW1 0x35 +#define AF9015_EEPROM_XTAL_TYPE1 0x36 +#define AF9015_EEPROM_SPEC_INV1 0x37 +#define AF9015_EEPROM_IF1L 0x38 +#define AF9015_EEPROM_IF1H 0x39 +#define AF9015_EEPROM_MT2060_IF1L 0x3a +#define AF9015_EEPROM_MT2060_IF1H 0x3b +#define AF9015_EEPROM_TUNER_ID1 0x3c + +#define AF9015_EEPROM_SAW_BW2 0x45 +#define AF9015_EEPROM_XTAL_TYPE2 0x46 +#define AF9015_EEPROM_SPEC_INV2 0x47 +#define AF9015_EEPROM_IF2L 0x48 +#define AF9015_EEPROM_IF2H 0x49 +#define AF9015_EEPROM_MT2060_IF2L 0x4a +#define AF9015_EEPROM_MT2060_IF2H 0x4b +#define AF9015_EEPROM_TUNER_ID2 0x4c + +#define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1) + +struct req_t { + u8 cmd; /* [0] */ + /* seq */ /* [1] */ + u8 i2c_addr; /* [2] */ + u16 addr; /* [3|4] */ + u8 mbox; /* [5] */ + u8 addr_len; /* [6] */ + u8 data_len; /* [7] */ + u8 *data; +}; + +enum af9015_cmd { + GET_CONFIG = 0x10, + DOWNLOAD_FIRMWARE = 0x11, + BOOT = 0x13, + READ_MEMORY = 0x20, + WRITE_MEMORY = 0x21, + READ_WRITE_I2C = 0x22, + COPY_FIRMWARE = 0x23, + RECONNECT_USB = 0x5a, + WRITE_VIRTUAL_MEMORY = 0x26, + GET_IR_CODE = 0x27, + READ_I2C, + WRITE_I2C, +}; + +enum af9015_ir_mode { + AF9015_IR_MODE_DISABLED = 0, + AF9015_IR_MODE_HID, + AF9015_IR_MODE_RLC, + AF9015_IR_MODE_RC6, + AF9015_IR_MODE_POLLING, /* just guess */ +}; + +struct af9015_state { + u8 ir_mode; + u8 rc_repeat; + u32 rc_keycode; + u8 rc_last[4]; + u8 dual_mode; + u8 seq; /* packet sequence number */ + u16 mt2060_if1[2]; + u16 firmware_size; + u16 firmware_checksum; + u32 eeprom_sum; + struct af9013_config af9013_config[2]; + + /* for demod callback override */ + int (*set_frontend[2]) (struct dvb_frontend *fe); + int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status); + int (*init[2]) (struct dvb_frontend *fe); + int (*sleep[2]) (struct dvb_frontend *fe); + int (*tuner_init[2]) (struct dvb_frontend *fe); + int (*tuner_sleep[2]) (struct dvb_frontend *fe); + struct mutex fe_mutex; +}; + +enum af9015_remote { + AF9015_REMOTE_NONE = 0, +/* 1 */ AF9015_REMOTE_A_LINK_DTU_M, + AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, + AF9015_REMOTE_MYGICTV_U718, + AF9015_REMOTE_DIGITTRADE_DVB_T, +/* 5 */ AF9015_REMOTE_AVERMEDIA_KS, +}; + +#endif diff --git a/drivers/media/dvb/dvb-usb-v2/af9035.c b/drivers/media/dvb/dvb-usb-v2/af9035.c new file mode 100644 index 000000000000..79197f46aa95 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/af9035.c @@ -0,0 +1,1087 @@ +/* + * Afatech AF9035 DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari + * Copyright (C) 2012 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "af9035.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static u16 af9035_checksum(const u8 *buf, size_t len) +{ + size_t i; + u16 checksum = 0; + + for (i = 1; i < len; i++) { + if (i % 2) + checksum += buf[i] << 8; + else + checksum += buf[i]; + } + checksum = ~checksum; + + return checksum; +} + +static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) +{ +#define BUF_LEN 64 +#define REQ_HDR_LEN 4 /* send header size */ +#define ACK_HDR_LEN 3 /* rece header size */ +#define CHECKSUM_LEN 2 +#define USB_TIMEOUT 2000 + struct state *state = d_to_priv(d); + int ret, wlen, rlen; + u8 buf[BUF_LEN]; + u16 checksum, tmp_checksum; + + /* buffer overflow check */ + if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) || + req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) { + pr_debug("%s: too much data wlen=%d rlen=%d\n", __func__, + req->wlen, req->rlen); + return -EINVAL; + } + + buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1; + buf[1] = req->mbox; + buf[2] = req->cmd; + buf[3] = state->seq++; + memcpy(&buf[REQ_HDR_LEN], req->wbuf, req->wlen); + + wlen = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN; + rlen = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN; + + /* calc and add checksum */ + checksum = af9035_checksum(buf, buf[0] - 1); + buf[buf[0] - 1] = (checksum >> 8); + buf[buf[0] - 0] = (checksum & 0xff); + + /* no ack for these packets */ + if (req->cmd == CMD_FW_DL) + rlen = 0; + + ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen); + if (ret) + goto err; + + /* no ack for those packets */ + if (req->cmd == CMD_FW_DL) + goto exit; + + /* verify checksum */ + checksum = af9035_checksum(buf, rlen - 2); + tmp_checksum = (buf[rlen - 2] << 8) | buf[rlen - 1]; + if (tmp_checksum != checksum) { + pr_err("%s: command=%02x checksum mismatch (%04x != %04x)\n", + KBUILD_MODNAME, req->cmd, tmp_checksum, + checksum); + ret = -EIO; + goto err; + } + + /* check status */ + if (buf[2]) { + pr_debug("%s: command=%02x failed fw error=%d\n", __func__, + req->cmd, buf[2]); + ret = -EIO; + goto err; + } + + /* read request, copy returned data to return buf */ + if (req->rlen) + memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen); + +exit: + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +/* write multiple registers */ +static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) +{ + u8 wbuf[6 + len]; + u8 mbox = (reg >> 16) & 0xff; + struct usb_req req = { CMD_MEM_WR, mbox, sizeof(wbuf), wbuf, 0, NULL }; + + wbuf[0] = len; + wbuf[1] = 2; + wbuf[2] = 0; + wbuf[3] = 0; + wbuf[4] = (reg >> 8) & 0xff; + wbuf[5] = (reg >> 0) & 0xff; + memcpy(&wbuf[6], val, len); + + return af9035_ctrl_msg(d, &req); +} + +/* read multiple registers */ +static int af9035_rd_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) +{ + u8 wbuf[] = { len, 2, 0, 0, (reg >> 8) & 0xff, reg & 0xff }; + u8 mbox = (reg >> 16) & 0xff; + struct usb_req req = { CMD_MEM_RD, mbox, sizeof(wbuf), wbuf, len, val }; + + return af9035_ctrl_msg(d, &req); +} + +/* write single register */ +static int af9035_wr_reg(struct dvb_usb_device *d, u32 reg, u8 val) +{ + return af9035_wr_regs(d, reg, &val, 1); +} + +/* read single register */ +static int af9035_rd_reg(struct dvb_usb_device *d, u32 reg, u8 *val) +{ + return af9035_rd_regs(d, reg, val, 1); +} + +/* write single register with mask */ +static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val, + u8 mask) +{ + int ret; + u8 tmp; + + /* no need for read if whole reg is written */ + if (mask != 0xff) { + ret = af9035_rd_regs(d, reg, &tmp, 1); + if (ret) + return ret; + + val &= mask; + tmp &= ~mask; + val |= tmp; + } + + return af9035_wr_regs(d, reg, &val, 1); +} + +static int af9035_i2c_master_xfer(struct i2c_adapter *adap, + struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct state *state = d_to_priv(d); + int ret; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + /* + * I2C sub header is 5 bytes long. Meaning of those bytes are: + * 0: data len + * 1: I2C addr << 1 + * 2: reg addr len + * byte 3 and 4 can be used as reg addr + * 3: reg addr MSB + * used when reg addr len is set to 2 + * 4: reg addr LSB + * used when reg addr len is set to 1 or 2 + * + * For the simplify we do not use register addr at all. + * NOTE: As a firmware knows tuner type there is very small possibility + * there could be some tuner I2C hacks done by firmware and this may + * lead problems if firmware expects those bytes are used. + */ + if (num == 2 && !(msg[0].flags & I2C_M_RD) && + (msg[1].flags & I2C_M_RD)) { + if (msg[0].len > 40 || msg[1].len > 40) { + /* TODO: correct limits > 40 */ + ret = -EOPNOTSUPP; + } else if (msg[0].addr == state->af9033_config[0].i2c_addr) { + /* integrated demod */ + u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | + msg[0].buf[2]; + ret = af9035_rd_regs(d, reg, &msg[1].buf[0], + msg[1].len); + } else { + /* I2C */ + u8 buf[5 + msg[0].len]; + struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf), + buf, msg[1].len, msg[1].buf }; + buf[0] = msg[1].len; + buf[1] = msg[0].addr << 1; + buf[2] = 0x00; /* reg addr len */ + buf[3] = 0x00; /* reg addr MSB */ + buf[4] = 0x00; /* reg addr LSB */ + memcpy(&buf[5], msg[0].buf, msg[0].len); + ret = af9035_ctrl_msg(d, &req); + } + } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) { + if (msg[0].len > 40) { + /* TODO: correct limits > 40 */ + ret = -EOPNOTSUPP; + } else if (msg[0].addr == state->af9033_config[0].i2c_addr) { + /* integrated demod */ + u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | + msg[0].buf[2]; + ret = af9035_wr_regs(d, reg, &msg[0].buf[3], + msg[0].len - 3); + } else { + /* I2C */ + u8 buf[5 + msg[0].len]; + struct usb_req req = { CMD_I2C_WR, 0, sizeof(buf), buf, + 0, NULL }; + buf[0] = msg[0].len; + buf[1] = msg[0].addr << 1; + buf[2] = 0x00; /* reg addr len */ + buf[3] = 0x00; /* reg addr MSB */ + buf[4] = 0x00; /* reg addr LSB */ + memcpy(&buf[5], msg[0].buf, msg[0].len); + ret = af9035_ctrl_msg(d, &req); + } + } else { + /* + * We support only two kind of I2C transactions: + * 1) 1 x read + 1 x write + * 2) 1 x write + */ + ret = -EOPNOTSUPP; + } + + mutex_unlock(&d->i2c_mutex); + + if (ret < 0) + return ret; + else + return num; +} + +static u32 af9035_i2c_functionality(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm af9035_i2c_algo = { + .master_xfer = af9035_i2c_master_xfer, + .functionality = af9035_i2c_functionality, +}; + +static int af9035_identify_state(struct dvb_usb_device *d, const char **name) +{ + int ret; + u8 wbuf[1] = { 1 }; + u8 rbuf[4]; + struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf, + sizeof(rbuf), rbuf }; + + ret = af9035_ctrl_msg(d, &req); + if (ret < 0) + goto err; + + pr_debug("%s: reply=%02x %02x %02x %02x\n", __func__, + rbuf[0], rbuf[1], rbuf[2], rbuf[3]); + if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3]) + ret = WARM; + else + ret = COLD; + + return ret; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_download_firmware(struct dvb_usb_device *d, + const struct firmware *fw) +{ + int ret, i, j, len; + u8 wbuf[1]; + u8 rbuf[4]; + struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; + struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL }; + struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ; + u8 hdr_core; + u16 hdr_addr, hdr_data_len, hdr_checksum; + #define MAX_DATA 58 + #define HDR_SIZE 7 + + /* + * Thanks to Daniel Glöckner about that info! + * + * byte 0: MCS 51 core + * There are two inside the AF9035 (1=Link and 2=OFDM) with separate + * address spaces + * byte 1-2: Big endian destination address + * byte 3-4: Big endian number of data bytes following the header + * byte 5-6: Big endian header checksum, apparently ignored by the chip + * Calculated as ~(h[0]*256+h[1]+h[2]*256+h[3]+h[4]*256) + */ + + for (i = fw->size; i > HDR_SIZE;) { + hdr_core = fw->data[fw->size - i + 0]; + hdr_addr = fw->data[fw->size - i + 1] << 8; + hdr_addr |= fw->data[fw->size - i + 2] << 0; + hdr_data_len = fw->data[fw->size - i + 3] << 8; + hdr_data_len |= fw->data[fw->size - i + 4] << 0; + hdr_checksum = fw->data[fw->size - i + 5] << 8; + hdr_checksum |= fw->data[fw->size - i + 6] << 0; + + pr_debug("%s: core=%d addr=%04x data_len=%d checksum=%04x\n", + __func__, hdr_core, hdr_addr, hdr_data_len, + hdr_checksum); + + if (((hdr_core != 1) && (hdr_core != 2)) || + (hdr_data_len > i)) { + pr_debug("%s: bad firmware\n", __func__); + break; + } + + /* download begin packet */ + req.cmd = CMD_FW_DL_BEGIN; + ret = af9035_ctrl_msg(d, &req); + if (ret < 0) + goto err; + + /* download firmware packet(s) */ + for (j = HDR_SIZE + hdr_data_len; j > 0; j -= MAX_DATA) { + len = j; + if (len > MAX_DATA) + len = MAX_DATA; + req_fw_dl.wlen = len; + req_fw_dl.wbuf = (u8 *) &fw->data[fw->size - i + + HDR_SIZE + hdr_data_len - j]; + ret = af9035_ctrl_msg(d, &req_fw_dl); + if (ret < 0) + goto err; + } + + /* download end packet */ + req.cmd = CMD_FW_DL_END; + ret = af9035_ctrl_msg(d, &req); + if (ret < 0) + goto err; + + i -= hdr_data_len + HDR_SIZE; + + pr_debug("%s: data uploaded=%zu\n", __func__, fw->size - i); + } + + /* firmware loaded, request boot */ + req.cmd = CMD_FW_BOOT; + ret = af9035_ctrl_msg(d, &req); + if (ret < 0) + goto err; + + /* ensure firmware starts */ + wbuf[0] = 1; + ret = af9035_ctrl_msg(d, &req_fw_ver); + if (ret < 0) + goto err; + + if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { + pr_err("%s: firmware did not run\n", KBUILD_MODNAME); + ret = -ENODEV; + goto err; + } + + pr_info("%s: firmware version=%d.%d.%d.%d", KBUILD_MODNAME, + rbuf[0], rbuf[1], rbuf[2], rbuf[3]); + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_download_firmware_it9135(struct dvb_usb_device *d, + const struct firmware *fw) +{ + int ret, i, i_prev; + u8 wbuf[1]; + u8 rbuf[4]; + struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; + struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL }; + struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ; + #define HDR_SIZE 7 + + /* + * There seems to be following firmware header. Meaning of bytes 0-3 + * is unknown. + * + * 0: 3 + * 1: 0, 1 + * 2: 0 + * 3: 1, 2, 3 + * 4: addr MSB + * 5: addr LSB + * 6: count of data bytes ? + */ + + for (i = HDR_SIZE, i_prev = 0; i <= fw->size; i++) { + if (i == fw->size || + (fw->data[i + 0] == 0x03 && + (fw->data[i + 1] == 0x00 || + fw->data[i + 1] == 0x01) && + fw->data[i + 2] == 0x00)) { + req_fw_dl.wlen = i - i_prev; + req_fw_dl.wbuf = (u8 *) &fw->data[i_prev]; + i_prev = i; + ret = af9035_ctrl_msg(d, &req_fw_dl); + if (ret < 0) + goto err; + + pr_debug("%s: data uploaded=%d\n", __func__, i); + } + } + + /* firmware loaded, request boot */ + req.cmd = CMD_FW_BOOT; + ret = af9035_ctrl_msg(d, &req); + if (ret < 0) + goto err; + + /* ensure firmware starts */ + wbuf[0] = 1; + ret = af9035_ctrl_msg(d, &req_fw_ver); + if (ret < 0) + goto err; + + if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { + pr_err("%s: firmware did not run\n", KBUILD_MODNAME); + ret = -ENODEV; + goto err; + } + + pr_info("%s: firmware version=%d.%d.%d.%d", KBUILD_MODNAME, + rbuf[0], rbuf[1], rbuf[2], rbuf[3]); + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_read_config(struct dvb_usb_device *d) +{ + struct state *state = d_to_priv(d); + int ret, i, eeprom_shift = 0; + u8 tmp; + u16 tmp16; + + /* check if there is dual tuners */ + ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp); + if (ret < 0) + goto err; + + state->dual_mode = tmp; + pr_debug("%s: dual mode=%d\n", __func__, state->dual_mode); + + for (i = 0; i < state->dual_mode + 1; i++) { + /* tuner */ + ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp); + if (ret < 0) + goto err; + + state->af9033_config[i].tuner = tmp; + pr_debug("%s: [%d]tuner=%02x\n", __func__, i, tmp); + + switch (tmp) { + case AF9033_TUNER_TUA9001: + case AF9033_TUNER_FC0011: + case AF9033_TUNER_MXL5007T: + case AF9033_TUNER_TDA18218: + state->af9033_config[i].spec_inv = 1; + break; + default: + pr_info("%s: tuner ID=%02x not supported, please " \ + "report!", KBUILD_MODNAME, tmp); + }; + + /* tuner IF frequency */ + ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp); + if (ret < 0) + goto err; + + tmp16 = tmp; + + ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_H + eeprom_shift, &tmp); + if (ret < 0) + goto err; + + tmp16 |= tmp << 8; + + pr_debug("%s: [%d]IF=%d\n", __func__, i, tmp16); + + eeprom_shift = 0x10; /* shift for the 2nd tuner params */ + } + + /* get demod clock */ + ret = af9035_rd_reg(d, 0x00d800, &tmp); + if (ret < 0) + goto err; + + tmp = (tmp >> 0) & 0x0f; + + for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++) + state->af9033_config[i].clock = clock_lut[tmp]; + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_read_config_it9135(struct dvb_usb_device *d) +{ + struct state *state = d_to_priv(d); + int ret, i; + u8 tmp; + + state->dual_mode = false; + + /* get demod clock */ + ret = af9035_rd_reg(d, 0x00d800, &tmp); + if (ret < 0) + goto err; + + tmp = (tmp >> 0) & 0x0f; + + for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++) + state->af9033_config[i].clock = clock_lut_it9135[tmp]; + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_fc0011_tuner_callback(struct dvb_usb_device *d, + int cmd, int arg) +{ + int ret; + + switch (cmd) { + case FC0011_FE_CALLBACK_POWER: + /* Tuner enable */ + ret = af9035_wr_reg_mask(d, 0xd8eb, 1, 1); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8ec, 1, 1); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8ed, 1, 1); + if (ret < 0) + goto err; + + /* LED */ + ret = af9035_wr_reg_mask(d, 0xd8d0, 1, 1); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8d1, 1, 1); + if (ret < 0) + goto err; + + usleep_range(10000, 50000); + break; + case FC0011_FE_CALLBACK_RESET: + ret = af9035_wr_reg(d, 0xd8e9, 1); + if (ret < 0) + goto err; + + ret = af9035_wr_reg(d, 0xd8e8, 1); + if (ret < 0) + goto err; + + ret = af9035_wr_reg(d, 0xd8e7, 1); + if (ret < 0) + goto err; + + usleep_range(10000, 20000); + + ret = af9035_wr_reg(d, 0xd8e7, 0); + if (ret < 0) + goto err; + + usleep_range(10000, 20000); + break; + default: + ret = -EINVAL; + goto err; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_tuner_callback(struct dvb_usb_device *d, int cmd, int arg) +{ + struct state *state = d_to_priv(d); + + switch (state->af9033_config[0].tuner) { + case AF9033_TUNER_FC0011: + return af9035_fc0011_tuner_callback(d, cmd, arg); + default: + break; + } + + return -ENODEV; +} + +static int af9035_frontend_callback(void *adapter_priv, int component, + int cmd, int arg) +{ + struct i2c_adapter *adap = adapter_priv; + struct dvb_usb_device *d = i2c_get_adapdata(adap); + + switch (component) { + case DVB_FRONTEND_COMPONENT_TUNER: + return af9035_tuner_callback(d, cmd, arg); + default: + break; + } + + return -EINVAL; +} + +static int af9035_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + int ret; + + if (!state->af9033_config[adap->id].tuner) { + /* unsupported tuner */ + ret = -ENODEV; + goto err; + } + + if (adap->id == 0) { + state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB; + state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL; + + ret = af9035_wr_reg(d, 0x00417f, + state->af9033_config[1].i2c_addr); + if (ret < 0) + goto err; + + ret = af9035_wr_reg(d, 0x00d81a, + state->dual_mode); + if (ret < 0) + goto err; + } + + /* attach demodulator */ + adap->fe[0] = dvb_attach(af9033_attach, + &state->af9033_config[adap->id], &d->i2c_adap); + if (adap->fe[0] == NULL) { + ret = -ENODEV; + goto err; + } + + /* disable I2C-gate */ + adap->fe[0]->ops.i2c_gate_ctrl = NULL; + adap->fe[0]->callback = af9035_frontend_callback; + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static struct tua9001_config af9035_tua9001_config = { + .i2c_addr = 0x60, +}; + +static const struct fc0011_config af9035_fc0011_config = { + .i2c_address = 0x60, +}; + +static struct mxl5007t_config af9035_mxl5007t_config = { + .xtal_freq_hz = MxL_XTAL_24_MHZ, + .if_freq_hz = MxL_IF_4_57_MHZ, + .invert_if = 0, + .loop_thru_enable = 0, + .clk_out_enable = 0, + .clk_out_amp = MxL_CLKOUT_AMP_0_94V, +}; + +static struct tda18218_config af9035_tda18218_config = { + .i2c_address = 0x60, + .i2c_wr_max = 21, +}; + +static int af9035_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + int ret; + struct dvb_frontend *fe; + + switch (state->af9033_config[adap->id].tuner) { + case AF9033_TUNER_TUA9001: + /* AF9035 gpiot3 = TUA9001 RESETN + AF9035 gpiot2 = TUA9001 RXEN */ + + /* configure gpiot2 and gpiot2 as output */ + ret = af9035_wr_reg_mask(d, 0x00d8ec, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0x00d8ed, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0x00d8e8, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0x00d8e9, 0x01, 0x01); + if (ret < 0) + goto err; + + /* reset tuner */ + ret = af9035_wr_reg_mask(d, 0x00d8e7, 0x00, 0x01); + if (ret < 0) + goto err; + + usleep_range(2000, 20000); + + ret = af9035_wr_reg_mask(d, 0x00d8e7, 0x01, 0x01); + if (ret < 0) + goto err; + + /* activate tuner RX */ + /* TODO: use callback for TUA9001 RXEN */ + ret = af9035_wr_reg_mask(d, 0x00d8eb, 0x01, 0x01); + if (ret < 0) + goto err; + + /* attach tuner */ + fe = dvb_attach(tua9001_attach, adap->fe[0], + &d->i2c_adap, &af9035_tua9001_config); + break; + case AF9033_TUNER_FC0011: + fe = dvb_attach(fc0011_attach, adap->fe[0], + &d->i2c_adap, &af9035_fc0011_config); + break; + case AF9033_TUNER_MXL5007T: + ret = af9035_wr_reg(d, 0x00d8e0, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(d, 0x00d8e1, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(d, 0x00d8df, 0); + if (ret < 0) + goto err; + + msleep(30); + + ret = af9035_wr_reg(d, 0x00d8df, 1); + if (ret < 0) + goto err; + + msleep(300); + + ret = af9035_wr_reg(d, 0x00d8c0, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(d, 0x00d8c1, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(d, 0x00d8bf, 0); + if (ret < 0) + goto err; + ret = af9035_wr_reg(d, 0x00d8b4, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(d, 0x00d8b5, 1); + if (ret < 0) + goto err; + ret = af9035_wr_reg(d, 0x00d8b3, 1); + if (ret < 0) + goto err; + + /* attach tuner */ + fe = dvb_attach(mxl5007t_attach, adap->fe[0], + &d->i2c_adap, 0x60, &af9035_mxl5007t_config); + break; + case AF9033_TUNER_TDA18218: + /* attach tuner */ + fe = dvb_attach(tda18218_attach, adap->fe[0], + &d->i2c_adap, &af9035_tda18218_config); + break; + default: + fe = NULL; + } + + if (fe == NULL) { + ret = -ENODEV; + goto err; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_init(struct dvb_usb_device *d) +{ + struct state *state = d_to_priv(d); + int ret, i; + u16 frame_size = 87 * 188 / 4; + u8 packet_size = 512 / 4; + struct reg_val_mask tab[] = { + { 0x80f99d, 0x01, 0x01 }, + { 0x80f9a4, 0x01, 0x01 }, + { 0x00dd11, 0x00, 0x20 }, + { 0x00dd11, 0x00, 0x40 }, + { 0x00dd13, 0x00, 0x20 }, + { 0x00dd13, 0x00, 0x40 }, + { 0x00dd11, 0x20, 0x20 }, + { 0x00dd88, (frame_size >> 0) & 0xff, 0xff}, + { 0x00dd89, (frame_size >> 8) & 0xff, 0xff}, + { 0x00dd0c, packet_size, 0xff}, + { 0x00dd11, state->dual_mode << 6, 0x40 }, + { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff}, + { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff}, + { 0x00dd0d, packet_size, 0xff }, + { 0x80f9a3, 0x00, 0x01 }, + { 0x80f9cd, 0x00, 0x01 }, + { 0x80f99d, 0x00, 0x01 }, + { 0x80f9a4, 0x00, 0x01 }, + }; + + pr_debug("%s: USB speed=%d frame_size=%04x packet_size=%02x\n", + __func__, d->udev->speed, frame_size, packet_size); + + /* init endpoints */ + for (i = 0; i < ARRAY_SIZE(tab); i++) { + ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val, + tab[i].mask); + if (ret < 0) + goto err; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_rc_query(struct dvb_usb_device *d) +{ + unsigned int key; + unsigned char b[4]; + int ret; + struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b }; + + ret = af9035_ctrl_msg(d, &req); + if (ret < 0) + goto err; + + if ((b[2] + b[3]) == 0xff) { + if ((b[0] + b[1]) == 0xff) { + /* NEC */ + key = b[0] << 8 | b[2]; + } else { + /* ext. NEC */ + key = b[0] << 16 | b[1] << 8 | b[2]; + } + } else { + key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]; + } + + rc_keydown(d->rc_dev, key, 0); + +err: + /* ignore errors */ + return 0; +} + +static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) +{ + int ret; + u8 tmp; + + ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp); + if (ret < 0) + goto err; + + pr_debug("%s: ir_mode=%02x\n", __func__, tmp); + + /* don't activate rc if in HID mode or if not available */ + if (tmp == 5) { + ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp); + if (ret < 0) + goto err; + + pr_debug("%s: ir_type=%02x\n", __func__, tmp); + + switch (tmp) { + case 0: /* NEC */ + default: + rc->allowed_protos = RC_TYPE_NEC; + break; + case 1: /* RC6 */ + rc->allowed_protos = RC_TYPE_RC6; + break; + } + + rc->query = af9035_rc_query; + rc->interval = 500; + + /* load empty to enable rc */ + if (!rc->map_name) + rc->map_name = RC_MAP_EMPTY; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +/* interface 0 is used by DVB-T receiver and + interface 1 is for remote controller (HID) */ +static const struct dvb_usb_device_properties af9035_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .identify_state = af9035_identify_state, + .firmware = "dvb-usb-af9035-02.fw", + .download_firmware = af9035_download_firmware, + + .i2c_algo = &af9035_i2c_algo, + .read_config = af9035_read_config, + .frontend_attach = af9035_frontend_attach, + .tuner_attach = af9035_tuner_attach, + .init = af9035_init, + .get_rc_config = af9035_get_rc_config, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), + }, { + .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), + }, + }, +}; + +static const struct dvb_usb_device_properties it9135_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .identify_state = af9035_identify_state, + .firmware = "dvb-usb-it9135-01.fw", + .download_firmware = af9035_download_firmware_it9135, + + .i2c_algo = &af9035_i2c_algo, + .read_config = af9035_read_config_it9135, + .frontend_attach = af9035_frontend_attach, + .tuner_attach = af9035_tuner_attach, + .init = af9035_init, + .get_rc_config = af9035_get_rc_config, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), + }, { + .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), + }, + }, +}; + +static const struct usb_device_id af9035_id_table[] = { + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035, + &af9035_props, "Afatech AF9035 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000, + &af9035_props, "Afatech AF9035 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1001, + &af9035_props, "Afatech AF9035 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1002, + &af9035_props, "Afatech AF9035 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1003, + &af9035_props, "Afatech AF9035 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK, + &af9035_props, "TerraTec Cinergy T Stick", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835, + &af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835, + &af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867, + &af9035_props, "AVerMedia HD Volar (A867)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867, + &af9035_props, "AVerMedia HD Volar (A867)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR, + &af9035_props, "AVerMedia Twinstar (A825)", NULL) }, + { } +}; +MODULE_DEVICE_TABLE(usb, af9035_id_table); + +static struct usb_driver af9035_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = af9035_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(af9035_usb_driver); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Afatech AF9035 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/af9035.h b/drivers/media/dvb/dvb-usb-v2/af9035.h new file mode 100644 index 000000000000..59ff69ede0f0 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/af9035.h @@ -0,0 +1,111 @@ +/* + * Afatech AF9035 DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari + * Copyright (C) 2012 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef AF9035_H +#define AF9035_H + +#include "dvb_usb.h" +#include "af9033.h" +#include "tua9001.h" +#include "fc0011.h" +#include "mxl5007t.h" +#include "tda18218.h" + +struct reg_val { + u32 reg; + u8 val; +}; + +struct reg_val_mask { + u32 reg; + u8 val; + u8 mask; +}; + +struct usb_req { + u8 cmd; + u8 mbox; + u8 wlen; + u8 *wbuf; + u8 rlen; + u8 *rbuf; +}; + +struct state { + u8 seq; /* packet sequence number */ + bool dual_mode; + + struct af9033_config af9033_config[2]; +}; + +u32 clock_lut[] = { + 20480000, /* FPGA */ + 16384000, /* 16.38 MHz */ + 20480000, /* 20.48 MHz */ + 36000000, /* 36.00 MHz */ + 30000000, /* 30.00 MHz */ + 26000000, /* 26.00 MHz */ + 28000000, /* 28.00 MHz */ + 32000000, /* 32.00 MHz */ + 34000000, /* 34.00 MHz */ + 24000000, /* 24.00 MHz */ + 22000000, /* 22.00 MHz */ + 12000000, /* 12.00 MHz */ +}; + +u32 clock_lut_it9135[] = { + 12000000, /* 12.00 MHz */ + 20480000, /* 20.48 MHz */ + 36000000, /* 36.00 MHz */ + 30000000, /* 30.00 MHz */ + 26000000, /* 26.00 MHz */ + 28000000, /* 28.00 MHz */ + 32000000, /* 32.00 MHz */ + 34000000, /* 34.00 MHz */ + 24000000, /* 24.00 MHz */ + 22000000, /* 22.00 MHz */ +}; + +/* EEPROM locations */ +#define EEPROM_IR_MODE 0x430d +#define EEPROM_DUAL_MODE 0x4326 +#define EEPROM_IR_TYPE 0x4329 +#define EEPROM_1_IFFREQ_L 0x432d +#define EEPROM_1_IFFREQ_H 0x432e +#define EEPROM_1_TUNER_ID 0x4331 +#define EEPROM_2_IFFREQ_L 0x433d +#define EEPROM_2_IFFREQ_H 0x433e +#define EEPROM_2_TUNER_ID 0x4341 + +/* USB commands */ +#define CMD_MEM_RD 0x00 +#define CMD_MEM_WR 0x01 +#define CMD_I2C_RD 0x02 +#define CMD_I2C_WR 0x03 +#define CMD_IR_GET 0x18 +#define CMD_FW_DL 0x21 +#define CMD_FW_QUERYINFO 0x22 +#define CMD_FW_BOOT 0x23 +#define CMD_FW_DL_BEGIN 0x24 +#define CMD_FW_DL_END 0x25 +#define CMD_FW_SCATTER_WR 0x29 + +#endif diff --git a/drivers/media/dvb/dvb-usb-v2/anysee.c b/drivers/media/dvb/dvb-usb-v2/anysee.c new file mode 100644 index 000000000000..fb3829a73d2d --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/anysee.c @@ -0,0 +1,1324 @@ +/* + * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * TODO: + * - add smart card reader support for Conditional Access (CA) + * + * Card reader in Anysee is nothing more than ISO 7816 card reader. + * There is no hardware CAM in any Anysee device sold. + * In my understanding it should be implemented by making own module + * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This + * module registers serial interface that can be used to communicate + * with any ISO 7816 smart card. + * + * Any help according to implement serial smart card reader support + * is highly welcome! + */ + +#include "anysee.h" +#include "dvb-pll.h" +#include "tda1002x.h" +#include "mt352.h" +#include "mt352_priv.h" +#include "zl10353.h" +#include "tda18212.h" +#include "cx24116.h" +#include "stv0900.h" +#include "stv6110.h" +#include "isl6423.h" +#include "cxd2820r.h" + +/* debug */ +static int dvb_usb_anysee_debug; +module_param_named(debug, dvb_usb_anysee_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static DEFINE_MUTEX(anysee_usb_mutex); + +static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, + u8 *rbuf, u8 rlen) +{ + struct anysee_state *state = d_to_priv(d); + int act_len, ret, i; + u8 buf[64]; + + memcpy(&buf[0], sbuf, slen); + buf[60] = state->seq++; + + mutex_lock(&anysee_usb_mutex); + + deb_xfer(">>> "); + debug_dump(buf, slen, deb_xfer); + + /* We need receive one message more after dvb_usb_generic_rw due + to weird transaction flow, which is 1 x send + 2 x receive. */ + ret = dvb_usbv2_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf)); + if (ret) + goto error_unlock; + + /* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32 + * (EPIPE, Broken pipe). Function supports currently msleep() as a + * parameter but I would not like to use it, since according to + * Documentation/timers/timers-howto.txt it should not be used such + * short, under < 20ms, sleeps. Repeating failed message would be + * better choice as not to add unwanted delays... + * Fixing that correctly is one of those or both; + * 1) use repeat if possible + * 2) add suitable delay + */ + + /* get answer, retry few times if error returned */ + for (i = 0; i < 3; i++) { + /* receive 2nd answer */ + ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, + d->props->generic_bulk_ctrl_endpoint), buf, sizeof(buf), + &act_len, 2000); + + if (ret) { + deb_info("%s: recv bulk message failed: %d", + __func__, ret); + } else { + deb_xfer("<<< "); + debug_dump(buf, rlen, deb_xfer); + + if (buf[63] != 0x4f) + deb_info("%s: cmd failed\n", __func__); + + break; + } + } + + if (ret) { + /* all retries failed, it is fatal */ + err("%s: recv bulk message failed: %d", __func__, ret); + goto error_unlock; + } + + /* read request, copy returned data to return buf */ + if (rbuf && rlen) + memcpy(rbuf, buf, rlen); + +error_unlock: + mutex_unlock(&anysee_usb_mutex); + + return ret; +} + +static int anysee_read_reg(struct dvb_usb_device *d, u16 reg, u8 *val) +{ + u8 buf[] = {CMD_REG_READ, reg >> 8, reg & 0xff, 0x01}; + int ret; + ret = anysee_ctrl_msg(d, buf, sizeof(buf), val, 1); + deb_info("%s: reg:%04x val:%02x\n", __func__, reg, *val); + return ret; +} + +static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val) +{ + u8 buf[] = {CMD_REG_WRITE, reg >> 8, reg & 0xff, 0x01, val}; + deb_info("%s: reg:%04x val:%02x\n", __func__, reg, val); + return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); +} + +/* write single register with mask */ +static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val, + u8 mask) +{ + int ret; + u8 tmp; + + /* no need for read if whole reg is written */ + if (mask != 0xff) { + ret = anysee_read_reg(d, reg, &tmp); + if (ret) + return ret; + + val &= mask; + tmp &= ~mask; + val |= tmp; + } + + return anysee_write_reg(d, reg, val); +} + +/* read single register with mask */ +static int anysee_rd_reg_mask(struct dvb_usb_device *d, u16 reg, u8 *val, + u8 mask) +{ + int ret, i; + u8 tmp; + + ret = anysee_read_reg(d, reg, &tmp); + if (ret) + return ret; + + tmp &= mask; + + /* find position of the first bit */ + for (i = 0; i < 8; i++) { + if ((mask >> i) & 0x01) + break; + } + *val = tmp >> i; + + return 0; +} + +static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id) +{ + u8 buf[] = {CMD_GET_HW_INFO}; + return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3); +} + +static int anysee_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00}; + deb_info("%s: onoff:%02x\n", __func__, onoff); + return anysee_ctrl_msg(fe_to_d(fe), buf, sizeof(buf), NULL, 0); +} + +static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval) +{ + u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x01, mode, interval}; + deb_info("%s: state:%02x interval:%02x\n", __func__, mode, interval); + return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); +} + +static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff) +{ + u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x02, onoff}; + deb_info("%s: onoff:%02x\n", __func__, onoff); + return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); +} + +/* I2C */ +static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret = 0, inc, i = 0; + u8 buf[52]; /* 4 + 48 (I2C WR USB command header + I2C WR max) */ + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + while (i < num) { + if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { + if (msg[i].len > 2 || msg[i+1].len > 60) { + ret = -EOPNOTSUPP; + break; + } + buf[0] = CMD_I2C_READ; + buf[1] = (msg[i].addr << 1) | 0x01; + buf[2] = msg[i].buf[0]; + buf[3] = msg[i].buf[1]; + buf[4] = msg[i].len-1; + buf[5] = msg[i+1].len; + ret = anysee_ctrl_msg(d, buf, 6, msg[i+1].buf, + msg[i+1].len); + inc = 2; + } else { + if (msg[i].len > 48) { + ret = -EOPNOTSUPP; + break; + } + buf[0] = CMD_I2C_WRITE; + buf[1] = (msg[i].addr << 1); + buf[2] = msg[i].len; + buf[3] = 0x01; + memcpy(&buf[4], msg[i].buf, msg[i].len); + ret = anysee_ctrl_msg(d, buf, 4 + msg[i].len, NULL, 0); + inc = 1; + } + if (ret) + break; + + i += inc; + } + + mutex_unlock(&d->i2c_mutex); + + return ret ? ret : i; +} + +static u32 anysee_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm anysee_i2c_algo = { + .master_xfer = anysee_master_xfer, + .functionality = anysee_i2c_func, +}; + +static int anysee_mt352_demod_init(struct dvb_frontend *fe) +{ + static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x28 }; + static u8 reset[] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg[] = { AGC_TARGET, 0x28, 0x20 }; + static u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 }; + static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(200); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + + return 0; +} + +/* Callbacks for DVB USB */ +static struct tda10023_config anysee_tda10023_config = { + .demod_address = (0x1a >> 1), + .invert = 0, + .xtal = 16000000, + .pll_m = 11, + .pll_p = 3, + .pll_n = 1, + .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C, + .deltaf = 0xfeeb, +}; + +static struct mt352_config anysee_mt352_config = { + .demod_address = (0x1e >> 1), + .demod_init = anysee_mt352_demod_init, +}; + +static struct zl10353_config anysee_zl10353_config = { + .demod_address = (0x1e >> 1), + .parallel_ts = 1, +}; + +static struct zl10353_config anysee_zl10353_tda18212_config2 = { + .demod_address = (0x1e >> 1), + .parallel_ts = 1, + .disable_i2c_gate_ctrl = 1, + .no_tuner = 1, + .if2 = 41500, +}; + +static struct zl10353_config anysee_zl10353_tda18212_config = { + .demod_address = (0x18 >> 1), + .parallel_ts = 1, + .disable_i2c_gate_ctrl = 1, + .no_tuner = 1, + .if2 = 41500, +}; + +static struct tda10023_config anysee_tda10023_tda18212_config = { + .demod_address = (0x1a >> 1), + .xtal = 16000000, + .pll_m = 12, + .pll_p = 3, + .pll_n = 1, + .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_B, + .deltaf = 0xba02, +}; + +static struct tda18212_config anysee_tda18212_config = { + .i2c_address = (0xc0 >> 1), + .if_dvbt_6 = 4150, + .if_dvbt_7 = 4150, + .if_dvbt_8 = 4150, + .if_dvbc = 5000, +}; + +static struct tda18212_config anysee_tda18212_config2 = { + .i2c_address = 0x60 /* (0xc0 >> 1) */, + .if_dvbt_6 = 3550, + .if_dvbt_7 = 3700, + .if_dvbt_8 = 4150, + .if_dvbt2_6 = 3250, + .if_dvbt2_7 = 4000, + .if_dvbt2_8 = 4000, + .if_dvbc = 5000, +}; + +static struct cx24116_config anysee_cx24116_config = { + .demod_address = (0xaa >> 1), + .mpg_clk_pos_pol = 0x00, + .i2c_wr_max = 48, +}; + +static struct stv0900_config anysee_stv0900_config = { + .demod_address = (0xd0 >> 1), + .demod_mode = 0, + .xtal = 8000000, + .clkmode = 3, + .diseqc_mode = 2, + .tun1_maddress = 0, + .tun1_adc = 1, /* 1 Vpp */ + .path1_mode = 3, +}; + +static struct stv6110_config anysee_stv6110_config = { + .i2c_address = (0xc0 >> 1), + .mclk = 16000000, + .clk_div = 1, +}; + +static struct isl6423_config anysee_isl6423_config = { + .current_max = SEC_CURRENT_800m, + .curlim = SEC_CURRENT_LIM_OFF, + .mod_extern = 1, + .addr = (0x10 >> 1), +}; + +static struct cxd2820r_config anysee_cxd2820r_config = { + .i2c_address = 0x6d, /* (0xda >> 1) */ + .ts_mode = 0x38, +}; + +/* + * New USB device strings: Mfr=1, Product=2, SerialNumber=0 + * Manufacturer: AMT.CO.KR + * + * E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=???????? + * PCB: ? + * parts: DNOS404ZH102A(MT352, DTT7579(?)) + * + * E30 VID=04b4 PID=861f HW=2 FW=2.1 "anysee-T(LP)" + * PCB: PCB 507T (rev1.61) + * parts: DNOS404ZH103A(ZL10353, DTT7579(?)) + * OEA=0a OEB=00 OEC=00 OED=ff OEE=00 + * IOA=45 IOB=ff IOC=00 IOD=ff IOE=00 + * + * E30 Plus VID=04b4 PID=861f HW=6 FW=1.0 "anysee" + * PCB: 507CD (rev1.1) + * parts: DNOS404ZH103A(ZL10353, DTT7579(?)), CST56I01 + * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe + * IOA=4f IOB=ff IOC=00 IOD=06 IOE=01 + * IOD[0] ZL10353 1=enabled + * IOA[7] TS 0=enabled + * tuner is not behind ZL10353 I2C-gate (no care if gate disabled or not) + * + * E30 C Plus VID=04b4 PID=861f HW=10 FW=1.0 "anysee-DC(LP)" + * PCB: 507DC (rev0.2) + * parts: TDA10023, DTOS403IH102B TM, CST56I01 + * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe + * IOA=4f IOB=ff IOC=00 IOD=26 IOE=01 + * IOD[0] TDA10023 1=enabled + * + * E30 S2 Plus VID=04b4 PID=861f HW=11 FW=0.1 "anysee-S2(LP)" + * PCB: 507SI (rev2.1) + * parts: BS2N10WCC01(CX24116, CX24118), ISL6423, TDA8024 + * OEA=80 OEB=00 OEC=ff OED=ff OEE=fe + * IOA=4d IOB=ff IOC=00 IOD=26 IOE=01 + * IOD[0] CX24116 1=enabled + * + * E30 C Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)" + * PCB: 507FA (rev0.4) + * parts: TDA10023, DTOS403IH102B TM, TDA8024 + * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff + * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0 + * IOD[5] TDA10023 1=enabled + * IOE[0] tuner 1=enabled + * + * E30 Combo Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)" + * PCB: 507FA (rev1.1) + * parts: ZL10353, TDA10023, DTOS403IH102B TM, TDA8024 + * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff + * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0 + * DVB-C: + * IOD[5] TDA10023 1=enabled + * IOE[0] tuner 1=enabled + * DVB-T: + * IOD[0] ZL10353 1=enabled + * IOE[0] tuner 0=enabled + * tuner is behind ZL10353 I2C-gate + * + * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)" + * PCB: 508TC (rev0.6) + * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212) + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[4] TDA18212 1=enabled + * DVB-C: + * IOD[6] ZL10353 0=disabled + * IOD[5] TDA10023 1=enabled + * IOE[0] IF 1=enabled + * DVB-T: + * IOD[5] TDA10023 0=disabled + * IOD[6] ZL10353 1=enabled + * IOE[0] IF 0=enabled + * + * E7 S2 VID=1c73 PID=861f HW=19 FW=0.4 AMTCI=0.5 "anysee-E7S2(LP)" + * PCB: 508S2 (rev0.7) + * parts: DNBU10512IST(STV0903, STV6110), ISL6423 + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[5] STV0903 1=enabled + * + * E7 T2C VID=1c73 PID=861f HW=20 FW=0.1 AMTCI=0.5 "anysee-E7T2C(LP)" + * PCB: 508T2C (rev0.3) + * parts: DNOQ44QCH106A(CXD2820R, TDA18212), TDA8024 + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[5] CXD2820R 1=enabled + * + * E7 PTC VID=1c73 PID=861f HW=21 FW=0.1 AMTCI=?? "anysee-E7PTC(LP)" + * PCB: 508PTC (rev0.5) + * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212) + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[4] TDA18212 1=enabled + * DVB-C: + * IOD[6] ZL10353 0=disabled + * IOD[5] TDA10023 1=enabled + * IOE[0] IF 1=enabled + * DVB-T: + * IOD[5] TDA10023 0=disabled + * IOD[6] ZL10353 1=enabled + * IOE[0] IF 0=enabled + * + * E7 PS2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)" + * PCB: 508PS2 (rev0.4) + * parts: DNBU10512IST(STV0903, STV6110), ISL6423 + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[5] STV0903 1=enabled + */ + +static int anysee_read_config(struct dvb_usb_device *d) +{ + struct anysee_state *state = d_to_priv(d); + int ret; + u8 hw_info[3]; + + /* + * Check which hardware we have. + * We must do this call two times to get reliable values (hw/fw bug). + */ + ret = anysee_get_hw_info(d, hw_info); + if (ret) + goto error; + + ret = anysee_get_hw_info(d, hw_info); + if (ret) + goto error; + + /* Meaning of these info bytes are guessed. */ + info("firmware version:%d.%d hardware id:%d", + hw_info[1], hw_info[2], hw_info[0]); + + state->hw = hw_info[0]; +error: + return ret; +} + +/* external I2C gate used for DNOD44CDH086A(TDA18212) tuner module */ +static int anysee_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + /* enable / disable tuner access on IOE[4] */ + return anysee_wr_reg_mask(fe_to_d(fe), REG_IOE, (enable << 4), 0x10); +} + +static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct anysee_state *state = fe_to_priv(fe); + struct dvb_usb_device *d = fe_to_d(fe); + int ret; + + deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); + + /* no frontend sleep control */ + if (onoff == 0) + return 0; + + switch (state->hw) { + case ANYSEE_HW_507FA: /* 15 */ + /* E30 Combo Plus */ + /* E30 C Plus */ + + if (fe->id == 0) { + /* disable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 0), 0x01); + if (ret) + goto error; + + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); + if (ret) + goto error; + + /* enable DVB-C tuner on IOE[0] */ + ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 0), 0x01); + if (ret) + goto error; + } else { + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); + if (ret) + goto error; + + /* enable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); + if (ret) + goto error; + + /* enable DVB-T tuner on IOE[0] */ + ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 0), 0x01); + if (ret) + goto error; + } + + break; + case ANYSEE_HW_508TC: /* 18 */ + case ANYSEE_HW_508PTC: /* 21 */ + /* E7 TC */ + /* E7 PTC */ + + if (fe->id == 0) { + /* disable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 6), 0x40); + if (ret) + goto error; + + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); + if (ret) + goto error; + + /* enable IF route on IOE[0] */ + ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 0), 0x01); + if (ret) + goto error; + } else { + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); + if (ret) + goto error; + + /* enable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 6), 0x40); + if (ret) + goto error; + + /* enable IF route on IOE[0] */ + ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 0), 0x01); + if (ret) + goto error; + } + + break; + default: + ret = 0; + } + +error: + return ret; +} + +static int anysee_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct anysee_state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + int ret; + u8 tmp; + struct i2c_msg msg[2] = { + { + .addr = anysee_tda18212_config.i2c_address, + .flags = 0, + .len = 1, + .buf = "\x00", + }, { + .addr = anysee_tda18212_config.i2c_address, + .flags = I2C_M_RD, + .len = 1, + .buf = &tmp, + } + }; + + switch (state->hw) { + case ANYSEE_HW_507T: /* 2 */ + /* E30 */ + + /* attach demod */ + adap->fe[0] = dvb_attach(mt352_attach, &anysee_mt352_config, + &d->i2c_adap); + if (adap->fe[0]) + break; + + /* attach demod */ + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, + &d->i2c_adap); + + break; + case ANYSEE_HW_507CD: /* 6 */ + /* E30 Plus */ + + /* enable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); + if (ret) + goto error; + + /* enable transport stream on IOA[7] */ + ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); + if (ret) + goto error; + + /* attach demod */ + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, + &d->i2c_adap); + + break; + case ANYSEE_HW_507DC: /* 10 */ + /* E30 C Plus */ + + /* enable DVB-C demod on IOD[0] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); + if (ret) + goto error; + + /* attach demod */ + adap->fe[0] = dvb_attach(tda10023_attach, + &anysee_tda10023_config, &d->i2c_adap, 0x48); + + break; + case ANYSEE_HW_507SI: /* 11 */ + /* E30 S2 Plus */ + + /* enable DVB-S/S2 demod on IOD[0] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); + if (ret) + goto error; + + /* attach demod */ + adap->fe[0] = dvb_attach(cx24116_attach, &anysee_cx24116_config, + &d->i2c_adap); + + break; + case ANYSEE_HW_507FA: /* 15 */ + /* E30 Combo Plus */ + /* E30 C Plus */ + + /* enable tuner on IOE[4] */ + ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 4), 0x10); + if (ret) + goto error; + + /* probe TDA18212 */ + tmp = 0; + ret = i2c_transfer(&d->i2c_adap, msg, 2); + if (ret == 2 && tmp == 0xc7) + deb_info("%s: TDA18212 found\n", __func__); + else + tmp = 0; + + /* disable tuner on IOE[4] */ + ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 4), 0x10); + if (ret) + goto error; + + /* disable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 0), 0x01); + if (ret) + goto error; + + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); + if (ret) + goto error; + + /* attach demod */ + if (tmp == 0xc7) { + /* TDA18212 config */ + adap->fe[0] = dvb_attach(tda10023_attach, + &anysee_tda10023_tda18212_config, + &d->i2c_adap, 0x48); + + /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ + if (adap->fe[0]) + adap->fe[0]->ops.i2c_gate_ctrl = + anysee_i2c_gate_ctrl; + } else { + /* PLL config */ + adap->fe[0] = dvb_attach(tda10023_attach, + &anysee_tda10023_config, + &d->i2c_adap, 0x48); + } + + /* break out if first frontend attaching fails */ + if (!adap->fe[0]) + break; + + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); + if (ret) + goto error; + + /* enable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); + if (ret) + goto error; + + /* attach demod */ + if (tmp == 0xc7) { + /* TDA18212 config */ + adap->fe[1] = dvb_attach(zl10353_attach, + &anysee_zl10353_tda18212_config2, + &d->i2c_adap); + + /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ + if (adap->fe[1]) + adap->fe[1]->ops.i2c_gate_ctrl = + anysee_i2c_gate_ctrl; + } else { + /* PLL config */ + adap->fe[1] = dvb_attach(zl10353_attach, + &anysee_zl10353_config, + &d->i2c_adap); + } + + break; + case ANYSEE_HW_508TC: /* 18 */ + case ANYSEE_HW_508PTC: /* 21 */ + /* E7 TC */ + /* E7 PTC */ + + /* disable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 6), 0x40); + if (ret) + goto error; + + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); + if (ret) + goto error; + + /* attach demod */ + adap->fe[0] = dvb_attach(tda10023_attach, + &anysee_tda10023_tda18212_config, + &d->i2c_adap, 0x48); + + /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ + if (adap->fe[0]) + adap->fe[0]->ops.i2c_gate_ctrl = anysee_i2c_gate_ctrl; + + /* break out if first frontend attaching fails */ + if (!adap->fe[0]) + break; + + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); + if (ret) + goto error; + + /* enable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 6), 0x40); + if (ret) + goto error; + + /* attach demod */ + adap->fe[1] = dvb_attach(zl10353_attach, + &anysee_zl10353_tda18212_config, + &d->i2c_adap); + + /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ + if (adap->fe[1]) + adap->fe[1]->ops.i2c_gate_ctrl = anysee_i2c_gate_ctrl; + + state->has_ci = true; + + break; + case ANYSEE_HW_508S2: /* 19 */ + case ANYSEE_HW_508PS2: /* 22 */ + /* E7 S2 */ + /* E7 PS2 */ + + /* enable DVB-S/S2 demod on IOE[5] */ + ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 5), 0x20); + if (ret) + goto error; + + /* attach demod */ + adap->fe[0] = dvb_attach(stv0900_attach, + &anysee_stv0900_config, &d->i2c_adap, 0); + + state->has_ci = true; + + break; + case ANYSEE_HW_508T2C: /* 20 */ + /* E7 T2C */ + + /* enable DVB-T/T2/C demod on IOE[5] */ + ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 5), 0x20); + if (ret) + goto error; + + /* attach demod */ + adap->fe[0] = dvb_attach(cxd2820r_attach, + &anysee_cxd2820r_config, &d->i2c_adap); + + state->has_ci = true; + + break; + } + + if (!adap->fe[0]) { + /* we have no frontend :-( */ + ret = -ENODEV; + err("Unsupported Anysee version. " \ + "Please report the ."); + } +error: + return ret; +} + +static int anysee_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct anysee_state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + struct dvb_frontend *fe; + int ret; + deb_info("%s: adap=%d\n", __func__, adap->id); + + switch (state->hw) { + case ANYSEE_HW_507T: /* 2 */ + /* E30 */ + + /* attach tuner */ + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), NULL, + DVB_PLL_THOMSON_DTT7579); + + break; + case ANYSEE_HW_507CD: /* 6 */ + /* E30 Plus */ + + /* attach tuner */ + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), + &d->i2c_adap, DVB_PLL_THOMSON_DTT7579); + + break; + case ANYSEE_HW_507DC: /* 10 */ + /* E30 C Plus */ + + /* attach tuner */ + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), + &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); + + break; + case ANYSEE_HW_507SI: /* 11 */ + /* E30 S2 Plus */ + + /* attach LNB controller */ + fe = dvb_attach(isl6423_attach, adap->fe[0], &d->i2c_adap, + &anysee_isl6423_config); + + break; + case ANYSEE_HW_507FA: /* 15 */ + /* E30 Combo Plus */ + /* E30 C Plus */ + + /* Try first attach TDA18212 silicon tuner on IOE[4], if that + * fails attach old simple PLL. */ + + /* attach tuner */ + fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, + &anysee_tda18212_config); + + if (fe && adap->fe[1]) { + /* attach tuner for 2nd FE */ + fe = dvb_attach(tda18212_attach, adap->fe[1], + &d->i2c_adap, &anysee_tda18212_config); + break; + } else if (fe) { + break; + } + + /* attach tuner */ + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), + &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); + + if (fe && adap->fe[1]) { + /* attach tuner for 2nd FE */ + fe = dvb_attach(dvb_pll_attach, adap->fe[0], + (0xc0 >> 1), &d->i2c_adap, + DVB_PLL_SAMSUNG_DTOS403IH102A); + } + + break; + case ANYSEE_HW_508TC: /* 18 */ + case ANYSEE_HW_508PTC: /* 21 */ + /* E7 TC */ + /* E7 PTC */ + + /* attach tuner */ + fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, + &anysee_tda18212_config); + + if (fe) { + /* attach tuner for 2nd FE */ + fe = dvb_attach(tda18212_attach, adap->fe[1], + &d->i2c_adap, &anysee_tda18212_config); + } + + break; + case ANYSEE_HW_508S2: /* 19 */ + case ANYSEE_HW_508PS2: /* 22 */ + /* E7 S2 */ + /* E7 PS2 */ + + /* attach tuner */ + fe = dvb_attach(stv6110_attach, adap->fe[0], + &anysee_stv6110_config, &d->i2c_adap); + + if (fe) { + /* attach LNB controller */ + fe = dvb_attach(isl6423_attach, adap->fe[0], + &d->i2c_adap, &anysee_isl6423_config); + } + + break; + + case ANYSEE_HW_508T2C: /* 20 */ + /* E7 T2C */ + + /* attach tuner */ + fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, + &anysee_tda18212_config2); + + break; + default: + fe = NULL; + } + + if (fe) + ret = 0; + else + ret = -ENODEV; + + return ret; +} + +static int anysee_rc_query(struct dvb_usb_device *d) +{ + u8 buf[] = {CMD_GET_IR_CODE}; + u8 ircode[2]; + int ret; + + /* Remote controller is basic NEC using address byte 0x08. + Anysee device RC query returns only two bytes, status and code, + address byte is dropped. Also it does not return any value for + NEC RCs having address byte other than 0x08. Due to that, we + cannot use that device as standard NEC receiver. + It could be possible make hack which reads whole code directly + from device memory... */ + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), ircode, sizeof(ircode)); + if (ret) + return ret; + + if (ircode[0]) { + deb_rc("%s: key pressed %02x\n", __func__, ircode[1]); + rc_keydown(d->rc_dev, 0x08 << 8 | ircode[1], 0); + } + + return 0; +} + +static int anysee_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) +{ + rc->allowed_protos = RC_TYPE_NEC; + rc->query = anysee_rc_query; + rc->interval = 250; /* windows driver uses 500ms */ + + return 0; +} + +static int anysee_ci_read_attribute_mem(struct dvb_ca_en50221 *ci, int slot, + int addr) +{ + struct dvb_usb_device *d = ci->data; + int ret; + u8 buf[] = {CMD_CI, 0x02, 0x40 | addr >> 8, addr & 0xff, 0x00, 1}; + u8 val; + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1); + if (ret) + return ret; + + return val; +} + +static int anysee_ci_write_attribute_mem(struct dvb_ca_en50221 *ci, int slot, + int addr, u8 val) +{ + struct dvb_usb_device *d = ci->data; + int ret; + u8 buf[] = {CMD_CI, 0x03, 0x40 | addr >> 8, addr & 0xff, 0x00, 1, val}; + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_read_cam_control(struct dvb_ca_en50221 *ci, int slot, + u8 addr) +{ + struct dvb_usb_device *d = ci->data; + int ret; + u8 buf[] = {CMD_CI, 0x04, 0x40, addr, 0x00, 1}; + u8 val; + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1); + if (ret) + return ret; + + return val; +} + +static int anysee_ci_write_cam_control(struct dvb_ca_en50221 *ci, int slot, + u8 addr, u8 val) +{ + struct dvb_usb_device *d = ci->data; + int ret; + u8 buf[] = {CMD_CI, 0x05, 0x40, addr, 0x00, 1, val}; + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_slot_reset(struct dvb_ca_en50221 *ci, int slot) +{ + struct dvb_usb_device *d = ci->data; + int ret; + struct anysee_state *state = d_to_priv(d); + + state->ci_cam_ready = jiffies + msecs_to_jiffies(1000); + + ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); + if (ret) + return ret; + + msleep(300); + + ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_slot_shutdown(struct dvb_ca_en50221 *ci, int slot) +{ + struct dvb_usb_device *d = ci->data; + int ret; + + ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); + if (ret) + return ret; + + msleep(30); + + ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_slot_ts_enable(struct dvb_ca_en50221 *ci, int slot) +{ + struct dvb_usb_device *d = ci->data; + int ret; + + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 1), 0x02); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot, + int open) +{ + struct dvb_usb_device *d = ci->data; + struct anysee_state *state = d_to_priv(d); + int ret; + u8 tmp; + + ret = anysee_rd_reg_mask(d, REG_IOC, &tmp, 0x40); + if (ret) + return ret; + + if (tmp == 0) { + ret = DVB_CA_EN50221_POLL_CAM_PRESENT; + if (time_after(jiffies, state->ci_cam_ready)) + ret |= DVB_CA_EN50221_POLL_CAM_READY; + } + + return ret; +} + +static int anysee_ci_init(struct dvb_usb_device *d) +{ + struct anysee_state *state = d_to_priv(d); + int ret; + + state->ci.owner = THIS_MODULE; + state->ci.read_attribute_mem = anysee_ci_read_attribute_mem; + state->ci.write_attribute_mem = anysee_ci_write_attribute_mem; + state->ci.read_cam_control = anysee_ci_read_cam_control; + state->ci.write_cam_control = anysee_ci_write_cam_control; + state->ci.slot_reset = anysee_ci_slot_reset; + state->ci.slot_shutdown = anysee_ci_slot_shutdown; + state->ci.slot_ts_enable = anysee_ci_slot_ts_enable; + state->ci.poll_slot_status = anysee_ci_poll_slot_status; + state->ci.data = d; + + ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); + if (ret) + return ret; + + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 2)|(0 << 1)|(0 << 0), 0x07); + if (ret) + return ret; + + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 2)|(1 << 1)|(1 << 0), 0x07); + if (ret) + return ret; + + ret = dvb_ca_en50221_init(&d->adapter[0].dvb_adap, &state->ci, 0, 1); + if (ret) + return ret; + + return 0; +} + +static void anysee_ci_release(struct dvb_usb_device *d) +{ + struct anysee_state *state = d_to_priv(d); + + /* detach CI */ + if (state->has_ci) + dvb_ca_en50221_release(&state->ci); + + return; +} + +static int anysee_init(struct dvb_usb_device *d) +{ + struct anysee_state *state = d_to_priv(d); + int ret; + + /* There is one interface with two alternate settings. + Alternate setting 0 is for bulk transfer. + Alternate setting 1 is for isochronous transfer. + We use bulk transfer (alternate setting 0). */ + ret = usb_set_interface(d->udev, 0, 0); + if (ret) + return ret; + + /* LED light */ + ret = anysee_led_ctrl(d, 0x01, 0x03); + if (ret) + return ret; + + /* enable IR */ + ret = anysee_ir_ctrl(d, 1); + if (ret) + return ret; + + /* attach CI */ + if (state->has_ci) { + ret = anysee_ci_init(d); + if (ret) { + state->has_ci = false; + return ret; + } + } + + return 0; +} + +static void anysee_exit(struct dvb_usb_device *d) +{ + return anysee_ci_release(d); +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties anysee_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct anysee_state), + + .generic_bulk_ctrl_endpoint = 0x01, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &anysee_i2c_algo, + .read_config = anysee_read_config, + .frontend_attach = anysee_frontend_attach, + .tuner_attach = anysee_tuner_attach, + .init = anysee_init, + .get_rc_config = anysee_get_rc_config, + .frontend_ctrl = anysee_frontend_ctrl, + .streaming_ctrl = anysee_streaming_ctrl, + .exit = anysee_exit, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_BULK(0x82, 8, 16 * 512), + } + } +}; + +static const struct usb_device_id anysee_id_table[] = { + { DVB_USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE, + &anysee_props, "Anysee", RC_MAP_ANYSEE) }, + { DVB_USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE, + &anysee_props, "Anysee", RC_MAP_ANYSEE) }, + { } +}; +MODULE_DEVICE_TABLE(usb, anysee_id_table); + +static struct usb_driver anysee_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = anysee_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(anysee_usb_driver); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/anysee.h b/drivers/media/dvb/dvb-usb-v2/anysee.h new file mode 100644 index 000000000000..dc40dcf7c328 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/anysee.h @@ -0,0 +1,356 @@ +/* + * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * TODO: + * - add smart card reader support for Conditional Access (CA) + * + * Card reader in Anysee is nothing more than ISO 7816 card reader. + * There is no hardware CAM in any Anysee device sold. + * In my understanding it should be implemented by making own module + * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This + * module registers serial interface that can be used to communicate + * with any ISO 7816 smart card. + * + * Any help according to implement serial smart card reader support + * is highly welcome! + */ + +#ifndef _DVB_USB_ANYSEE_H_ +#define _DVB_USB_ANYSEE_H_ + +#define DVB_USB_LOG_PREFIX "anysee" +#include "dvb_usb.h" +#include "dvb_ca_en50221.h" + +#ifdef CONFIG_DVB_USB_DEBUG +#define dprintk(var, level, args...) \ + do { if ((var & level)) printk(args); } while (0) +#define DVB_USB_DEBUG_STATUS +#else +#define dprintk(args...) +#define debug_dump(b, l, func) +#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" +#endif + +#define debug_dump(b, l, func) {\ + int loop_; \ + for (loop_ = 0; loop_ < l; loop_++) \ + func("%02x ", b[loop_]); \ + func("\n");\ +} + +#define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args) +#define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args) +#define deb_rc(args...) dprintk(dvb_usb_anysee_debug, 0x04, args) +#define deb_reg(args...) dprintk(dvb_usb_anysee_debug, 0x08, args) +#define deb_i2c(args...) dprintk(dvb_usb_anysee_debug, 0x10, args) +#define deb_fw(args...) dprintk(dvb_usb_anysee_debug, 0x20, args) + +#undef err +#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#undef info +#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#undef warn +#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) + +enum cmd { + CMD_I2C_READ = 0x33, + CMD_I2C_WRITE = 0x31, + CMD_REG_READ = 0xb0, + CMD_REG_WRITE = 0xb1, + CMD_STREAMING_CTRL = 0x12, + CMD_LED_AND_IR_CTRL = 0x16, + CMD_GET_IR_CODE = 0x41, + CMD_GET_HW_INFO = 0x19, + CMD_SMARTCARD = 0x34, + CMD_CI = 0x37, +}; + +struct anysee_state { + u8 hw; /* PCB ID */ + u8 seq; + u8 fe_id:1; /* frondend ID */ + u8 has_ci:1; + struct dvb_ca_en50221 ci; + unsigned long ci_cam_ready; /* jiffies */ +}; + +#define ANYSEE_HW_507T 2 /* E30 */ +#define ANYSEE_HW_507CD 6 /* E30 Plus */ +#define ANYSEE_HW_507DC 10 /* E30 C Plus */ +#define ANYSEE_HW_507SI 11 /* E30 S2 Plus */ +#define ANYSEE_HW_507FA 15 /* E30 Combo Plus / E30 C Plus */ +#define ANYSEE_HW_508TC 18 /* E7 TC */ +#define ANYSEE_HW_508S2 19 /* E7 S2 */ +#define ANYSEE_HW_508T2C 20 /* E7 T2C */ +#define ANYSEE_HW_508PTC 21 /* E7 PTC Plus */ +#define ANYSEE_HW_508PS2 22 /* E7 PS2 Plus */ + +#define REG_IOA 0x80 /* Port A (bit addressable) */ +#define REG_IOB 0x90 /* Port B (bit addressable) */ +#define REG_IOC 0xa0 /* Port C (bit addressable) */ +#define REG_IOD 0xb0 /* Port D (bit addressable) */ +#define REG_IOE 0xb1 /* Port E (NOT bit addressable) */ +#define REG_OEA 0xb2 /* Port A Output Enable */ +#define REG_OEB 0xb3 /* Port B Output Enable */ +#define REG_OEC 0xb4 /* Port C Output Enable */ +#define REG_OED 0xb5 /* Port D Output Enable */ +#define REG_OEE 0xb6 /* Port E Output Enable */ + +#endif + +/*************************************************************************** + * USB API description (reverse engineered) + *************************************************************************** + +Transaction flow: +================= +BULK[00001] >>> REQUEST PACKET 64 bytes +BULK[00081] <<< REPLY PACKET #1 64 bytes (PREVIOUS TRANSACTION REPLY) +BULK[00081] <<< REPLY PACKET #2 64 bytes (CURRENT TRANSACTION REPLY) + +General reply packet(s) are always used if not own reply defined. + +============================================================================ +| 00-63 | GENERAL REPLY PACKET #1 (PREVIOUS REPLY) +============================================================================ +| 00 | reply data (if any) from previous transaction +| | Just same reply packet as returned during previous transaction. +| | Needed only if reply is missed in previous transaction. +| | Just skip normally. +---------------------------------------------------------------------------- +| 01-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | GENERAL REPLY PACKET #2 (CURRENT REPLY) +============================================================================ +| 00 | reply data (if any) +---------------------------------------------------------------------------- +| 01-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | I2C WRITE REQUEST PACKET +============================================================================ +| 00 | 0x31 I2C write command +---------------------------------------------------------------------------- +| 01 | i2c address +---------------------------------------------------------------------------- +| 02 | data length +| | 0x02 (for typical I2C reg / val pair) +---------------------------------------------------------------------------- +| 03 | 0x01 +---------------------------------------------------------------------------- +| 04- | data +---------------------------------------------------------------------------- +| -59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | I2C READ REQUEST PACKET +============================================================================ +| 00 | 0x33 I2C read command +---------------------------------------------------------------------------- +| 01 | i2c address + 1 +---------------------------------------------------------------------------- +| 02 | register +---------------------------------------------------------------------------- +| 03 | 0x00 +---------------------------------------------------------------------------- +| 04 | 0x00 +---------------------------------------------------------------------------- +| 05 | data length +---------------------------------------------------------------------------- +| 06-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | USB CONTROLLER REGISTER WRITE REQUEST PACKET +============================================================================ +| 00 | 0xb1 register write command +---------------------------------------------------------------------------- +| 01-02 | register +---------------------------------------------------------------------------- +| 03 | 0x01 +---------------------------------------------------------------------------- +| 04 | value +---------------------------------------------------------------------------- +| 05-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | USB CONTROLLER REGISTER READ REQUEST PACKET +============================================================================ +| 00 | 0xb0 register read command +---------------------------------------------------------------------------- +| 01-02 | register +---------------------------------------------------------------------------- +| 03 | 0x01 +---------------------------------------------------------------------------- +| 04-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | LED CONTROL REQUEST PACKET +============================================================================ +| 00 | 0x16 LED and IR control command +---------------------------------------------------------------------------- +| 01 | 0x01 (LED) +---------------------------------------------------------------------------- +| 03 | 0x00 blink +| | 0x01 lights continuously +---------------------------------------------------------------------------- +| 04 | blink interval +| | 0x00 fastest (looks like LED lights continuously) +| | 0xff slowest +---------------------------------------------------------------------------- +| 05-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | IR CONTROL REQUEST PACKET +============================================================================ +| 00 | 0x16 LED and IR control command +---------------------------------------------------------------------------- +| 01 | 0x02 (IR) +---------------------------------------------------------------------------- +| 03 | 0x00 IR disabled +| | 0x01 IR enabled +---------------------------------------------------------------------------- +| 04-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | STREAMING CONTROL REQUEST PACKET +============================================================================ +| 00 | 0x12 streaming control command +---------------------------------------------------------------------------- +| 01 | 0x00 streaming disabled +| | 0x01 streaming enabled +---------------------------------------------------------------------------- +| 02 | 0x00 +---------------------------------------------------------------------------- +| 03-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | REMOTE CONTROL REQUEST PACKET +============================================================================ +| 00 | 0x41 remote control command +---------------------------------------------------------------------------- +| 01-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | REMOTE CONTROL REPLY PACKET +============================================================================ +| 00 | 0x00 code not received +| | 0x01 code received +---------------------------------------------------------------------------- +| 01 | remote control code +---------------------------------------------------------------------------- +| 02-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | GET HARDWARE INFO REQUEST PACKET +============================================================================ +| 00 | 0x19 get hardware info command +---------------------------------------------------------------------------- +| 01-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | GET HARDWARE INFO REPLY PACKET +============================================================================ +| 00 | hardware id +---------------------------------------------------------------------------- +| 01-02 | firmware version +---------------------------------------------------------------------------- +| 03-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | SMART CARD READER PACKET +============================================================================ +| 00 | 0x34 smart card reader command +---------------------------------------------------------------------------- +| xx | +---------------------------------------------------------------------------- +| xx-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +*/ diff --git a/drivers/media/dvb/dvb-usb-v2/au6610.c b/drivers/media/dvb/dvb-usb-v2/au6610.c new file mode 100644 index 000000000000..05f2a8628142 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/au6610.c @@ -0,0 +1,206 @@ +/* + * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0. + * + * Copyright (C) 2006 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "au6610.h" +#include "zl10353.h" +#include "qt1010.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + int ret; + u16 index; + u8 *usb_buf; + + /* + * allocate enough for all known requests, + * read returns 5 and write 6 bytes + */ + usb_buf = kmalloc(6, GFP_KERNEL); + if (!usb_buf) + return -ENOMEM; + + switch (wlen) { + case 1: + index = wbuf[0] << 8; + break; + case 2: + index = wbuf[0] << 8; + index += wbuf[1]; + break; + default: + pr_err("%s: wlen = %d, aborting\n", KBUILD_MODNAME, wlen); + ret = -EINVAL; + goto error; + } + + ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation, + USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index, + usb_buf, 6, AU6610_USB_TIMEOUT); + if (ret < 0) + goto error; + + switch (operation) { + case AU6610_REQ_I2C_READ: + case AU6610_REQ_USB_READ: + /* requested value is always 5th byte in buffer */ + rbuf[0] = usb_buf[4]; + } +error: + kfree(usb_buf); + return ret; +} + +static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + u8 request; + u8 wo = (rbuf == NULL || rlen == 0); /* write-only */ + + if (wo) { + request = AU6610_REQ_I2C_WRITE; + } else { /* rw */ + request = AU6610_REQ_I2C_READ; + } + + return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen); +} + + +/* I2C */ +static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + if (num > 2) + return -EINVAL; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + /* write/read request */ + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf, + msg[i].len, msg[i+1].buf, + msg[i+1].len) < 0) + break; + i++; + } else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf, + msg[i].len, NULL, 0) < 0) + break; + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + + +static u32 au6610_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm au6610_i2c_algo = { + .master_xfer = au6610_i2c_xfer, + .functionality = au6610_i2c_func, +}; + +/* Callbacks for DVB USB */ +static struct zl10353_config au6610_zl10353_config = { + .demod_address = 0x0f, + .no_tuner = 1, + .parallel_ts = 1, +}; + +static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap) +{ + adap->fe[0] = dvb_attach(zl10353_attach, &au6610_zl10353_config, + &adap_to_d(adap)->i2c_adap); + if (adap->fe[0] == NULL) + return -ENODEV; + + return 0; +} + +static struct qt1010_config au6610_qt1010_config = { + .i2c_address = 0x62 +}; + +static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap) +{ + return dvb_attach(qt1010_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + &au6610_qt1010_config) == NULL ? -ENODEV : 0; +} + +static int au6610_init(struct dvb_usb_device *d) +{ + /* TODO: this functionality belongs likely to the streaming control */ + /* bInterfaceNumber 0, bAlternateSetting 5 */ + return usb_set_interface(d->udev, 0, 5); +} + +static struct dvb_usb_device_properties au6610_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + + .i2c_algo = &au6610_i2c_algo, + .frontend_attach = au6610_zl10353_frontend_attach, + .tuner_attach = au6610_qt1010_tuner_attach, + .init = au6610_init, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_ISOC(0x82, 5, 40, 942, 1), + }, + }, +}; + +static const struct usb_device_id au6610_id_table[] = { + { DVB_USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110, + &au6610_props, "Sigmatek DVB-110", NULL) }, + { } +}; +MODULE_DEVICE_TABLE(usb, au6610_id_table); + +static struct usb_driver au6610_driver = { + .name = KBUILD_MODNAME, + .id_table = au6610_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(au6610_driver); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0"); +MODULE_VERSION("0.1"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/au6610.h b/drivers/media/dvb/dvb-usb-v2/au6610.h new file mode 100644 index 000000000000..ea337bfc00b1 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/au6610.h @@ -0,0 +1,32 @@ +/* + * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0. + * + * Copyright (C) 2006 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef AU6610_H +#define AU6610_H +#include "dvb_usb.h" + +#define AU6610_REQ_I2C_WRITE 0x14 +#define AU6610_REQ_I2C_READ 0x13 +#define AU6610_REQ_USB_WRITE 0x16 +#define AU6610_REQ_USB_READ 0x15 + +#define AU6610_USB_TIMEOUT 1000 + +#endif diff --git a/drivers/media/dvb/dvb-usb-v2/ce6230.c b/drivers/media/dvb/dvb-usb-v2/ce6230.c new file mode 100644 index 000000000000..84ff4a96ca4e --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/ce6230.c @@ -0,0 +1,287 @@ +/* + * Intel CE6230 DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "ce6230.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) +{ + int ret; + unsigned int pipe; + u8 request; + u8 requesttype; + u16 value; + u16 index; + u8 *buf; + + request = req->cmd; + value = req->value; + index = req->index; + + switch (req->cmd) { + case I2C_READ: + case DEMOD_READ: + case REG_READ: + requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); + break; + case I2C_WRITE: + case DEMOD_WRITE: + case REG_WRITE: + requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); + break; + default: + pr_debug("%s: unknown command=%02x\n", __func__, req->cmd); + ret = -EINVAL; + goto error; + } + + buf = kmalloc(req->data_len, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto error; + } + + if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) { + /* write */ + memcpy(buf, req->data, req->data_len); + pipe = usb_sndctrlpipe(d->udev, 0); + } else { + /* read */ + pipe = usb_rcvctrlpipe(d->udev, 0); + } + + msleep(1); /* avoid I2C errors */ + + ret = usb_control_msg(d->udev, pipe, request, requesttype, value, index, + buf, req->data_len, CE6230_USB_TIMEOUT); + + ce6230_debug_dump(request, requesttype, value, index, buf, + req->data_len); + + if (ret < 0) + pr_err("%s: usb_control_msg() failed=%d\n", KBUILD_MODNAME, + ret); + else + ret = 0; + + /* read request, copy returned data to return buf */ + if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) + memcpy(req->data, buf, req->data_len); + + kfree(buf); +error: + return ret; +} + +/* I2C */ +static struct zl10353_config ce6230_zl10353_config; + +static int ce6230_i2c_master_xfer(struct i2c_adapter *adap, + struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret = 0, i = 0; + struct usb_req req; + + if (num > 2) + return -EOPNOTSUPP; + + memset(&req, 0, sizeof(req)); + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + while (i < num) { + if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { + if (msg[i].addr == + ce6230_zl10353_config.demod_address) { + req.cmd = DEMOD_READ; + req.value = msg[i].addr >> 1; + req.index = msg[i].buf[0]; + req.data_len = msg[i+1].len; + req.data = &msg[i+1].buf[0]; + ret = ce6230_ctrl_msg(d, &req); + } else { + pr_err("%s: I2C read not implemented\n", + KBUILD_MODNAME); + ret = -EOPNOTSUPP; + } + i += 2; + } else { + if (msg[i].addr == + ce6230_zl10353_config.demod_address) { + req.cmd = DEMOD_WRITE; + req.value = msg[i].addr >> 1; + req.index = msg[i].buf[0]; + req.data_len = msg[i].len-1; + req.data = &msg[i].buf[1]; + ret = ce6230_ctrl_msg(d, &req); + } else { + req.cmd = I2C_WRITE; + req.value = 0x2000 + (msg[i].addr >> 1); + req.index = 0x0000; + req.data_len = msg[i].len; + req.data = &msg[i].buf[0]; + ret = ce6230_ctrl_msg(d, &req); + } + i += 1; + } + if (ret) + break; + } + + mutex_unlock(&d->i2c_mutex); + return ret ? ret : i; +} + +static u32 ce6230_i2c_functionality(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm ce6230_i2c_algorithm = { + .master_xfer = ce6230_i2c_master_xfer, + .functionality = ce6230_i2c_functionality, +}; + +/* Callbacks for DVB USB */ +static struct zl10353_config ce6230_zl10353_config = { + .demod_address = 0x1e, + .adc_clock = 450000, + .if2 = 45700, + .no_tuner = 1, + .parallel_ts = 1, + .clock_ctl_1 = 0x34, + .pll_0 = 0x0e, +}; + +static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap) +{ + pr_debug("%s:\n", __func__); + + adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config, + &adap_to_d(adap)->i2c_adap); + if (adap->fe[0] == NULL) + return -ENODEV; + + return 0; +} + +static struct mxl5005s_config ce6230_mxl5003s_config = { + .i2c_address = 0xc6, + .if_freq = IF_FREQ_4570000HZ, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_DEFAULT, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) +{ + int ret; + + pr_debug("%s:\n", __func__); + + ret = dvb_attach(mxl5005s_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0; + return ret; +} + +static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + + pr_debug("%s: onoff=%d\n", __func__, onoff); + + /* InterfaceNumber 1 / AlternateSetting 0 idle + InterfaceNumber 1 / AlternateSetting 1 streaming */ + ret = usb_set_interface(d->udev, 1, onoff); + if (ret) + pr_err("%s: usb_set_interface() failed=%d\n", KBUILD_MODNAME, + ret); + + return ret; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties ce6230_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .bInterfaceNumber = 1, + + .i2c_algo = &ce6230_i2c_algorithm, + .power_ctrl = ce6230_power_ctrl, + .frontend_attach = ce6230_zl10353_frontend_attach, + .tuner_attach = ce6230_mxl5003s_tuner_attach, + + .num_adapters = 1, + .adapter = { + { + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = (16 * 512), + } + } + }, + } + }, +}; + +static const struct usb_device_id ce6230_id_table[] = { + { DVB_USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500, + &ce6230_props, "Intel CE9500 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310, + &ce6230_props, "AVerMedia A310 USB 2.0 DVB-T tuner", NULL) }, + { } +}; +MODULE_DEVICE_TABLE(usb, ce6230_id_table); + +static struct usb_driver ce6230_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = ce6230_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(ce6230_usb_driver); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Intel CE6230 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/ce6230.h b/drivers/media/dvb/dvb-usb-v2/ce6230.h new file mode 100644 index 000000000000..42d754494a3a --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/ce6230.h @@ -0,0 +1,61 @@ +/* + * Intel CE6230 DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef CE6230_H +#define CE6230_H + +#include "dvb_usb.h" +#include "zl10353.h" +#include "mxl5005s.h" + +#define ce6230_debug_dump(r, t, v, i, b, l) { \ + char *direction; \ + if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ + direction = ">>>"; \ + else \ + direction = "<<<"; \ + pr_debug("%s: %02x %02x %02x %02x %02x %02x %02x %02x %s [%d bytes]\n", \ + __func__, t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, \ + l & 0xff, l >> 8, direction, l); \ +} + +#define CE6230_USB_TIMEOUT 1000 + +struct usb_req { + u8 cmd; /* [1] */ + u16 value; /* [2|3] */ + u16 index; /* [4|5] */ + u16 data_len; /* [6|7] */ + u8 *data; +}; + +enum ce6230_cmd { + CONFIG_READ = 0xd0, /* rd 0 (unclear) */ + UNKNOWN_WRITE = 0xc7, /* wr 7 (unclear) */ + I2C_READ = 0xd9, /* rd 9 (unclear) */ + I2C_WRITE = 0xca, /* wr a */ + DEMOD_READ = 0xdb, /* rd b */ + DEMOD_WRITE = 0xcc, /* wr c */ + REG_READ = 0xde, /* rd e */ + REG_WRITE = 0xcf, /* wr f */ +}; + +#endif diff --git a/drivers/media/dvb/dvb-usb-v2/dvb_usb.h b/drivers/media/dvb/dvb-usb-v2/dvb_usb.h new file mode 100644 index 000000000000..4db591be646c --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/dvb_usb.h @@ -0,0 +1,392 @@ +/* + * DVB USB framework + * + * Copyright (C) 2004-6 Patrick Boettcher + * Copyright (C) 2012 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef DVB_USB_H +#define DVB_USB_H + +#include +#include +#include + +#include "dvb_frontend.h" +#include "dvb_demux.h" +#include "dvb_net.h" +#include "dmxdev.h" +#include "../dvb-usb/dvb-usb-ids.h" + +/* + * device file: /dev/dvb/adapter[0-1]/frontend[0-2] + * + * |-- device + * | |-- adapter0 + * | | |-- frontend0 + * | | |-- frontend1 + * | | `-- frontend2 + * | `-- adapter1 + * | |-- frontend0 + * | |-- frontend1 + * | `-- frontend2 + * + * + * Commonly used variable names: + * d = pointer to device (struct dvb_usb_device *) + * adap = pointer to adapter (struct dvb_usb_adapter *) + * fe = pointer to frontend (struct dvb_frontend *) + * + * Use macros defined in that file to resolve needed pointers. + */ + +/* helper macros for every DVB USB driver use */ +#define adap_to_d(adap) (container_of(adap, struct dvb_usb_device, \ + adapter[adap->id])) +#define adap_to_priv(adap) (adap_to_d(adap)->priv) +#define fe_to_adap(fe) ((struct dvb_usb_adapter *) ((fe)->dvb->priv)) +#define fe_to_d(fe) (adap_to_d(fe_to_adap(fe))) +#define fe_to_priv(fe) (fe_to_d(fe)->priv) +#define d_to_priv(d) (d->priv) + +#define DVB_USB_STREAM_BULK(endpoint_, count_, size_) { \ + .type = USB_BULK, \ + .count = count_, \ + .endpoint = endpoint_, \ + .u = { \ + .bulk = { \ + .buffersize = size_, \ + } \ + } \ +} + +#define DVB_USB_STREAM_ISOC(endpoint_, count_, frames_, size_, interval_) { \ + .type = USB_ISOC, \ + .count = count_, \ + .endpoint = endpoint_, \ + .u = { \ + .isoc = { \ + .framesperurb = frames_, \ + .framesize = size_,\ + .interval = interval_, \ + } \ + } \ +} + +#define DVB_USB_DEVICE(vend, prod, props_, name_, rc) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ + .idVendor = (vend), \ + .idProduct = (prod), \ + .driver_info = (kernel_ulong_t) &((const struct dvb_usb_driver_info) { \ + .props = (props_), \ + .name = (name_), \ + .rc_map = (rc), \ + }) + +struct dvb_usb_device; +struct dvb_usb_adapter; + +/** + * structure for carrying all needed data from the device driver to the general + * dvb usb routines + * @name: device name + * @rc_map: name of rc codes table + * @props: structure containing all device properties + */ +struct dvb_usb_driver_info { + const char *name; + const char *rc_map; + const struct dvb_usb_device_properties *props; +}; + +/** + * structure for remote controller configuration + * @map_name: name of rc codes table + * @allowed_protos: protocol(s) supported by the driver + * @change_protocol: callback to change protocol + * @query: called to query an event from the device + * @interval: time in ms between two queries + * @driver_type: used to point if a device supports raw mode + * @bulk_mode: device supports bulk mode for rc (disable polling mode) + */ +struct dvb_usb_rc { + const char *map_name; + u64 allowed_protos; + int (*change_protocol)(struct rc_dev *dev, u64 rc_type); + int (*query) (struct dvb_usb_device *d); + unsigned int interval; + const enum rc_driver_type driver_type; + bool bulk_mode; +}; + +/** + * usb streaming configration for adapter + * @type: urb type + * @count: count of used urbs + * @endpoint: stream usb endpoint number + */ +struct usb_data_stream_properties { +#define USB_BULK 1 +#define USB_ISOC 2 + u8 type; + u8 count; + u8 endpoint; + + union { + struct { + unsigned int buffersize; /* per URB */ + } bulk; + struct { + int framesperurb; + int framesize; + int interval; + } isoc; + } u; +}; + +/** + * properties of dvb usb device adapter + * @caps: adapter capabilities + * @pid_filter_count: pid count of adapter pid-filter + * @pid_filter_ctrl: called to enable/disable pid-filter + * @pid_filter: called to set/unset pid for filtering + * @stream: adapter usb stream configuration + */ +#define MAX_NO_OF_FE_PER_ADAP 3 +struct dvb_usb_adapter_properties { +#define DVB_USB_ADAP_HAS_PID_FILTER 0x01 +#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 +#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 + u8 caps; + + u8 pid_filter_count; + int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); + int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); + + struct usb_data_stream_properties stream; +}; + +/** + * struct dvb_usb_device_properties - properties of a dvb-usb-device + * @driver_name: name of the owning driver module + * @owner: owner of the dvb_adapter + * @adapter_nr: values from the DVB_DEFINE_MOD_OPT_ADAPTER_NR() macro + * @bInterfaceNumber: usb interface number driver binds + * @size_of_priv: bytes allocated for the driver private data + * @generic_bulk_ctrl_endpoint: bulk control endpoint number for sent + * @generic_bulk_ctrl_endpoint_response: bulk control endpoint number for + * receive + * @generic_bulk_ctrl_delay: delay between bulk control sent and receive message + * @identify_state: called to determine the firmware state (cold or warm) and + * return possible firmware file name to be loaded + * @firmware: name of the firmware file to be loaded + * @download_firmware: called to download the firmware + * @i2c_algo: i2c_algorithm if the device has i2c-adapter + * @num_adapters: dvb usb device adapter count + * @get_adapter_count: called to resolve adapter count + * @adapter: array of all adapter properties of device + * @power_ctrl: called to enable/disable power of the device + * @read_config: called to resolve device configuration + * @read_mac_address: called to resolve adapter mac-address + * @frontend_attach: called to attach the possible frontends + * @tuner_attach: called to attach the possible tuners + * @frontend_ctrl: called to power on/off active frontend + * @streaming_ctrl: called to start/stop the usb streaming of adapter + * @fe_ioctl_override: frontend ioctl override. avoid using that is possible + * @init: called after adapters are created in order to finalize device + * configuration + * @exit: called when driver is unloaded + * @get_rc_config: called to resolve used remote controller configuration + * @get_stream_config: called to resolve input and output stream configuration + * of the adapter just before streaming is started. input stream is transport + * stream from the demodulator and output stream is usb stream to host. + */ +#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 +struct dvb_usb_device_properties { + const char *driver_name; + struct module *owner; + short *adapter_nr; + + u8 bInterfaceNumber; + unsigned int size_of_priv; + u8 generic_bulk_ctrl_endpoint; + u8 generic_bulk_ctrl_endpoint_response; + unsigned int generic_bulk_ctrl_delay; + +#define WARM 0 +#define COLD 1 + int (*identify_state) (struct dvb_usb_device *, const char **); + const char *firmware; +#define RECONNECTS_USB 1 + int (*download_firmware) (struct dvb_usb_device *, + const struct firmware *); + + struct i2c_algorithm *i2c_algo; + + unsigned int num_adapters; + int (*get_adapter_count) (struct dvb_usb_device *); + struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; + int (*power_ctrl) (struct dvb_usb_device *, int); + int (*read_config) (struct dvb_usb_device *d); + int (*read_mac_address) (struct dvb_usb_adapter *, u8 []); + int (*frontend_attach) (struct dvb_usb_adapter *); + int (*tuner_attach) (struct dvb_usb_adapter *); + int (*frontend_ctrl) (struct dvb_frontend *, int); + int (*streaming_ctrl) (struct dvb_frontend *, int); + int (*fe_ioctl_override) (struct dvb_frontend *, + unsigned int, void *, unsigned int); + int (*init) (struct dvb_usb_device *); + void (*exit) (struct dvb_usb_device *); + int (*get_rc_config) (struct dvb_usb_device *, struct dvb_usb_rc *); +#define DVB_USB_FE_TS_TYPE_188 0 +#define DVB_USB_FE_TS_TYPE_204 1 +#define DVB_USB_FE_TS_TYPE_RAW 2 + int (*get_stream_config) (struct dvb_frontend *, u8 *, + struct usb_data_stream_properties *); +}; + +/** + * generic object of an usb stream + * @buf_num: number of buffer allocated + * @buf_size: size of each buffer in buf_list + * @buf_list: array containing all allocate buffers for streaming + * @dma_addr: list of dma_addr_t for each buffer in buf_list + * + * @urbs_initialized: number of URBs initialized + * @urbs_submitted: number of URBs submitted + */ +#define MAX_NO_URBS_FOR_DATA_STREAM 10 +struct usb_data_stream { + struct usb_device *udev; + struct usb_data_stream_properties props; + +#define USB_STATE_INIT 0x00 +#define USB_STATE_URB_BUF 0x01 + u8 state; + + void (*complete) (struct usb_data_stream *, u8 *, size_t); + + struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM]; + int buf_num; + unsigned long buf_size; + u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM]; + dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM]; + + int urbs_initialized; + int urbs_submitted; + + void *user_priv; +}; + +/** + * dvb adapter object on dvb usb device + * @props: pointer to adapter properties + * @stream: adapter the usb data stream + * @id: index of this adapter (starting with 0) + * @ts_type: transport stream, input stream, type + * @pid_filtering: is hardware pid_filtering used or not + * @feed_count: current feed count + * @max_feed_count: maimum feed count device can handle + * @dvb_adap: adapter dvb_adapter + * @dmxdev: adapter dmxdev + * @demux: adapter software demuxer + * @dvb_net: adapter dvb_net interfaces + * @sync_mutex: mutex used to sync control and streaming of the adapter + * @fe: adapter frontends + * @fe_init: rerouted frontend-init function + * @fe_sleep: rerouted frontend-sleep function + */ +struct dvb_usb_adapter { + const struct dvb_usb_adapter_properties *props; + struct usb_data_stream stream; + u8 id; + u8 ts_type; + bool pid_filtering; + u8 feed_count; + u8 max_feed_count; + s8 active_fe; + + /* dvb */ + struct dvb_adapter dvb_adap; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dvb_net dvb_net; + struct mutex sync_mutex; + + struct dvb_frontend *fe[MAX_NO_OF_FE_PER_ADAP]; + int (*fe_init[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); + int (*fe_sleep[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); +}; + +/** + * dvb usb device object + * @props: device properties + * @name: device name + * @rc_map: name of rc codes table + * @udev: pointer to the device's struct usb_device + * @intf: pointer to the device's usb interface + * @rc: remote controller configuration + * @probe_work: work to defer .probe() + * @powered: indicated whether the device is power or not + * @usb_mutex: mutex for usb control messages + * @i2c_mutex: mutex for i2c-transfers + * @i2c_adap: device's i2c-adapter + * @rc_dev: rc device for the remote control + * @rc_query_work: work for polling remote + * @priv: private data of the actual driver (allocate by dvb usb, size defined + * in size_of_priv of dvb_usb_properties). + */ +struct dvb_usb_device { + const struct dvb_usb_device_properties *props; + const char *name; + const char *rc_map; + + struct usb_device *udev; + struct usb_interface *intf; + struct dvb_usb_rc rc; + struct work_struct probe_work; + pid_t work_pid; + int powered; + + /* locking */ + struct mutex usb_mutex; + + /* i2c */ + struct mutex i2c_mutex; + struct i2c_adapter i2c_adap; + + struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; + + /* remote control */ + struct rc_dev *rc_dev; + char rc_phys[64]; + struct delayed_work rc_query_work; + + void *priv; +}; + +extern int dvb_usbv2_probe(struct usb_interface *, + const struct usb_device_id *); +extern void dvb_usbv2_disconnect(struct usb_interface *); +extern int dvb_usbv2_suspend(struct usb_interface *, pm_message_t); +extern int dvb_usbv2_resume(struct usb_interface *); + +/* the generic read/write method for device control */ +extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16); +extern int dvb_usbv2_generic_write(struct dvb_usb_device *, u8 *, u16); + +#endif diff --git a/drivers/media/dvb/dvb-usb-v2/dvb_usb_common.h b/drivers/media/dvb/dvb-usb-v2/dvb_usb_common.h new file mode 100644 index 000000000000..45f07090d431 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/dvb_usb_common.h @@ -0,0 +1,35 @@ +/* + * DVB USB framework + * + * Copyright (C) 2004-6 Patrick Boettcher + * Copyright (C) 2012 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef DVB_USB_COMMON_H +#define DVB_USB_COMMON_H + +#include "dvb_usb.h" + +/* commonly used methods */ +extern int usb_urb_initv2(struct usb_data_stream *stream, + const struct usb_data_stream_properties *props); +extern int usb_urb_exitv2(struct usb_data_stream *stream); +extern int usb_urb_submitv2(struct usb_data_stream *stream, + struct usb_data_stream_properties *props); +extern int usb_urb_killv2(struct usb_data_stream *stream); + +#endif diff --git a/drivers/media/dvb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/dvb/dvb-usb-v2/dvb_usb_core.c new file mode 100644 index 000000000000..3224621e1f32 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/dvb_usb_core.c @@ -0,0 +1,999 @@ +/* + * DVB USB framework + * + * Copyright (C) 2004-6 Patrick Boettcher + * Copyright (C) 2012 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "dvb_usb_common.h" + +int dvb_usbv2_disable_rc_polling; +module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644); +MODULE_PARM_DESC(disable_rc_polling, + "disable remote control polling (default: 0)"); +static int dvb_usb_force_pid_filter_usage; +module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, + int, 0444); +MODULE_PARM_DESC(force_pid_filter_usage, "force all DVB USB devices to use a " \ + "PID filter, if any (default: 0)"); + +static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *name) +{ + int ret; + const struct firmware *fw; + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + if (!d->props->download_firmware) { + ret = -EINVAL; + goto err; + } + + ret = request_firmware(&fw, name, &d->udev->dev); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: Did not find the firmware file "\ + "'%s'. Please see linux/Documentation/dvb/ " \ + "for more details on firmware-problems. " \ + "Status %d\n", KBUILD_MODNAME, name, ret); + goto err; + } + + dev_info(&d->udev->dev, "%s: downloading firmware from file '%s'\n", + KBUILD_MODNAME, name); + + ret = d->props->download_firmware(d, fw); + release_firmware(fw); + if (ret < 0) + goto err; + + return ret; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usbv2_i2c_init(struct dvb_usb_device *d) +{ + int ret; + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + if (!d->props->i2c_algo) + return 0; + + strlcpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name)); + d->i2c_adap.algo = d->props->i2c_algo; + d->i2c_adap.dev.parent = &d->udev->dev; + i2c_set_adapdata(&d->i2c_adap, d); + + ret = i2c_add_adapter(&d->i2c_adap); + if (ret < 0) { + d->i2c_adap.algo = NULL; + dev_err(&d->udev->dev, "%s: i2c_add_adapter() failed=%d\n", + KBUILD_MODNAME, ret); + goto err; + } + + return 0; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usbv2_i2c_exit(struct dvb_usb_device *d) +{ + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + if (d->i2c_adap.algo) + i2c_del_adapter(&d->i2c_adap); + + return 0; +} + +static void dvb_usb_read_remote_control(struct work_struct *work) +{ + struct dvb_usb_device *d = container_of(work, + struct dvb_usb_device, rc_query_work.work); + int ret; + + /* + * When the parameter has been set to 1 via sysfs while the + * driver was running, or when bulk mode is enabled after IR init. + */ + if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode) + return; + + ret = d->rc.query(d); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: rc.query() failed=%d\n", + KBUILD_MODNAME, ret); + return; /* stop polling */ + } + + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->rc.interval)); +} + +static int dvb_usbv2_remote_init(struct dvb_usb_device *d) +{ + int ret; + struct rc_dev *dev; + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config) + return 0; + + d->rc.map_name = d->rc_map; + ret = d->props->get_rc_config(d, &d->rc); + if (ret < 0) + goto err; + + /* disable rc when there is no keymap defined */ + if (!d->rc.map_name) + return 0; + + dev = rc_allocate_device(); + if (!dev) { + ret = -ENOMEM; + goto err; + } + + dev->dev.parent = &d->udev->dev; + dev->input_name = d->name; + usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); + strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); + dev->input_phys = d->rc_phys; + usb_to_input_id(d->udev, &dev->input_id); + /* TODO: likely RC-core should took const char * */ + dev->driver_name = (char *) d->props->driver_name; + dev->map_name = d->rc.map_name; + dev->driver_type = d->rc.driver_type; + dev->allowed_protos = d->rc.allowed_protos; + dev->change_protocol = d->rc.change_protocol; + dev->priv = d; + + ret = rc_register_device(dev); + if (ret < 0) { + rc_free_device(dev); + goto err; + } + + d->rc_dev = dev; + + /* start polling if needed */ + if (d->rc.query && !d->rc.bulk_mode) { + /* initialize a work queue for handling polling */ + INIT_DELAYED_WORK(&d->rc_query_work, + dvb_usb_read_remote_control); + dev_info(&d->udev->dev, "%s: schedule remote query interval " \ + "to %d msecs\n", KBUILD_MODNAME, + d->rc.interval); + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->rc.interval)); + } + + return 0; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usbv2_remote_exit(struct dvb_usb_device *d) +{ + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + if (d->rc_dev) { + cancel_delayed_work_sync(&d->rc_query_work); + rc_unregister_device(d->rc_dev); + d->rc_dev = NULL; + } + + return 0; +} + +static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buf, + size_t len) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + dvb_dmx_swfilter(&adap->demux, buf, len); +} + +static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buf, + size_t len) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + dvb_dmx_swfilter_204(&adap->demux, buf, len); +} + +static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, u8 *buf, + size_t len) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + dvb_dmx_swfilter_raw(&adap->demux, buf, len); +} + +int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) +{ + dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, + adap->id); + + adap->stream.udev = adap_to_d(adap)->udev; + adap->stream.user_priv = adap; + adap->stream.complete = dvb_usb_data_complete; + + return usb_urb_initv2(&adap->stream, &adap->props->stream); +} + +int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap) +{ + dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, + adap->id); + + return usb_urb_exitv2(&adap->stream); +} + +static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, + int count) +{ + struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; + struct dvb_usb_device *d = adap_to_d(adap); + int ret; + dev_dbg(&d->udev->dev, "%s: adap=%d active_fe=%d feed_type=%d " \ + "setting pid [%s]: %04x (%04d) at index %d '%s'\n", + __func__, adap->id, adap->active_fe, dvbdmxfeed->type, + adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, + dvbdmxfeed->pid, dvbdmxfeed->index, + (count == 1) ? "on" : "off"); + + if (adap->active_fe == -1) + return -EINVAL; + + adap->feed_count += count; + + /* stop feeding if it is last pid */ + if (adap->feed_count == 0) { + dev_dbg(&d->udev->dev, "%s: stop feeding\n", __func__); + usb_urb_killv2(&adap->stream); + + if (d->props->streaming_ctrl) { + ret = d->props->streaming_ctrl( + adap->fe[adap->active_fe], 0); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: streaming_ctrl() " \ + "failed=%d\n", KBUILD_MODNAME, + ret); + goto err_mutex_unlock; + } + } + mutex_unlock(&adap->sync_mutex); + } + + /* activate the pid on the device pid filter */ + if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->pid_filtering && + adap->props->pid_filter) + ret = adap->props->pid_filter(adap, dvbdmxfeed->index, + dvbdmxfeed->pid, (count == 1) ? 1 : 0); + if (ret < 0) + dev_err(&d->udev->dev, "%s: pid_filter() " \ + "failed=%d\n", KBUILD_MODNAME, + ret); + + /* start feeding if it is first pid */ + if (adap->feed_count == 1 && count == 1) { + struct usb_data_stream_properties stream_props; + mutex_lock(&adap->sync_mutex); + dev_dbg(&d->udev->dev, "%s: start feeding\n", __func__); + + /* resolve input and output streaming paramters */ + if (d->props->get_stream_config) { + memcpy(&stream_props, &adap->props->stream, + sizeof(struct usb_data_stream_properties)); + ret = d->props->get_stream_config( + adap->fe[adap->active_fe], + &adap->ts_type, &stream_props); + if (ret < 0) + goto err_mutex_unlock; + } else { + stream_props = adap->props->stream; + } + + switch (adap->ts_type) { + case DVB_USB_FE_TS_TYPE_204: + adap->stream.complete = dvb_usb_data_complete_204; + break; + case DVB_USB_FE_TS_TYPE_RAW: + adap->stream.complete = dvb_usb_data_complete_raw; + break; + case DVB_USB_FE_TS_TYPE_188: + default: + adap->stream.complete = dvb_usb_data_complete; + break; + } + + usb_urb_submitv2(&adap->stream, &stream_props); + + if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->props->caps & + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && + adap->props->pid_filter_ctrl) { + ret = adap->props->pid_filter_ctrl(adap, + adap->pid_filtering); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: " \ + "pid_filter_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_mutex_unlock; + } + } + + if (d->props->streaming_ctrl) { + ret = d->props->streaming_ctrl( + adap->fe[adap->active_fe], 1); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: streaming_ctrl() " \ + "failed=%d\n", KBUILD_MODNAME, + ret); + goto err_mutex_unlock; + } + } + } + + return 0; +err_mutex_unlock: + mutex_unlock(&adap->sync_mutex); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + return dvb_usb_ctrl_feed(dvbdmxfeed, 1); +} + +static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + return dvb_usb_ctrl_feed(dvbdmxfeed, -1); +} + +int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) +{ + int ret; + struct dvb_usb_device *d = adap_to_d(adap); + dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id); + + ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner, + &d->udev->dev, d->props->adapter_nr); + if (ret < 0) { + dev_dbg(&d->udev->dev, "%s: dvb_register_adapter() failed=%d\n", + __func__, ret); + goto err_dvb_register_adapter; + } + + adap->dvb_adap.priv = adap; + + if (d->props->read_mac_address) { + ret = d->props->read_mac_address(adap, + adap->dvb_adap.proposed_mac); + if (ret < 0) + goto err_dvb_dmx_init; + + dev_info(&d->udev->dev, "%s: MAC address: %pM\n", + KBUILD_MODNAME, adap->dvb_adap.proposed_mac); + } + + adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; + adap->demux.priv = adap; + adap->demux.filternum = 0; + adap->demux.filternum = adap->max_feed_count; + adap->demux.feednum = adap->demux.filternum; + adap->demux.start_feed = dvb_usb_start_feed; + adap->demux.stop_feed = dvb_usb_stop_feed; + adap->demux.write_to_decoder = NULL; + ret = dvb_dmx_init(&adap->demux); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: dvb_dmx_init() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_dvb_dmx_init; + } + + adap->dmxdev.filternum = adap->demux.filternum; + adap->dmxdev.demux = &adap->demux.dmx; + adap->dmxdev.capabilities = 0; + ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: dvb_dmxdev_init() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_dvb_dmxdev_init; + } + + ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: dvb_net_init() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_dvb_net_init; + } + + mutex_init(&adap->sync_mutex); + + return 0; +err_dvb_net_init: + dvb_dmxdev_release(&adap->dmxdev); +err_dvb_dmxdev_init: + dvb_dmx_release(&adap->demux); +err_dvb_dmx_init: + dvb_unregister_adapter(&adap->dvb_adap); +err_dvb_register_adapter: + adap->dvb_adap.priv = NULL; + return ret; +} + +int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap) +{ + dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, + adap->id); + + if (adap->dvb_adap.priv) { + dvb_net_release(&adap->dvb_net); + adap->demux.dmx.close(&adap->demux.dmx); + dvb_dmxdev_release(&adap->dmxdev); + dvb_dmx_release(&adap->demux); + dvb_unregister_adapter(&adap->dvb_adap); + } + + return 0; +} + +int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + + if (onoff) + d->powered++; + else + d->powered--; + + if (d->powered == 0 || (onoff && d->powered == 1)) { + /* when switching from 1 to 0 or from 0 to 1 */ + dev_dbg(&d->udev->dev, "%s: power=%d\n", __func__, onoff); + if (d->props->power_ctrl) { + ret = d->props->power_ctrl(d, onoff); + if (ret < 0) + goto err; + } + } + + return 0; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usb_fe_init(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *d = adap_to_d(adap); + mutex_lock(&adap->sync_mutex); + dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id, + fe->id); + + ret = dvb_usbv2_device_power_ctrl(d, 1); + if (ret < 0) + goto err; + + if (d->props->frontend_ctrl) { + ret = d->props->frontend_ctrl(fe, 1); + if (ret < 0) + goto err; + } + + if (adap->fe_init[fe->id]) { + ret = adap->fe_init[fe->id](fe); + if (ret < 0) + goto err; + } + + adap->active_fe = fe->id; + mutex_unlock(&adap->sync_mutex); + + return 0; +err: + mutex_unlock(&adap->sync_mutex); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usb_fe_sleep(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *d = adap_to_d(adap); + mutex_lock(&adap->sync_mutex); + dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id, + fe->id); + + if (adap->fe_sleep[fe->id]) { + ret = adap->fe_sleep[fe->id](fe); + if (ret < 0) + goto err; + } + + if (d->props->frontend_ctrl) { + ret = d->props->frontend_ctrl(fe, 0); + if (ret < 0) + goto err; + } + + ret = dvb_usbv2_device_power_ctrl(d, 0); + if (ret < 0) + goto err; + + adap->active_fe = -1; + mutex_unlock(&adap->sync_mutex); + + return 0; +err: + mutex_unlock(&adap->sync_mutex); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) +{ + int ret, i, count_registered = 0; + struct dvb_usb_device *d = adap_to_d(adap); + dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id); + + memset(adap->fe, 0, sizeof(adap->fe)); + adap->active_fe = -1; + + if (d->props->frontend_attach) { + ret = d->props->frontend_attach(adap); + if (ret < 0) { + dev_dbg(&d->udev->dev, "%s: frontend_attach() " \ + "failed=%d\n", __func__, ret); + goto err_dvb_frontend_detach; + } + } else { + dev_dbg(&d->udev->dev, "%s: frontend_attach() do not exists\n", + __func__); + ret = 0; + goto err; + } + + for (i = 0; i < MAX_NO_OF_FE_PER_ADAP && adap->fe[i]; i++) { + adap->fe[i]->id = i; + /* re-assign sleep and wakeup functions */ + adap->fe_init[i] = adap->fe[i]->ops.init; + adap->fe[i]->ops.init = dvb_usb_fe_init; + adap->fe_sleep[i] = adap->fe[i]->ops.sleep; + adap->fe[i]->ops.sleep = dvb_usb_fe_sleep; + + ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: frontend%d registration " \ + "failed\n", KBUILD_MODNAME, i); + goto err_dvb_unregister_frontend; + } + + count_registered++; + } + + if (d->props->tuner_attach) { + ret = d->props->tuner_attach(adap); + if (ret < 0) { + dev_dbg(&d->udev->dev, "%s: tuner_attach() failed=%d\n", + __func__, ret); + goto err_dvb_unregister_frontend; + } + } + + return 0; + +err_dvb_unregister_frontend: + for (i = count_registered - 1; i >= 0; i--) + dvb_unregister_frontend(adap->fe[i]); + +err_dvb_frontend_detach: + for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { + if (adap->fe[i]) + dvb_frontend_detach(adap->fe[i]); + } + +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap) +{ + int i; + dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, + adap->id); + + for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { + if (adap->fe[i]) { + dvb_unregister_frontend(adap->fe[i]); + dvb_frontend_detach(adap->fe[i]); + } + } + + return 0; +} + +static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) +{ + struct dvb_usb_adapter *adap; + int ret, i, adapter_count; + + /* resolve adapter count */ + adapter_count = d->props->num_adapters; + if (d->props->get_adapter_count) { + ret = d->props->get_adapter_count(d); + if (ret < 0) + goto err; + + adapter_count = ret; + } + + for (i = 0; i < adapter_count; i++) { + adap = &d->adapter[i]; + adap->id = i; + adap->props = &d->props->adapter[i]; + + /* speed - when running at FULL speed we need a HW PID filter */ + if (d->udev->speed == USB_SPEED_FULL && + !(adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) { + dev_err(&d->udev->dev, "%s: this USB2.0 device " \ + "cannot be run on a USB1.1 port (it " \ + "lacks a hardware PID filter)\n", + KBUILD_MODNAME); + ret = -ENODEV; + goto err; + } else if ((d->udev->speed == USB_SPEED_FULL && + adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) || + (adap->props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { + dev_info(&d->udev->dev, "%s: will use the device's " \ + "hardware PID filter " \ + "(table count: %d)\n", KBUILD_MODNAME, + adap->props->pid_filter_count); + adap->pid_filtering = 1; + adap->max_feed_count = adap->props->pid_filter_count; + } else { + dev_info(&d->udev->dev, "%s: will pass the complete " \ + "MPEG2 transport stream to the " \ + "software demuxer\n", KBUILD_MODNAME); + adap->pid_filtering = 0; + adap->max_feed_count = 255; + } + + if (!adap->pid_filtering && dvb_usb_force_pid_filter_usage && + adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) { + dev_info(&d->udev->dev, "%s: PID filter enabled by " \ + "module option\n", KBUILD_MODNAME); + adap->pid_filtering = 1; + adap->max_feed_count = adap->props->pid_filter_count; + } + + ret = dvb_usbv2_adapter_stream_init(adap); + if (ret) + goto err; + + ret = dvb_usbv2_adapter_dvb_init(adap); + if (ret) + goto err; + + ret = dvb_usbv2_adapter_frontend_init(adap); + if (ret) + goto err; + + /* use exclusive FE lock if there is multiple shared FEs */ + if (adap->fe[1]) + adap->dvb_adap.mfe_shared = 1; + + adap->dvb_adap.fe_ioctl_override = d->props->fe_ioctl_override; + } + + return 0; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) +{ + int i; + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { + if (d->adapter[i].props) { + dvb_usbv2_adapter_frontend_exit(&d->adapter[i]); + dvb_usbv2_adapter_dvb_exit(&d->adapter[i]); + dvb_usbv2_adapter_stream_exit(&d->adapter[i]); + } + } + + return 0; +} + +/* general initialization functions */ +static int dvb_usbv2_exit(struct dvb_usb_device *d) +{ + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + dvb_usbv2_remote_exit(d); + dvb_usbv2_adapter_exit(d); + dvb_usbv2_i2c_exit(d); + kfree(d->priv); + kfree(d); + + return 0; +} + +static int dvb_usbv2_init(struct dvb_usb_device *d) +{ + int ret; + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + dvb_usbv2_device_power_ctrl(d, 1); + + if (d->props->read_config) { + ret = d->props->read_config(d); + if (ret < 0) + goto err; + } + + ret = dvb_usbv2_i2c_init(d); + if (ret < 0) + goto err; + + ret = dvb_usbv2_adapter_init(d); + if (ret < 0) + goto err; + + if (d->props->init) { + ret = d->props->init(d); + if (ret < 0) + goto err; + } + + ret = dvb_usbv2_remote_init(d); + if (ret < 0) + goto err; + + dvb_usbv2_device_power_ctrl(d, 0); + + return 0; +err: + dvb_usbv2_device_power_ctrl(d, 0); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +/* + * udev, which is used for the firmware downloading, requires we cannot + * block during module_init(). module_init() calls USB probe() which + * is this routine. Due to that we delay actual operation using workqueue + * and return always success here. + */ +static void dvb_usbv2_init_work(struct work_struct *work) +{ + int ret; + struct dvb_usb_device *d = + container_of(work, struct dvb_usb_device, probe_work); + + d->work_pid = current->pid; + dev_dbg(&d->udev->dev, "%s: work_pid=%d\n", __func__, d->work_pid); + + if (d->props->size_of_priv) { + d->priv = kzalloc(d->props->size_of_priv, GFP_KERNEL); + if (!d->priv) { + dev_err(&d->udev->dev, "%s: kzalloc() failed\n", + KBUILD_MODNAME); + ret = -ENOMEM; + goto err_usb_driver_release_interface; + } + } + + if (d->props->identify_state) { + const char *name = NULL; + ret = d->props->identify_state(d, &name); + if (ret == 0) { + ; + } else if (ret == COLD) { + dev_info(&d->udev->dev, "%s: found a '%s' in cold " \ + "state\n", KBUILD_MODNAME, d->name); + + if (!name) + name = d->props->firmware; + + ret = dvb_usbv2_download_firmware(d, name); + if (ret == 0) { + /* device is warm, continue initialization */ + ; + } else if (ret == RECONNECTS_USB) { + /* + * USB core will call disconnect() and then + * probe() as device reconnects itself from the + * USB bus. disconnect() will release all driver + * resources and probe() is called for 'new' + * device. As 'new' device is warm we should + * never go here again. + */ + return; + } else { + /* + * Unexpected error. We must unregister driver + * manually from the device, because device is + * already register by returning from probe() + * with success. usb_driver_release_interface() + * finally calls disconnect() in order to free + * resources. + */ + goto err_usb_driver_release_interface; + } + } else { + goto err_usb_driver_release_interface; + } + } + + dev_info(&d->udev->dev, "%s: found a '%s' in warm state\n", + KBUILD_MODNAME, d->name); + + ret = dvb_usbv2_init(d); + if (ret < 0) + goto err_usb_driver_release_interface; + + dev_info(&d->udev->dev, "%s: '%s' successfully initialized and " \ + "connected\n", KBUILD_MODNAME, d->name); + + return; +err_usb_driver_release_interface: + dev_info(&d->udev->dev, "%s: '%s' error while loading driver (%d)\n", + KBUILD_MODNAME, d->name, ret); + usb_driver_release_interface(to_usb_driver(d->intf->dev.driver), + d->intf); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return; +} + +int dvb_usbv2_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret; + struct dvb_usb_device *d; + struct usb_device *udev = interface_to_usbdev(intf); + struct dvb_usb_driver_info *driver_info = + (struct dvb_usb_driver_info *) id->driver_info; + + dev_dbg(&udev->dev, "%s: bInterfaceNumber=%d\n", __func__, + intf->cur_altsetting->desc.bInterfaceNumber); + + if (!id->driver_info) { + dev_err(&udev->dev, "%s: driver_info failed\n", KBUILD_MODNAME); + ret = -ENODEV; + goto err; + } + + d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); + if (!d) { + dev_err(&udev->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); + ret = -ENOMEM; + goto err; + } + + d->name = driver_info->name; + d->rc_map = driver_info->rc_map; + d->udev = udev; + d->intf = intf; + d->props = driver_info->props; + + if (d->intf->cur_altsetting->desc.bInterfaceNumber != + d->props->bInterfaceNumber) { + ret = -ENODEV; + goto err_kfree; + } + + mutex_init(&d->usb_mutex); + mutex_init(&d->i2c_mutex); + INIT_WORK(&d->probe_work, dvb_usbv2_init_work); + usb_set_intfdata(intf, d); + ret = schedule_work(&d->probe_work); + if (ret < 0) { + dev_err(&d->udev->dev, "%s: schedule_work() failed\n", + KBUILD_MODNAME); + goto err_kfree; + } + + return 0; +err_kfree: + kfree(d); +err: + dev_dbg(&udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} +EXPORT_SYMBOL(dvb_usbv2_probe); + +void dvb_usbv2_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + const char *name = d->name; + struct device dev = d->udev->dev; + dev_dbg(&d->udev->dev, "%s: pid=%d work_pid=%d\n", __func__, + current->pid, d->work_pid); + + /* ensure initialization work is finished until release resources */ + if (d->work_pid != current->pid) + cancel_work_sync(&d->probe_work); + + if (d->props->exit) + d->props->exit(d); + + dvb_usbv2_exit(d); + + dev_info(&dev, "%s: '%s' successfully deinitialized and disconnected\n", + KBUILD_MODNAME, name); +} +EXPORT_SYMBOL(dvb_usbv2_disconnect); + +int dvb_usbv2_suspend(struct usb_interface *intf, pm_message_t msg) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + int i; + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + /* stop remote controller poll */ + if (d->rc.query && !d->rc.bulk_mode) + cancel_delayed_work_sync(&d->rc_query_work); + + /* stop streaming */ + for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { + if (d->adapter[i].dvb_adap.priv && + d->adapter[i].active_fe != -1) + usb_urb_killv2(&d->adapter[i].stream); + } + + return 0; +} +EXPORT_SYMBOL(dvb_usbv2_suspend); + +int dvb_usbv2_resume(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + int i; + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + /* start streaming */ + for (i = 0; i < MAX_NO_OF_ADAPTER_PER_DEVICE; i++) { + if (d->adapter[i].dvb_adap.priv && + d->adapter[i].active_fe != -1) + usb_urb_submitv2(&d->adapter[i].stream, NULL); + } + + /* start remote controller poll */ + if (d->rc.query && !d->rc.bulk_mode) + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->rc.interval)); + + return 0; +} +EXPORT_SYMBOL(dvb_usbv2_resume); + +MODULE_VERSION("2.0"); +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("DVB USB common"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/dvb_usb_firmware.c b/drivers/media/dvb/dvb-usb-v2/dvb_usb_firmware.c new file mode 100644 index 000000000000..61c3fe9a599e --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/dvb_usb_firmware.c @@ -0,0 +1,125 @@ +/* dvb_usb_firmware.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for downloading the firmware to Cypress FX 1 + * and 2 based devices. + * + */ + +#include "dvb_usb.h" +#include "dvb_usb_firmware.h" + +struct usb_cypress_controller { + u8 id; + const char *name; /* name of the usb controller */ + u16 cs_reg; /* needs to be restarted, + * when the firmware has been downloaded */ +}; + +static const struct usb_cypress_controller cypress[] = { + { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cs_reg = 0x7f92 }, + { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cs_reg = 0x7f92 }, + { .id = CYPRESS_FX2, .name = "Cypress FX2", .cs_reg = 0xe600 }, +}; + +/* + * load a firmware packet to the device + */ +static int usb_cypress_writemem(struct usb_device *udev, u16 addr, u8 *data, + u8 len) +{ + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000); +} + +int usbv2_cypress_load_firmware(struct usb_device *udev, + const struct firmware *fw, int type) +{ + struct hexline hx; + u8 reset; + int ret, pos = 0; + + /* stop the CPU */ + reset = 1; + ret = usb_cypress_writemem(udev, cypress[type].cs_reg, &reset, 1); + if (ret != 1) + pr_err("%s: could not stop the USB controller CPU", + KBUILD_MODNAME); + + while ((ret = dvb_usbv2_get_hexline(fw, &hx, &pos)) > 0) { + pr_debug("%s: writing to address %04x (buffer: %02x %02x)\n", + __func__, hx.addr, hx.len, hx.chk); + + ret = usb_cypress_writemem(udev, hx.addr, hx.data, hx.len); + if (ret != hx.len) { + pr_err("%s: error while transferring firmware " \ + "(transferred size=%d, block size=%d)", + KBUILD_MODNAME, ret, hx.len); + ret = -EINVAL; + break; + } + } + if (ret < 0) { + pr_err("%s: firmware download failed at %d with %d", + KBUILD_MODNAME, pos, ret); + return ret; + } + + if (ret == 0) { + /* restart the CPU */ + reset = 0; + if (ret || usb_cypress_writemem( + udev, cypress[type].cs_reg, &reset, 1) != 1) { + pr_err("%s: could not restart the USB controller CPU", + KBUILD_MODNAME); + ret = -EINVAL; + } + } else + ret = -EIO; + + return ret; +} +EXPORT_SYMBOL(usbv2_cypress_load_firmware); + +int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx, + int *pos) +{ + u8 *b = (u8 *) &fw->data[*pos]; + int data_offs = 4; + + if (*pos >= fw->size) + return 0; + + memset(hx, 0, sizeof(struct hexline)); + + hx->len = b[0]; + + if ((*pos + hx->len + 4) >= fw->size) + return -EINVAL; + + hx->addr = b[1] | (b[2] << 8); + hx->type = b[3]; + + if (hx->type == 0x04) { + /* b[4] and b[5] are the Extended linear address record data + * field */ + hx->addr |= (b[4] << 24) | (b[5] << 16); + /* + hx->len -= 2; + data_offs += 2; + */ + } + memcpy(hx->data, &b[data_offs], hx->len); + hx->chk = b[hx->len + data_offs]; + + *pos += hx->len + 5; + + return *pos; +} +EXPORT_SYMBOL(dvb_usbv2_get_hexline); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Cypress firmware download"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/dvb_usb_firmware.h b/drivers/media/dvb/dvb-usb-v2/dvb_usb_firmware.h new file mode 100644 index 000000000000..358d9d0b1899 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/dvb_usb_firmware.h @@ -0,0 +1,31 @@ +/* dvb_usb_firmware.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for downloading the firmware to Cypress FX 1 + * and 2 based devices. + * + */ + +#ifndef DVB_USB_FIRMWARE_H +#define DVB_USB_FIRMWARE_H + +#define CYPRESS_AN2135 0 +#define CYPRESS_AN2235 1 +#define CYPRESS_FX2 2 + +/* commonly used firmware download types and function */ +struct hexline { + u8 len; + u32 addr; + u8 type; + u8 data[255]; + u8 chk; +}; +extern int usbv2_cypress_load_firmware(struct usb_device *, + const struct firmware *, int); +extern int dvb_usbv2_get_hexline(const struct firmware *, + struct hexline *, int *); + +#endif diff --git a/drivers/media/dvb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb-v2/dvb_usb_urb.c new file mode 100644 index 000000000000..5f5bdd0c4c9d --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/dvb_usb_urb.c @@ -0,0 +1,83 @@ +/* + * DVB USB framework + * + * Copyright (C) 2004-6 Patrick Boettcher + * Copyright (C) 2012 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "dvb_usb_common.h" + +#undef DVB_USB_XFER_DEBUG +int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, + u16 rlen) +{ + int ret, actual_length; + + if (!d || !wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint || + !d->props->generic_bulk_ctrl_endpoint_response) { + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, -EINVAL); + return -EINVAL; + } + + ret = mutex_lock_interruptible(&d->usb_mutex); + if (ret < 0) + return ret; + +#ifdef DVB_USB_XFER_DEBUG + print_hex_dump(KERN_DEBUG, KBUILD_MODNAME ": >>> ", DUMP_PREFIX_NONE, + 32, 1, wbuf, wlen, 0); +#endif + ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev, + d->props->generic_bulk_ctrl_endpoint), wbuf, wlen, + &actual_length, 2000); + if (ret < 0) + dev_err(&d->udev->dev, "%s: usb_bulk_msg() failed=%d\n", + KBUILD_MODNAME, ret); + else + ret = actual_length != wlen ? -EIO : 0; + + /* an answer is expected, and no error before */ + if (!ret && rbuf && rlen) { + if (d->props->generic_bulk_ctrl_delay) + usleep_range(d->props->generic_bulk_ctrl_delay, + d->props->generic_bulk_ctrl_delay + + 20000); + + ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, + d->props->generic_bulk_ctrl_endpoint_response), + rbuf, rlen, &actual_length, 2000); + if (ret) + dev_err(&d->udev->dev, "%s: 2nd usb_bulk_msg() " \ + "failed=%d\n", KBUILD_MODNAME, ret); + +#ifdef DVB_USB_XFER_DEBUG + print_hex_dump(KERN_DEBUG, KBUILD_MODNAME ": <<< ", + DUMP_PREFIX_NONE, 32, 1, rbuf, actual_length, + 0); +#endif + } + + mutex_unlock(&d->usb_mutex); + return ret; +} +EXPORT_SYMBOL(dvb_usbv2_generic_rw); + +int dvb_usbv2_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) +{ + return dvb_usbv2_generic_rw(d, buf, len, NULL, 0); +} +EXPORT_SYMBOL(dvb_usbv2_generic_write); diff --git a/drivers/media/dvb/dvb-usb-v2/ec168.c b/drivers/media/dvb/dvb-usb-v2/ec168.c new file mode 100644 index 000000000000..ab77622c383d --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/ec168.c @@ -0,0 +1,376 @@ +/* + * E3C EC168 DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "ec168.h" +#include "ec100.h" +#include "mxl5005s.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req) +{ + int ret; + unsigned int pipe; + u8 request, requesttype; + u8 *buf; + + switch (req->cmd) { + case DOWNLOAD_FIRMWARE: + case GPIO: + case WRITE_I2C: + case STREAMING_CTRL: + requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); + request = req->cmd; + break; + case READ_I2C: + requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); + request = req->cmd; + break; + case GET_CONFIG: + requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); + request = CONFIG; + break; + case SET_CONFIG: + requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); + request = CONFIG; + break; + case WRITE_DEMOD: + requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); + request = DEMOD_RW; + break; + case READ_DEMOD: + requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); + request = DEMOD_RW; + break; + default: + pr_err("%s: unknown command=%02x\n", KBUILD_MODNAME, req->cmd); + ret = -EINVAL; + goto error; + } + + buf = kmalloc(req->size, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto error; + } + + if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) { + /* write */ + memcpy(buf, req->data, req->size); + pipe = usb_sndctrlpipe(d->udev, 0); + } else { + /* read */ + pipe = usb_rcvctrlpipe(d->udev, 0); + } + + msleep(1); /* avoid I2C errors */ + + ret = usb_control_msg(d->udev, pipe, request, requesttype, req->value, + req->index, buf, req->size, EC168_USB_TIMEOUT); + + ec168_debug_dump(request, requesttype, req->value, req->index, buf, + req->size); + + if (ret < 0) + goto err_dealloc; + else + ret = 0; + + /* read request, copy returned data to return buf */ + if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) + memcpy(req->data, buf, req->size); + + kfree(buf); + return ret; + +err_dealloc: + kfree(buf); +error: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +/* I2C */ +static struct ec100_config ec168_ec100_config; + +static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct ec168_req req; + int i = 0; + int ret; + + if (num > 2) + return -EINVAL; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + while (i < num) { + if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { + if (msg[i].addr == ec168_ec100_config.demod_address) { + req.cmd = READ_DEMOD; + req.value = 0; + req.index = 0xff00 + msg[i].buf[0]; /* reg */ + req.size = msg[i+1].len; /* bytes to read */ + req.data = &msg[i+1].buf[0]; + ret = ec168_ctrl_msg(d, &req); + i += 2; + } else { + pr_err("%s: I2C read not implemented\n", + KBUILD_MODNAME); + ret = -EOPNOTSUPP; + i += 2; + } + } else { + if (msg[i].addr == ec168_ec100_config.demod_address) { + req.cmd = WRITE_DEMOD; + req.value = msg[i].buf[1]; /* val */ + req.index = 0xff00 + msg[i].buf[0]; /* reg */ + req.size = 0; + req.data = NULL; + ret = ec168_ctrl_msg(d, &req); + i += 1; + } else { + req.cmd = WRITE_I2C; + req.value = msg[i].buf[0]; /* val */ + req.index = 0x0100 + msg[i].addr; /* I2C addr */ + req.size = msg[i].len-1; + req.data = &msg[i].buf[1]; + ret = ec168_ctrl_msg(d, &req); + i += 1; + } + } + if (ret) + goto error; + + } + ret = i; + +error: + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 ec168_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm ec168_i2c_algo = { + .master_xfer = ec168_i2c_xfer, + .functionality = ec168_i2c_func, +}; + +/* Callbacks for DVB USB */ +static int ec168_identify_state(struct dvb_usb_device *d, const char **name) +{ + int ret; + u8 reply; + struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply}; + pr_debug("%s:\n", __func__); + + ret = ec168_ctrl_msg(d, &req); + if (ret) + goto error; + + pr_debug("%s: reply=%02x\n", __func__, reply); + + if (reply == 0x01) + ret = WARM; + else + ret = COLD; + + return ret; +error: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int ec168_download_firmware(struct dvb_usb_device *d, + const struct firmware *fw) +{ + int ret, len, remaining; + struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL}; + pr_debug("%s:\n", __func__); + + #define LEN_MAX 2048 /* max packet size */ + for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { + len = remaining; + if (len > LEN_MAX) + len = LEN_MAX; + + req.size = len; + req.data = (u8 *) &fw->data[fw->size - remaining]; + req.index = fw->size - remaining; + + ret = ec168_ctrl_msg(d, &req); + if (ret) { + pr_err("%s: firmware download failed=%d\n", + KBUILD_MODNAME, ret); + goto error; + } + } + + req.size = 0; + + /* set "warm"? */ + req.cmd = SET_CONFIG; + req.value = 0; + req.index = 0x0001; + ret = ec168_ctrl_msg(d, &req); + if (ret) + goto error; + + /* really needed - no idea what does */ + req.cmd = GPIO; + req.value = 0; + req.index = 0x0206; + ret = ec168_ctrl_msg(d, &req); + if (ret) + goto error; + + /* activate tuner I2C? */ + req.cmd = WRITE_I2C; + req.value = 0; + req.index = 0x00c6; + ret = ec168_ctrl_msg(d, &req); + if (ret) + goto error; + + return ret; +error: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static struct ec100_config ec168_ec100_config = { + .demod_address = 0xff, /* not real address, demod is integrated */ +}; + +static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap) +{ + pr_debug("%s:\n", __func__); + adap->fe[0] = dvb_attach(ec100_attach, &ec168_ec100_config, + &adap_to_d(adap)->i2c_adap); + if (adap->fe[0] == NULL) + return -ENODEV; + + return 0; +} + +static struct mxl5005s_config ec168_mxl5003s_config = { + .i2c_address = 0xc6, + .if_freq = IF_FREQ_4570000HZ, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_OFF, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) +{ + pr_debug("%s:\n", __func__); + return dvb_attach(mxl5005s_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + &ec168_mxl5003s_config) == NULL ? -ENODEV : 0; +} + +static int ec168_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL}; + pr_debug("%s: onoff=%d\n", __func__, onoff); + if (onoff) + req.index = 0x0102; + return ec168_ctrl_msg(fe_to_d(fe), &req); +} + +/* DVB USB Driver stuff */ +/* bInterfaceNumber 0 is HID + * bInterfaceNumber 1 is DVB-T */ +static struct dvb_usb_device_properties ec168_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .bInterfaceNumber = 1, + + .identify_state = ec168_identify_state, + .firmware = "dvb-usb-ec168.fw", + .download_firmware = ec168_download_firmware, + + .i2c_algo = &ec168_i2c_algo, + .frontend_attach = ec168_ec100_frontend_attach, + .tuner_attach = ec168_mxl5003s_tuner_attach, + .streaming_ctrl = ec168_streaming_ctrl, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_BULK(0x82, 6, 32 * 512), + } + }, +}; + +static const struct dvb_usb_driver_info ec168_driver_info = { + .name = "E3C EC168 reference design", + .props = &ec168_props, +}; + +static const struct usb_device_id ec168_id[] = { + { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168), + .driver_info = (kernel_ulong_t) &ec168_driver_info }, + { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2), + .driver_info = (kernel_ulong_t) &ec168_driver_info }, + { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3), + .driver_info = (kernel_ulong_t) &ec168_driver_info }, + { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4), + .driver_info = (kernel_ulong_t) &ec168_driver_info }, + { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5), + .driver_info = (kernel_ulong_t) &ec168_driver_info }, + {} +}; +MODULE_DEVICE_TABLE(usb, ec168_id); + +static struct usb_driver ec168_driver = { + .name = KBUILD_MODNAME, + .id_table = ec168_id, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(ec168_driver); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("E3C EC168 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/ec168.h b/drivers/media/dvb/dvb-usb-v2/ec168.h new file mode 100644 index 000000000000..9181236f6ebc --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/ec168.h @@ -0,0 +1,63 @@ +/* + * E3C EC168 DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef EC168_H +#define EC168_H + +#include "dvb_usb.h" + +#define ec168_debug_dump(r, t, v, i, b, l) { \ + char *direction; \ + if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ + direction = ">>>"; \ + else \ + direction = "<<<"; \ + pr_debug("%s: %02x %02x %02x %02x %02x %02x %02x %02x %s\n", \ + __func__, t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, \ + l & 0xff, l >> 8, direction); \ +} + +#define EC168_USB_TIMEOUT 1000 + +struct ec168_req { + u8 cmd; /* [1] */ + u16 value; /* [2|3] */ + u16 index; /* [4|5] */ + u16 size; /* [6|7] */ + u8 *data; +}; + +enum ec168_cmd { + DOWNLOAD_FIRMWARE = 0x00, + CONFIG = 0x01, + DEMOD_RW = 0x03, + GPIO = 0x04, + STREAMING_CTRL = 0x10, + READ_I2C = 0x20, + WRITE_I2C = 0x21, + HID_DOWNLOAD = 0x30, + GET_CONFIG, + SET_CONFIG, + READ_DEMOD, + WRITE_DEMOD, +}; + +#endif diff --git a/drivers/media/dvb/dvb-usb-v2/gl861.c b/drivers/media/dvb/dvb-usb-v2/gl861.c new file mode 100644 index 000000000000..cf29f43e3598 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/gl861.c @@ -0,0 +1,175 @@ +/* DVB USB compliant linux driver for GL861 USB2.0 devices. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "gl861.h" + +#include "zl10353.h" +#include "qt1010.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + u16 index; + u16 value = addr << (8 + 1); + int wo = (rbuf == NULL || rlen == 0); /* write-only */ + u8 req, type; + + if (wo) { + req = GL861_REQ_I2C_WRITE; + type = GL861_WRITE; + } else { /* rw */ + req = GL861_REQ_I2C_READ; + type = GL861_READ; + } + + switch (wlen) { + case 1: + index = wbuf[0]; + break; + case 2: + index = wbuf[0]; + value = value + wbuf[1]; + break; + default: + pr_err("%s: wlen=%d, aborting\n", KBUILD_MODNAME, wlen); + return -EINVAL; + } + + msleep(1); /* avoid I2C errors */ + + return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type, + value, index, rbuf, rlen, 2000); +} + +/* I2C */ +static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + if (num > 2) + return -EINVAL; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + /* write/read request */ + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf, + msg[i].len, msg[i+1].buf, msg[i+1].len) < 0) + break; + i++; + } else + if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf, + msg[i].len, NULL, 0) < 0) + break; + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 gl861_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm gl861_i2c_algo = { + .master_xfer = gl861_i2c_xfer, + .functionality = gl861_i2c_func, +}; + +/* Callbacks for DVB USB */ +static struct zl10353_config gl861_zl10353_config = { + .demod_address = 0x0f, + .no_tuner = 1, + .parallel_ts = 1, +}; + +static int gl861_frontend_attach(struct dvb_usb_adapter *adap) +{ + + adap->fe[0] = dvb_attach(zl10353_attach, &gl861_zl10353_config, + &adap_to_d(adap)->i2c_adap); + if (adap->fe[0] == NULL) + return -EIO; + + return 0; +} + +static struct qt1010_config gl861_qt1010_config = { + .i2c_address = 0x62 +}; + +static int gl861_tuner_attach(struct dvb_usb_adapter *adap) +{ + return dvb_attach(qt1010_attach, + adap->fe[0], &adap_to_d(adap)->i2c_adap, + &gl861_qt1010_config) == NULL ? -ENODEV : 0; +} + +static int gl861_init(struct dvb_usb_device *d) +{ + /* + * There is 2 interfaces. Interface 0 is for TV and interface 1 is + * for HID remote controller. Interface 0 has 2 alternate settings. + * For some reason we need to set interface explicitly, defaulted + * as alternate setting 1? + */ + return usb_set_interface(d->udev, 0, 0); +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties gl861_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + + .i2c_algo = &gl861_i2c_algo, + .frontend_attach = gl861_frontend_attach, + .tuner_attach = gl861_tuner_attach, + .init = gl861_init, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_BULK(0x81, 7, 512), + } + } +}; + +static const struct usb_device_id gl861_id_table[] = { + { DVB_USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801, + &gl861_props, "MSI Mega Sky 55801 DVB-T USB2.0", NULL) }, + { DVB_USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU, + &gl861_props, "A-LINK DTU DVB-T USB2.0", NULL) }, + { } +}; +MODULE_DEVICE_TABLE(usb, gl861_id_table); + +static struct usb_driver gl861_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = gl861_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(gl861_usb_driver); + +MODULE_AUTHOR("Carl Lundqvist "); +MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861"); +MODULE_VERSION("0.1"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb-v2/gl861.h b/drivers/media/dvb/dvb-usb-v2/gl861.h new file mode 100644 index 000000000000..b0b80d87bb7e --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/gl861.h @@ -0,0 +1,12 @@ +#ifndef _DVB_USB_GL861_H_ +#define _DVB_USB_GL861_H_ + +#include "dvb_usb.h" + +#define GL861_WRITE 0x40 +#define GL861_READ 0xc0 + +#define GL861_REQ_I2C_WRITE 0x01 +#define GL861_REQ_I2C_READ 0x02 + +#endif diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.c new file mode 100644 index 000000000000..d83df4bb72d3 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.c @@ -0,0 +1,612 @@ +/* + * mxl111sf-demod.c - driver for the MaxLinear MXL111SF DVB-T demodulator + * + * Copyright (C) 2010 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "mxl111sf-demod.h" +#include "mxl111sf-reg.h" + +/* debug */ +static int mxl111sf_demod_debug; +module_param_named(debug, mxl111sf_demod_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); + +#define mxl_dbg(fmt, arg...) \ + if (mxl111sf_demod_debug) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +/* ------------------------------------------------------------------------ */ + +struct mxl111sf_demod_state { + struct mxl111sf_state *mxl_state; + + struct mxl111sf_demod_config *cfg; + + struct dvb_frontend fe; +}; + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_demod_read_reg(struct mxl111sf_demod_state *state, + u8 addr, u8 *data) +{ + return (state->cfg->read_reg) ? + state->cfg->read_reg(state->mxl_state, addr, data) : + -EINVAL; +} + +static int mxl111sf_demod_write_reg(struct mxl111sf_demod_state *state, + u8 addr, u8 data) +{ + return (state->cfg->write_reg) ? + state->cfg->write_reg(state->mxl_state, addr, data) : + -EINVAL; +} + +static +int mxl111sf_demod_program_regs(struct mxl111sf_demod_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info) +{ + return (state->cfg->program_regs) ? + state->cfg->program_regs(state->mxl_state, ctrl_reg_info) : + -EINVAL; +} + +/* ------------------------------------------------------------------------ */ +/* TPS */ + +static +int mxl1x1sf_demod_get_tps_code_rate(struct mxl111sf_demod_state *state, + fe_code_rate_t *code_rate) +{ + u8 val; + int ret = mxl111sf_demod_read_reg(state, V6_CODE_RATE_TPS_REG, &val); + /* bit<2:0> - 000:1/2, 001:2/3, 010:3/4, 011:5/6, 100:7/8 */ + if (mxl_fail(ret)) + goto fail; + + switch (val & V6_CODE_RATE_TPS_MASK) { + case 0: + *code_rate = FEC_1_2; + break; + case 1: + *code_rate = FEC_2_3; + break; + case 2: + *code_rate = FEC_3_4; + break; + case 3: + *code_rate = FEC_5_6; + break; + case 4: + *code_rate = FEC_7_8; + break; + } +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_tps_modulation(struct mxl111sf_demod_state *state, + fe_modulation_t *modulation) +{ + u8 val; + int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val); + /* Constellation, 00 : QPSK, 01 : 16QAM, 10:64QAM */ + if (mxl_fail(ret)) + goto fail; + + switch ((val & V6_PARAM_CONSTELLATION_MASK) >> 4) { + case 0: + *modulation = QPSK; + break; + case 1: + *modulation = QAM_16; + break; + case 2: + *modulation = QAM_64; + break; + } +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_tps_guard_fft_mode(struct mxl111sf_demod_state *state, + fe_transmit_mode_t *fft_mode) +{ + u8 val; + int ret = mxl111sf_demod_read_reg(state, V6_MODE_TPS_REG, &val); + /* FFT Mode, 00:2K, 01:8K, 10:4K */ + if (mxl_fail(ret)) + goto fail; + + switch ((val & V6_PARAM_FFT_MODE_MASK) >> 2) { + case 0: + *fft_mode = TRANSMISSION_MODE_2K; + break; + case 1: + *fft_mode = TRANSMISSION_MODE_8K; + break; + case 2: + *fft_mode = TRANSMISSION_MODE_4K; + break; + } +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_tps_guard_interval(struct mxl111sf_demod_state *state, + fe_guard_interval_t *guard) +{ + u8 val; + int ret = mxl111sf_demod_read_reg(state, V6_CP_TPS_REG, &val); + /* 00:1/32, 01:1/16, 10:1/8, 11:1/4 */ + if (mxl_fail(ret)) + goto fail; + + switch ((val & V6_PARAM_GI_MASK) >> 4) { + case 0: + *guard = GUARD_INTERVAL_1_32; + break; + case 1: + *guard = GUARD_INTERVAL_1_16; + break; + case 2: + *guard = GUARD_INTERVAL_1_8; + break; + case 3: + *guard = GUARD_INTERVAL_1_4; + break; + } +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_tps_hierarchy(struct mxl111sf_demod_state *state, + fe_hierarchy_t *hierarchy) +{ + u8 val; + int ret = mxl111sf_demod_read_reg(state, V6_TPS_HIERACHY_REG, &val); + /* bit<6:4> - 000:Non hierarchy, 001:1, 010:2, 011:4 */ + if (mxl_fail(ret)) + goto fail; + + switch ((val & V6_TPS_HIERARCHY_INFO_MASK) >> 6) { + case 0: + *hierarchy = HIERARCHY_NONE; + break; + case 1: + *hierarchy = HIERARCHY_1; + break; + case 2: + *hierarchy = HIERARCHY_2; + break; + case 3: + *hierarchy = HIERARCHY_4; + break; + } +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ +/* LOCKS */ + +static +int mxl1x1sf_demod_get_sync_lock_status(struct mxl111sf_demod_state *state, + int *sync_lock) +{ + u8 val = 0; + int ret = mxl111sf_demod_read_reg(state, V6_SYNC_LOCK_REG, &val); + if (mxl_fail(ret)) + goto fail; + *sync_lock = (val & SYNC_LOCK_MASK) >> 4; +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_rs_lock_status(struct mxl111sf_demod_state *state, + int *rs_lock) +{ + u8 val = 0; + int ret = mxl111sf_demod_read_reg(state, V6_RS_LOCK_DET_REG, &val); + if (mxl_fail(ret)) + goto fail; + *rs_lock = (val & RS_LOCK_DET_MASK) >> 3; +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_tps_lock_status(struct mxl111sf_demod_state *state, + int *tps_lock) +{ + u8 val = 0; + int ret = mxl111sf_demod_read_reg(state, V6_TPS_LOCK_REG, &val); + if (mxl_fail(ret)) + goto fail; + *tps_lock = (val & V6_PARAM_TPS_LOCK_MASK) >> 6; +fail: + return ret; +} + +static +int mxl1x1sf_demod_get_fec_lock_status(struct mxl111sf_demod_state *state, + int *fec_lock) +{ + u8 val = 0; + int ret = mxl111sf_demod_read_reg(state, V6_IRQ_STATUS_REG, &val); + if (mxl_fail(ret)) + goto fail; + *fec_lock = (val & IRQ_MASK_FEC_LOCK) >> 4; +fail: + return ret; +} + +#if 0 +static +int mxl1x1sf_demod_get_cp_lock_status(struct mxl111sf_demod_state *state, + int *cp_lock) +{ + u8 val = 0; + int ret = mxl111sf_demod_read_reg(state, V6_CP_LOCK_DET_REG, &val); + if (mxl_fail(ret)) + goto fail; + *cp_lock = (val & V6_CP_LOCK_DET_MASK) >> 2; +fail: + return ret; +} +#endif + +static int mxl1x1sf_demod_reset_irq_status(struct mxl111sf_demod_state *state) +{ + return mxl111sf_demod_write_reg(state, 0x0e, 0xff); +} + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + int ret = 0; + + struct mxl111sf_reg_ctrl_info phy_pll_patch[] = { + {0x00, 0xff, 0x01}, /* change page to 1 */ + {0x40, 0xff, 0x05}, + {0x40, 0xff, 0x01}, + {0x41, 0xff, 0xca}, + {0x41, 0xff, 0xc0}, + {0x00, 0xff, 0x00}, /* change page to 0 */ + {0, 0, 0} + }; + + mxl_dbg("()"); + + if (fe->ops.tuner_ops.set_params) { + ret = fe->ops.tuner_ops.set_params(fe); + if (mxl_fail(ret)) + goto fail; + msleep(50); + } + ret = mxl111sf_demod_program_regs(state, phy_pll_patch); + mxl_fail(ret); + msleep(50); + ret = mxl1x1sf_demod_reset_irq_status(state); + mxl_fail(ret); + msleep(100); +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +#if 0 +/* resets TS Packet error count */ +/* After setting 7th bit of V5_PER_COUNT_RESET_REG, it should be reset to 0. */ +static +int mxl1x1sf_demod_reset_packet_error_count(struct mxl111sf_demod_state *state) +{ + struct mxl111sf_reg_ctrl_info reset_per_count[] = { + {0x20, 0x01, 0x01}, + {0x20, 0x01, 0x00}, + {0, 0, 0} + }; + return mxl111sf_demod_program_regs(state, reset_per_count); +} +#endif + +/* returns TS Packet error count */ +/* PER Count = FEC_PER_COUNT * (2 ** (FEC_PER_SCALE * 4)) */ +static int mxl111sf_demod_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + u32 fec_per_count, fec_per_scale; + u8 val; + int ret; + + *ucblocks = 0; + + /* FEC_PER_COUNT Register */ + ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_COUNT_REG, &val); + if (mxl_fail(ret)) + goto fail; + + fec_per_count = val; + + /* FEC_PER_SCALE Register */ + ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_SCALE_REG, &val); + if (mxl_fail(ret)) + goto fail; + + val &= V6_FEC_PER_SCALE_MASK; + val *= 4; + + fec_per_scale = 1 << val; + + fec_per_count *= fec_per_scale; + + *ucblocks = fec_per_count; +fail: + return ret; +} + +#ifdef MXL111SF_DEMOD_ENABLE_CALCULATIONS +/* FIXME: leaving this enabled breaks the build on some architectures, + * and we shouldn't have any floating point math in the kernel, anyway. + * + * These macros need to be re-written, but it's harmless to simply + * return zero for now. */ +#define CALCULATE_BER(avg_errors, count) \ + ((u32)(avg_errors * 4)/(count*64*188*8)) +#define CALCULATE_SNR(data) \ + ((u32)((10 * (u32)data / 64) - 2.5)) +#else +#define CALCULATE_BER(avg_errors, count) 0 +#define CALCULATE_SNR(data) 0 +#endif + +static int mxl111sf_demod_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + u8 val1, val2, val3; + int ret; + + *ber = 0; + + ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_LSB_REG, &val1); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_MSB_REG, &val2); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_demod_read_reg(state, V6_N_ACCUMULATE_REG, &val3); + if (mxl_fail(ret)) + goto fail; + + *ber = CALCULATE_BER((val1 | (val2 << 8)), val3); +fail: + return ret; +} + +static int mxl111sf_demod_calc_snr(struct mxl111sf_demod_state *state, + u16 *snr) +{ + u8 val1, val2; + int ret; + + *snr = 0; + + ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_LSB_REG, &val1); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_MSB_REG, &val2); + if (mxl_fail(ret)) + goto fail; + + *snr = CALCULATE_SNR(val1 | ((val2 & 0x03) << 8)); +fail: + return ret; +} + +static int mxl111sf_demod_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + + int ret = mxl111sf_demod_calc_snr(state, snr); + if (mxl_fail(ret)) + goto fail; + + *snr /= 10; /* 0.1 dB */ +fail: + return ret; +} + +static int mxl111sf_demod_read_status(struct dvb_frontend *fe, + fe_status_t *status) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + int ret, locked, cr_lock, sync_lock, fec_lock; + + *status = 0; + + ret = mxl1x1sf_demod_get_rs_lock_status(state, &locked); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_demod_get_tps_lock_status(state, &cr_lock); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_demod_get_sync_lock_status(state, &sync_lock); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_demod_get_fec_lock_status(state, &fec_lock); + if (mxl_fail(ret)) + goto fail; + + if (locked) + *status |= FE_HAS_SIGNAL; + if (cr_lock) + *status |= FE_HAS_CARRIER; + if (sync_lock) + *status |= FE_HAS_SYNC; + if (fec_lock) /* false positives? */ + *status |= FE_HAS_VITERBI; + + if ((locked) && (cr_lock) && (sync_lock)) + *status |= FE_HAS_LOCK; +fail: + return ret; +} + +static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + fe_modulation_t modulation; + u16 snr; + + mxl111sf_demod_calc_snr(state, &snr); + mxl1x1sf_demod_get_tps_modulation(state, &modulation); + + switch (modulation) { + case QPSK: + *signal_strength = (snr >= 1300) ? + min(65535, snr * 44) : snr * 38; + break; + case QAM_16: + *signal_strength = (snr >= 1500) ? + min(65535, snr * 38) : snr * 33; + break; + case QAM_64: + *signal_strength = (snr >= 2000) ? + min(65535, snr * 29) : snr * 25; + break; + default: + *signal_strength = 0; + return -EINVAL; + } + + return 0; +} + +static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct mxl111sf_demod_state *state = fe->demodulator_priv; + + mxl_dbg("()"); +#if 0 + p->inversion = /* FIXME */ ? INVERSION_ON : INVERSION_OFF; +#endif + if (fe->ops.tuner_ops.get_bandwidth) + fe->ops.tuner_ops.get_bandwidth(fe, &p->bandwidth_hz); + if (fe->ops.tuner_ops.get_frequency) + fe->ops.tuner_ops.get_frequency(fe, &p->frequency); + mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_HP); + mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_LP); + mxl1x1sf_demod_get_tps_modulation(state, &p->modulation); + mxl1x1sf_demod_get_tps_guard_fft_mode(state, + &p->transmission_mode); + mxl1x1sf_demod_get_tps_guard_interval(state, + &p->guard_interval); + mxl1x1sf_demod_get_tps_hierarchy(state, + &p->hierarchy); + + return 0; +} + +static +int mxl111sf_demod_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + +static void mxl111sf_demod_release(struct dvb_frontend *fe) +{ + struct mxl111sf_demod_state *state = fe->demodulator_priv; + mxl_dbg("()"); + kfree(state); + fe->demodulator_priv = NULL; +} + +static struct dvb_frontend_ops mxl111sf_demod_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "MaxLinear MxL111SF DVB-T demodulator", + .frequency_min = 177000000, + .frequency_max = 858000000, + .frequency_stepsize = 166666, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER + }, + .release = mxl111sf_demod_release, +#if 0 + .init = mxl111sf_init, + .i2c_gate_ctrl = mxl111sf_i2c_gate_ctrl, +#endif + .set_frontend = mxl111sf_demod_set_frontend, + .get_frontend = mxl111sf_demod_get_frontend, + .get_tune_settings = mxl111sf_demod_get_tune_settings, + .read_status = mxl111sf_demod_read_status, + .read_signal_strength = mxl111sf_demod_read_signal_strength, + .read_ber = mxl111sf_demod_read_ber, + .read_snr = mxl111sf_demod_read_snr, + .read_ucblocks = mxl111sf_demod_read_ucblocks, +}; + +struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, + struct mxl111sf_demod_config *cfg) +{ + struct mxl111sf_demod_state *state = NULL; + + mxl_dbg("()"); + + state = kzalloc(sizeof(struct mxl111sf_demod_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + state->mxl_state = mxl_state; + state->cfg = cfg; + + memcpy(&state->fe.ops, &mxl111sf_demod_ops, + sizeof(struct dvb_frontend_ops)); + + state->fe.demodulator_priv = state; + return &state->fe; +} +EXPORT_SYMBOL_GPL(mxl111sf_demod_attach); + +MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver"); +MODULE_AUTHOR("Michael Krufky "); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1"); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.h new file mode 100644 index 000000000000..432706ae5274 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.h @@ -0,0 +1,55 @@ +/* + * mxl111sf-demod.h - driver for the MaxLinear MXL111SF DVB-T demodulator + * + * Copyright (C) 2010 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __MXL111SF_DEMOD_H__ +#define __MXL111SF_DEMOD_H__ + +#include "dvb_frontend.h" +#include "mxl111sf.h" + +struct mxl111sf_demod_config { + int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data); + int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data); + int (*program_regs)(struct mxl111sf_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info); +}; + +#if defined(CONFIG_DVB_USB_MXL111SF) || \ + (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE)) +extern +struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, + struct mxl111sf_demod_config *cfg); +#else +static inline +struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, + struct mxl111sf_demod_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_USB_MXL111SF */ + +#endif /* __MXL111SF_DEMOD_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.c new file mode 100644 index 000000000000..e4121cb8f5ef --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.c @@ -0,0 +1,763 @@ +/* + * mxl111sf-gpio.c - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "mxl111sf-gpio.h" +#include "mxl111sf-i2c.h" +#include "mxl111sf.h" + +/* ------------------------------------------------------------------------- */ + +#define MXL_GPIO_MUX_REG_0 0x84 +#define MXL_GPIO_MUX_REG_1 0x89 +#define MXL_GPIO_MUX_REG_2 0x82 + +#define MXL_GPIO_DIR_INPUT 0 +#define MXL_GPIO_DIR_OUTPUT 1 + + +static int mxl111sf_set_gpo_state(struct mxl111sf_state *state, u8 pin, u8 val) +{ + int ret; + u8 tmp; + + mxl_debug_adv("(%d, %d)", pin, val); + + if ((pin > 0) && (pin < 8)) { + ret = mxl111sf_read_reg(state, 0x19, &tmp); + if (mxl_fail(ret)) + goto fail; + tmp &= ~(1 << (pin - 1)); + tmp |= (val << (pin - 1)); + ret = mxl111sf_write_reg(state, 0x19, tmp); + if (mxl_fail(ret)) + goto fail; + } else if (pin <= 10) { + if (pin == 0) + pin += 7; + ret = mxl111sf_read_reg(state, 0x30, &tmp); + if (mxl_fail(ret)) + goto fail; + tmp &= ~(1 << (pin - 3)); + tmp |= (val << (pin - 3)); + ret = mxl111sf_write_reg(state, 0x30, tmp); + if (mxl_fail(ret)) + goto fail; + } else + ret = -EINVAL; +fail: + return ret; +} + +static int mxl111sf_get_gpi_state(struct mxl111sf_state *state, u8 pin, u8 *val) +{ + int ret; + u8 tmp; + + mxl_debug("(0x%02x)", pin); + + *val = 0; + + switch (pin) { + case 0: + case 1: + case 2: + case 3: + ret = mxl111sf_read_reg(state, 0x23, &tmp); + if (mxl_fail(ret)) + goto fail; + *val = (tmp >> (pin + 4)) & 0x01; + break; + case 4: + case 5: + case 6: + case 7: + ret = mxl111sf_read_reg(state, 0x2f, &tmp); + if (mxl_fail(ret)) + goto fail; + *val = (tmp >> pin) & 0x01; + break; + case 8: + case 9: + case 10: + ret = mxl111sf_read_reg(state, 0x22, &tmp); + if (mxl_fail(ret)) + goto fail; + *val = (tmp >> (pin - 3)) & 0x01; + break; + default: + return -EINVAL; /* invalid pin */ + } +fail: + return ret; +} + +struct mxl_gpio_cfg { + u8 pin; + u8 dir; + u8 val; +}; + +static int mxl111sf_config_gpio_pins(struct mxl111sf_state *state, + struct mxl_gpio_cfg *gpio_cfg) +{ + int ret; + u8 tmp; + + mxl_debug_adv("(%d, %d)", gpio_cfg->pin, gpio_cfg->dir); + + switch (gpio_cfg->pin) { + case 0: + case 1: + case 2: + case 3: + ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_0, &tmp); + if (mxl_fail(ret)) + goto fail; + tmp &= ~(1 << (gpio_cfg->pin + 4)); + tmp |= (gpio_cfg->dir << (gpio_cfg->pin + 4)); + ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_0, tmp); + if (mxl_fail(ret)) + goto fail; + break; + case 4: + case 5: + case 6: + case 7: + ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_1, &tmp); + if (mxl_fail(ret)) + goto fail; + tmp &= ~(1 << gpio_cfg->pin); + tmp |= (gpio_cfg->dir << gpio_cfg->pin); + ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_1, tmp); + if (mxl_fail(ret)) + goto fail; + break; + case 8: + case 9: + case 10: + ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_2, &tmp); + if (mxl_fail(ret)) + goto fail; + tmp &= ~(1 << (gpio_cfg->pin - 3)); + tmp |= (gpio_cfg->dir << (gpio_cfg->pin - 3)); + ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_2, tmp); + if (mxl_fail(ret)) + goto fail; + break; + default: + return -EINVAL; /* invalid pin */ + } + + ret = (MXL_GPIO_DIR_OUTPUT == gpio_cfg->dir) ? + mxl111sf_set_gpo_state(state, + gpio_cfg->pin, gpio_cfg->val) : + mxl111sf_get_gpi_state(state, + gpio_cfg->pin, &gpio_cfg->val); + mxl_fail(ret); +fail: + return ret; +} + +static int mxl111sf_hw_do_set_gpio(struct mxl111sf_state *state, + int gpio, int direction, int val) +{ + struct mxl_gpio_cfg gpio_config = { + .pin = gpio, + .dir = direction, + .val = val, + }; + + mxl_debug("(%d, %d, %d)", gpio, direction, val); + + return mxl111sf_config_gpio_pins(state, &gpio_config); +} + +/* ------------------------------------------------------------------------- */ + +#define PIN_MUX_MPEG_MODE_MASK 0x40 /* 0x17 <6> */ +#define PIN_MUX_MPEG_PAR_EN_MASK 0x01 /* 0x18 <0> */ +#define PIN_MUX_MPEG_SER_EN_MASK 0x02 /* 0x18 <1> */ +#define PIN_MUX_MPG_IN_MUX_MASK 0x80 /* 0x3D <7> */ +#define PIN_MUX_BT656_ENABLE_MASK 0x04 /* 0x12 <2> */ +#define PIN_MUX_I2S_ENABLE_MASK 0x40 /* 0x15 <6> */ +#define PIN_MUX_SPI_MODE_MASK 0x10 /* 0x3D <4> */ +#define PIN_MUX_MCLK_EN_CTRL_MASK 0x10 /* 0x82 <4> */ +#define PIN_MUX_MPSYN_EN_CTRL_MASK 0x20 /* 0x82 <5> */ +#define PIN_MUX_MDVAL_EN_CTRL_MASK 0x40 /* 0x82 <6> */ +#define PIN_MUX_MPERR_EN_CTRL_MASK 0x80 /* 0x82 <7> */ +#define PIN_MUX_MDAT_EN_0_MASK 0x10 /* 0x84 <4> */ +#define PIN_MUX_MDAT_EN_1_MASK 0x20 /* 0x84 <5> */ +#define PIN_MUX_MDAT_EN_2_MASK 0x40 /* 0x84 <6> */ +#define PIN_MUX_MDAT_EN_3_MASK 0x80 /* 0x84 <7> */ +#define PIN_MUX_MDAT_EN_4_MASK 0x10 /* 0x89 <4> */ +#define PIN_MUX_MDAT_EN_5_MASK 0x20 /* 0x89 <5> */ +#define PIN_MUX_MDAT_EN_6_MASK 0x40 /* 0x89 <6> */ +#define PIN_MUX_MDAT_EN_7_MASK 0x80 /* 0x89 <7> */ + +int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state, + enum mxl111sf_mux_config pin_mux_config) +{ + u8 r12, r15, r17, r18, r3D, r82, r84, r89; + int ret; + + mxl_debug("(%d)", pin_mux_config); + + ret = mxl111sf_read_reg(state, 0x17, &r17); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x18, &r18); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x12, &r12); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x15, &r15); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x82, &r82); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x84, &r84); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x89, &r89); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x3D, &r3D); + if (mxl_fail(ret)) + goto fail; + + switch (pin_mux_config) { + case PIN_MUX_TS_OUT_PARALLEL: + /* mpeg_mode = 1 */ + r17 |= PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 1 */ + r18 |= PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 0 */ + r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 1 */ + r82 |= PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 1 */ + r82 |= PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 1 */ + r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 1 */ + r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0xF */ + r84 |= 0xF0; + /* mdat_en_ctrl[7:4] = 0xF */ + r89 |= 0xF0; + break; + case PIN_MUX_TS_OUT_SERIAL: + /* mpeg_mode = 1 */ + r17 |= PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 1 */ + r18 |= PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 1 */ + r82 |= PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 1 */ + r82 |= PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 1 */ + r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 1 */ + r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0xF */ + r84 |= 0xF0; + /* mdat_en_ctrl[7:4] = 0xF */ + r89 |= 0xF0; + break; + case PIN_MUX_GPIO_MODE: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 0 */ + r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_TS_SERIAL_IN_MODE_0: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 1 */ + r18 |= PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_TS_SERIAL_IN_MODE_1: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 1 */ + r18 |= PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 1 */ + r3D |= PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_TS_SPI_IN_MODE_1: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 1 */ + r18 |= PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 1 */ + r3D |= PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 1 */ + r15 |= PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 1 */ + r3D |= PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_TS_SPI_IN_MODE_0: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 1 */ + r18 |= PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 1 */ + r15 |= PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 1 */ + r3D |= PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_TS_PARALLEL_IN: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 1 */ + r18 |= PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 0 */ + r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_BT656_I2S_MODE: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 0 */ + r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 1 */ + r12 |= PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 1 */ + r15 |= PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_DEFAULT: + default: + /* mpeg_mode = 1 */ + r17 |= PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 0 */ + r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + } + + ret = mxl111sf_write_reg(state, 0x17, r17); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x18, r18); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x12, r12); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x15, r15); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x82, r82); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x84, r84); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x89, r89); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x3D, r3D); + if (mxl_fail(ret)) + goto fail; +fail: + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl111sf_hw_set_gpio(struct mxl111sf_state *state, int gpio, int val) +{ + return mxl111sf_hw_do_set_gpio(state, gpio, MXL_GPIO_DIR_OUTPUT, val); +} + +static int mxl111sf_hw_gpio_initialize(struct mxl111sf_state *state) +{ + u8 gpioval = 0x07; /* write protect enabled, signal LEDs off */ + int i, ret; + + mxl_debug("()"); + + for (i = 3; i < 8; i++) { + ret = mxl111sf_hw_set_gpio(state, i, (gpioval >> i) & 0x01); + if (mxl_fail(ret)) + break; + } + + return ret; +} + +#define PCA9534_I2C_ADDR (0x40 >> 1) +static int pca9534_set_gpio(struct mxl111sf_state *state, int gpio, int val) +{ + u8 w[2] = { 1, 0 }; + u8 r = 0; + struct i2c_msg msg[] = { + { .addr = PCA9534_I2C_ADDR, + .flags = 0, .buf = w, .len = 1 }, + { .addr = PCA9534_I2C_ADDR, + .flags = I2C_M_RD, .buf = &r, .len = 1 }, + }; + + mxl_debug("(%d, %d)", gpio, val); + + /* read current GPIO levels from flip-flop */ + i2c_transfer(&state->d->i2c_adap, msg, 2); + + /* prepare write buffer with current GPIO levels */ + msg[0].len = 2; +#if 0 + w[0] = 1; +#endif + w[1] = r; + + /* clear the desired GPIO */ + w[1] &= ~(1 << gpio); + + /* set the desired GPIO value */ + w[1] |= ((val ? 1 : 0) << gpio); + + /* write new GPIO levels to flip-flop */ + i2c_transfer(&state->d->i2c_adap, &msg[0], 1); + + return 0; +} + +static int pca9534_init_port_expander(struct mxl111sf_state *state) +{ + u8 w[2] = { 1, 0x07 }; /* write protect enabled, signal LEDs off */ + + struct i2c_msg msg = { + .addr = PCA9534_I2C_ADDR, + .flags = 0, .buf = w, .len = 2 + }; + + mxl_debug("()"); + + i2c_transfer(&state->d->i2c_adap, &msg, 1); + + /* configure all pins as outputs */ + w[0] = 3; + w[1] = 0; + + i2c_transfer(&state->d->i2c_adap, &msg, 1); + + return 0; +} + +int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val) +{ + mxl_debug("(%d, %d)", gpio, val); + + switch (state->gpio_port_expander) { + default: + mxl_printk(KERN_ERR, + "gpio_port_expander undefined, assuming PCA9534"); + /* fall-thru */ + case mxl111sf_PCA9534: + return pca9534_set_gpio(state, gpio, val); + case mxl111sf_gpio_hw: + return mxl111sf_hw_set_gpio(state, gpio, val); + } +} + +static int mxl111sf_probe_port_expander(struct mxl111sf_state *state) +{ + int ret; + u8 w = 1; + u8 r = 0; + struct i2c_msg msg[] = { + { .flags = 0, .buf = &w, .len = 1 }, + { .flags = I2C_M_RD, .buf = &r, .len = 1 }, + }; + + mxl_debug("()"); + + msg[0].addr = 0x70 >> 1; + msg[1].addr = 0x70 >> 1; + + /* read current GPIO levels from flip-flop */ + ret = i2c_transfer(&state->d->i2c_adap, msg, 2); + if (ret == 2) { + state->port_expander_addr = msg[0].addr; + state->gpio_port_expander = mxl111sf_PCA9534; + mxl_debug("found port expander at 0x%02x", + state->port_expander_addr); + return 0; + } + + msg[0].addr = 0x40 >> 1; + msg[1].addr = 0x40 >> 1; + + ret = i2c_transfer(&state->d->i2c_adap, msg, 2); + if (ret == 2) { + state->port_expander_addr = msg[0].addr; + state->gpio_port_expander = mxl111sf_PCA9534; + mxl_debug("found port expander at 0x%02x", + state->port_expander_addr); + return 0; + } + state->port_expander_addr = 0xff; + state->gpio_port_expander = mxl111sf_gpio_hw; + mxl_debug("using hardware gpio"); + return 0; +} + +int mxl111sf_init_port_expander(struct mxl111sf_state *state) +{ + mxl_debug("()"); + + if (0x00 == state->port_expander_addr) + mxl111sf_probe_port_expander(state); + + switch (state->gpio_port_expander) { + default: + mxl_printk(KERN_ERR, + "gpio_port_expander undefined, assuming PCA9534"); + /* fall-thru */ + case mxl111sf_PCA9534: + return pca9534_init_port_expander(state); + case mxl111sf_gpio_hw: + return mxl111sf_hw_gpio_initialize(state); + } +} + +/* ------------------------------------------------------------------------ */ + +int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode) +{ +/* GPO: + * 3 - ATSC/MH# | 1 = ATSC transport, 0 = MH transport | default 0 + * 4 - ATSC_RST## | 1 = ATSC enable, 0 = ATSC Reset | default 0 + * 5 - ATSC_EN | 1 = ATSC power enable, 0 = ATSC power off | default 0 + * 6 - MH_RESET# | 1 = MH enable, 0 = MH Reset | default 0 + * 7 - MH_EN | 1 = MH power enable, 0 = MH power off | default 0 + */ + mxl_debug("(%d)", mode); + + switch (mode) { + case MXL111SF_GPIO_MOD_MH: + mxl111sf_set_gpio(state, 4, 0); + mxl111sf_set_gpio(state, 5, 0); + msleep(50); + mxl111sf_set_gpio(state, 7, 1); + msleep(50); + mxl111sf_set_gpio(state, 6, 1); + msleep(50); + + mxl111sf_set_gpio(state, 3, 0); + break; + case MXL111SF_GPIO_MOD_ATSC: + mxl111sf_set_gpio(state, 6, 0); + mxl111sf_set_gpio(state, 7, 0); + msleep(50); + mxl111sf_set_gpio(state, 5, 1); + msleep(50); + mxl111sf_set_gpio(state, 4, 1); + msleep(50); + mxl111sf_set_gpio(state, 3, 1); + break; + default: /* DVBT / STANDBY */ + mxl111sf_init_port_expander(state); + break; + } + return 0; +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.h new file mode 100644 index 000000000000..0220f54299a5 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.h @@ -0,0 +1,56 @@ +/* + * mxl111sf-gpio.h - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _DVB_USB_MXL111SF_GPIO_H_ +#define _DVB_USB_MXL111SF_GPIO_H_ + +#include "mxl111sf.h" + +int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val); +int mxl111sf_init_port_expander(struct mxl111sf_state *state); + +#define MXL111SF_GPIO_MOD_DVBT 0 +#define MXL111SF_GPIO_MOD_MH 1 +#define MXL111SF_GPIO_MOD_ATSC 2 +int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode); + +enum mxl111sf_mux_config { + PIN_MUX_DEFAULT = 0, + PIN_MUX_TS_OUT_PARALLEL, + PIN_MUX_TS_OUT_SERIAL, + PIN_MUX_GPIO_MODE, + PIN_MUX_TS_SERIAL_IN_MODE_0, + PIN_MUX_TS_SERIAL_IN_MODE_1, + PIN_MUX_TS_SPI_IN_MODE_0, + PIN_MUX_TS_SPI_IN_MODE_1, + PIN_MUX_TS_PARALLEL_IN, + PIN_MUX_BT656_I2S_MODE, +}; + +int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state, + enum mxl111sf_mux_config pin_mux_config); + +#endif /* _DVB_USB_MXL111SF_GPIO_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.c new file mode 100644 index 000000000000..34434557ef65 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.c @@ -0,0 +1,850 @@ +/* + * mxl111sf-i2c.c - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "mxl111sf-i2c.h" +#include "mxl111sf.h" + +/* SW-I2C ----------------------------------------------------------------- */ + +#define SW_I2C_ADDR 0x1a +#define SW_I2C_EN 0x02 +#define SW_SCL_OUT 0x04 +#define SW_SDA_OUT 0x08 +#define SW_SDA_IN 0x04 + +#define SW_I2C_BUSY_ADDR 0x2f +#define SW_I2C_BUSY 0x02 + +static int mxl111sf_i2c_bitbang_sendbyte(struct mxl111sf_state *state, + u8 byte) +{ + int i, ret; + u8 data = 0; + + mxl_i2c("(0x%02x)", byte); + + ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data); + if (mxl_fail(ret)) + goto fail; + + for (i = 0; i < 8; i++) { + + data = (byte & (0x80 >> i)) ? SW_SDA_OUT : 0; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | data); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | data | SW_SCL_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | data); + if (mxl_fail(ret)) + goto fail; + } + + /* last bit was 0 so we need to release SDA */ + if (!(byte & 1)) { + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + } + + /* CLK high for ACK readback */ + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data); + if (mxl_fail(ret)) + goto fail; + + /* drop the CLK after getting ACK, SDA will go high right away */ + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + if (data & SW_SDA_IN) + ret = -EIO; +fail: + return ret; +} + +static int mxl111sf_i2c_bitbang_recvbyte(struct mxl111sf_state *state, + u8 *pbyte) +{ + int i, ret; + u8 byte = 0; + u8 data = 0; + + mxl_i2c("()"); + + *pbyte = 0; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + for (i = 0; i < 8; i++) { + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | + SW_SCL_OUT | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data); + if (mxl_fail(ret)) + goto fail; + + if (data & SW_SDA_IN) + byte |= (0x80 >> i); + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + } + *pbyte = byte; +fail: + return ret; +} + +static int mxl111sf_i2c_start(struct mxl111sf_state *state) +{ + int ret; + + mxl_i2c("()"); + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN); /* start */ + mxl_fail(ret); +fail: + return ret; +} + +static int mxl111sf_i2c_stop(struct mxl111sf_state *state) +{ + int ret; + + mxl_i2c("()"); + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN); /* stop */ + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_SCL_OUT | SW_SDA_OUT); + mxl_fail(ret); +fail: + return ret; +} + +static int mxl111sf_i2c_ack(struct mxl111sf_state *state) +{ + int ret; + u8 b = 0; + + mxl_i2c("()"); + + ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &b); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN); + if (mxl_fail(ret)) + goto fail; + + /* pull SDA low */ + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + mxl_fail(ret); +fail: + return ret; +} + +static int mxl111sf_i2c_nack(struct mxl111sf_state *state) +{ + int ret; + + mxl_i2c("()"); + + /* SDA high to signal last byte read from slave */ + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + mxl_fail(ret); +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_i2c_sw_xfer_msg(struct mxl111sf_state *state, + struct i2c_msg *msg) +{ + int i, ret; + + mxl_i2c("()"); + + if (msg->flags & I2C_M_RD) { + + ret = mxl111sf_i2c_start(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_i2c_bitbang_sendbyte(state, + (msg->addr << 1) | 0x01); + if (mxl_fail(ret)) { + mxl111sf_i2c_stop(state); + goto fail; + } + + for (i = 0; i < msg->len; i++) { + ret = mxl111sf_i2c_bitbang_recvbyte(state, + &msg->buf[i]); + if (mxl_fail(ret)) { + mxl111sf_i2c_stop(state); + goto fail; + } + + if (i < msg->len - 1) + mxl111sf_i2c_ack(state); + } + + mxl111sf_i2c_nack(state); + + ret = mxl111sf_i2c_stop(state); + if (mxl_fail(ret)) + goto fail; + + } else { + + ret = mxl111sf_i2c_start(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_i2c_bitbang_sendbyte(state, + (msg->addr << 1) & 0xfe); + if (mxl_fail(ret)) { + mxl111sf_i2c_stop(state); + goto fail; + } + + for (i = 0; i < msg->len; i++) { + ret = mxl111sf_i2c_bitbang_sendbyte(state, + msg->buf[i]); + if (mxl_fail(ret)) { + mxl111sf_i2c_stop(state); + goto fail; + } + } + + /* FIXME: we only want to do this on the last transaction */ + mxl111sf_i2c_stop(state); + } +fail: + return ret; +} + +/* HW-I2C ----------------------------------------------------------------- */ + +#define USB_WRITE_I2C_CMD 0x99 +#define USB_READ_I2C_CMD 0xdd +#define USB_END_I2C_CMD 0xfe + +#define USB_WRITE_I2C_CMD_LEN 26 +#define USB_READ_I2C_CMD_LEN 24 + +#define I2C_MUX_REG 0x30 +#define I2C_CONTROL_REG 0x00 +#define I2C_SLAVE_ADDR_REG 0x08 +#define I2C_DATA_REG 0x0c +#define I2C_INT_STATUS_REG 0x10 + +static int mxl111sf_i2c_send_data(struct mxl111sf_state *state, + u8 index, u8 *wdata) +{ + int ret = mxl111sf_ctrl_msg(state->d, wdata[0], + &wdata[1], 25, NULL, 0); + mxl_fail(ret); + + return ret; +} + +static int mxl111sf_i2c_get_data(struct mxl111sf_state *state, + u8 index, u8 *wdata, u8 *rdata) +{ + int ret = mxl111sf_ctrl_msg(state->d, wdata[0], + &wdata[1], 25, rdata, 24); + mxl_fail(ret); + + return ret; +} + +static u8 mxl111sf_i2c_check_status(struct mxl111sf_state *state) +{ + u8 status = 0; + u8 buf[26]; + + mxl_i2c_adv("()"); + + buf[0] = USB_READ_I2C_CMD; + buf[1] = 0x00; + + buf[2] = I2C_INT_STATUS_REG; + buf[3] = 0x00; + buf[4] = 0x00; + + buf[5] = USB_END_I2C_CMD; + + mxl111sf_i2c_get_data(state, 0, buf, buf); + + if (buf[1] & 0x04) + status = 1; + + return status; +} + +static u8 mxl111sf_i2c_check_fifo(struct mxl111sf_state *state) +{ + u8 status = 0; + u8 buf[26]; + + mxl_i2c("()"); + + buf[0] = USB_READ_I2C_CMD; + buf[1] = 0x00; + + buf[2] = I2C_MUX_REG; + buf[3] = 0x00; + buf[4] = 0x00; + + buf[5] = I2C_INT_STATUS_REG; + buf[6] = 0x00; + buf[7] = 0x00; + buf[8] = USB_END_I2C_CMD; + + mxl111sf_i2c_get_data(state, 0, buf, buf); + + if (0x08 == (buf[1] & 0x08)) + status = 1; + + if ((buf[5] & 0x02) == 0x02) + mxl_i2c("(buf[5] & 0x02) == 0x02"); /* FIXME */ + + return status; +} + +static int mxl111sf_i2c_readagain(struct mxl111sf_state *state, + u8 count, u8 *rbuf) +{ + u8 i2c_w_data[26]; + u8 i2c_r_data[24]; + u8 i = 0; + u8 fifo_status = 0; + int status = 0; + + mxl_i2c("read %d bytes", count); + + while ((fifo_status == 0) && (i++ < 5)) + fifo_status = mxl111sf_i2c_check_fifo(state); + + i2c_w_data[0] = 0xDD; + i2c_w_data[1] = 0x00; + + for (i = 2; i < 26; i++) + i2c_w_data[i] = 0xFE; + + for (i = 0; i < count; i++) { + i2c_w_data[2+(i*3)] = 0x0C; + i2c_w_data[3+(i*3)] = 0x00; + i2c_w_data[4+(i*3)] = 0x00; + } + + mxl111sf_i2c_get_data(state, 0, i2c_w_data, i2c_r_data); + + /* Check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("error!"); + } else { + for (i = 0; i < count; i++) { + rbuf[i] = i2c_r_data[(i*3)+1]; + mxl_i2c("%02x\t %02x", + i2c_r_data[(i*3)+1], + i2c_r_data[(i*3)+2]); + } + + status = 1; + } + + return status; +} + +#define HWI2C400 1 +static int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state, + struct i2c_msg *msg) +{ + int i, k, ret = 0; + u16 index = 0; + u8 buf[26]; + u8 i2c_r_data[24]; + u16 block_len; + u16 left_over_len; + u8 rd_status[8]; + u8 ret_status; + u8 readbuff[26]; + + mxl_i2c("addr: 0x%02x, read buff len: %d, write buff len: %d", + msg->addr, (msg->flags & I2C_M_RD) ? msg->len : 0, + (!(msg->flags & I2C_M_RD)) ? msg->len : 0); + + for (index = 0; index < 26; index++) + buf[index] = USB_END_I2C_CMD; + + /* command to indicate data payload is destined for I2C interface */ + buf[0] = USB_WRITE_I2C_CMD; + buf[1] = 0x00; + + /* enable I2C interface */ + buf[2] = I2C_MUX_REG; + buf[3] = 0x80; + buf[4] = 0x00; + + /* enable I2C interface */ + buf[5] = I2C_MUX_REG; + buf[6] = 0x81; + buf[7] = 0x00; + + /* set Timeout register on I2C interface */ + buf[8] = 0x14; + buf[9] = 0xff; + buf[10] = 0x00; +#if 0 + /* enable Interrupts on I2C interface */ + buf[8] = 0x24; + buf[9] = 0xF7; + buf[10] = 0x00; +#endif + buf[11] = 0x24; + buf[12] = 0xF7; + buf[13] = 0x00; + + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* write data on I2C bus */ + if (!(msg->flags & I2C_M_RD) && (msg->len > 0)) { + mxl_i2c("%d\t%02x", msg->len, msg->buf[0]); + + /* control register on I2C interface to initialize I2C bus */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x5E; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + + /* I2C Slave device Address */ + buf[5] = I2C_SLAVE_ADDR_REG; + buf[6] = (msg->addr); + buf[7] = 0x00; + buf[8] = USB_END_I2C_CMD; + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* check for slave device status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK writing slave address %02x", + msg->addr); + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x4E; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + /* I2C interface can do I2C operations in block of 8 bytes of + I2C data. calculation to figure out number of blocks of i2c + data required to program */ + block_len = (msg->len / 8); + left_over_len = (msg->len % 8); + index = 0; + + mxl_i2c("block_len %d, left_over_len %d", + block_len, left_over_len); + + for (index = 0; index < block_len; index++) { + for (i = 0; i < 8; i++) { + /* write data on I2C interface */ + buf[2+(i*3)] = I2C_DATA_REG; + buf[3+(i*3)] = msg->buf[(index*8)+i]; + buf[4+(i*3)] = 0x00; + } + + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK writing slave address %02x", + msg->addr); + + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x4E; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + } + + if (left_over_len) { + for (k = 0; k < 26; k++) + buf[k] = USB_END_I2C_CMD; + + buf[0] = 0x99; + buf[1] = 0x00; + + for (i = 0; i < left_over_len; i++) { + buf[2+(i*3)] = I2C_DATA_REG; + buf[3+(i*3)] = msg->buf[(index*8)+i]; + mxl_i2c("index = %d %d data %d", + index, i, msg->buf[(index*8)+i]); + buf[4+(i*3)] = 0x00; + } + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK writing slave address %02x", + msg->addr); + + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x4E; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + } + + /* issue I2C STOP after write */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x4E; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + + } + + /* read data from I2C bus */ + if ((msg->flags & I2C_M_RD) && (msg->len > 0)) { + mxl_i2c("read buf len %d", msg->len); + + /* command to indicate data payload is + destined for I2C interface */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xDF; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + + /* I2C xfer length */ + buf[5] = 0x14; + buf[6] = (msg->len & 0xFF); + buf[7] = 0; + + /* I2C slave device Address */ + buf[8] = I2C_SLAVE_ADDR_REG; + buf[9] = msg->addr; + buf[10] = 0x00; + buf[11] = USB_END_I2C_CMD; + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK reading slave address %02x", + msg->addr); + + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xC7; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + /* I2C interface can do I2C operations in block of 8 bytes of + I2C data. calculation to figure out number of blocks of + i2c data required to program */ + block_len = ((msg->len) / 8); + left_over_len = ((msg->len) % 8); + index = 0; + + mxl_i2c("block_len %d, left_over_len %d", + block_len, left_over_len); + + /* command to read data from I2C interface */ + buf[0] = USB_READ_I2C_CMD; + buf[1] = 0x00; + + for (index = 0; index < block_len; index++) { + /* setup I2C read request packet on I2C interface */ + for (i = 0; i < 8; i++) { + buf[2+(i*3)] = I2C_DATA_REG; + buf[3+(i*3)] = 0x00; + buf[4+(i*3)] = 0x00; + } + + ret = mxl111sf_i2c_get_data(state, 0, buf, i2c_r_data); + + /* check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK reading slave address %02x", + msg->addr); + + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xC7; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + /* copy data from i2c data payload to read buffer */ + for (i = 0; i < 8; i++) { + rd_status[i] = i2c_r_data[(i*3)+2]; + + if (rd_status[i] == 0x04) { + if (i < 7) { + mxl_i2c("i2c fifo empty!" + " @ %d", i); + msg->buf[(index*8)+i] = + i2c_r_data[(i*3)+1]; + /* read again */ + ret_status = + mxl111sf_i2c_readagain( + state, 8-(i+1), + readbuff); + if (ret_status == 1) { + for (k = 0; + k < 8-(i+1); + k++) { + + msg->buf[(index*8)+(k+i+1)] = + readbuff[k]; + mxl_i2c("read data: %02x\t %02x", + msg->buf[(index*8)+(k+i)], + (index*8)+(k+i)); + mxl_i2c("read data: %02x\t %02x", + msg->buf[(index*8)+(k+i+1)], + readbuff[k]); + + } + goto stop_copy; + } else { + mxl_i2c("readagain " + "ERROR!"); + } + } else { + msg->buf[(index*8)+i] = + i2c_r_data[(i*3)+1]; + } + } else { + msg->buf[(index*8)+i] = + i2c_r_data[(i*3)+1]; + } + } +stop_copy: + ; + + } + + if (left_over_len) { + for (k = 0; k < 26; k++) + buf[k] = USB_END_I2C_CMD; + + buf[0] = 0xDD; + buf[1] = 0x00; + + for (i = 0; i < left_over_len; i++) { + buf[2+(i*3)] = I2C_DATA_REG; + buf[3+(i*3)] = 0x00; + buf[4+(i*3)] = 0x00; + } + ret = mxl111sf_i2c_get_data(state, 0, buf, + i2c_r_data); + + /* check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK reading slave address %02x", + msg->addr); + + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xC7; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + for (i = 0; i < left_over_len; i++) { + msg->buf[(block_len*8)+i] = + i2c_r_data[(i*3)+1]; + mxl_i2c("read data: %02x\t %02x", + i2c_r_data[(i*3)+1], + i2c_r_data[(i*3)+2]); + } + } + + /* indicate I2C interface to issue NACK + after next I2C read op */ + buf[0] = USB_WRITE_I2C_CMD; + buf[1] = 0x00; + + /* control register */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x17; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + + buf[5] = USB_END_I2C_CMD; + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* control register */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xC7; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + + } +exit: + /* STOP and disable I2C MUX */ + buf[0] = USB_WRITE_I2C_CMD; + buf[1] = 0x00; + + /* de-initilize I2C BUS */ + buf[5] = USB_END_I2C_CMD; + mxl111sf_i2c_send_data(state, 0, buf); + + /* Control Register */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xDF; + buf[4] = 0x03; + + /* disable I2C interface */ + buf[5] = I2C_MUX_REG; + buf[6] = 0x00; + buf[7] = 0x00; + + /* de-initilize I2C BUS */ + buf[8] = USB_END_I2C_CMD; + mxl111sf_i2c_send_data(state, 0, buf); + + /* disable I2C interface */ + buf[2] = I2C_MUX_REG; + buf[3] = 0x81; + buf[4] = 0x00; + + /* disable I2C interface */ + buf[5] = I2C_MUX_REG; + buf[6] = 0x00; + buf[7] = 0x00; + + /* disable I2C interface */ + buf[8] = I2C_MUX_REG; + buf[9] = 0x00; + buf[10] = 0x00; + + buf[11] = USB_END_I2C_CMD; + mxl111sf_i2c_send_data(state, 0, buf); + + return ret; +} + +/* ------------------------------------------------------------------------ */ + +int mxl111sf_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct mxl111sf_state *state = d->priv; + int hwi2c = (state->chip_rev > MXL111SF_V6); + int i, ret; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + ret = (hwi2c) ? + mxl111sf_i2c_hw_xfer_msg(state, &msg[i]) : + mxl111sf_i2c_sw_xfer_msg(state, &msg[i]); + if (mxl_fail(ret)) { + mxl_debug_adv("failed with error %d on i2c " + "transaction %d of %d, %sing %d bytes " + "to/from 0x%02x", ret, i+1, num, + (msg[i].flags & I2C_M_RD) ? + "read" : "writ", + msg[i].len, msg[i].addr); + + break; + } + } + + mutex_unlock(&d->i2c_mutex); + + return i == num ? num : -EREMOTEIO; +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.h new file mode 100644 index 000000000000..a57a45ffb9e4 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.h @@ -0,0 +1,35 @@ +/* + * mxl111sf-i2c.h - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _DVB_USB_MXL111SF_I2C_H_ +#define _DVB_USB_MXL111SF_I2C_H_ + +#include + +int mxl111sf_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg msg[], int num); + +#endif /* _DVB_USB_MXL111SF_I2C_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.c new file mode 100644 index 000000000000..b741b3a7a325 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.c @@ -0,0 +1,343 @@ +/* + * mxl111sf-phy.c - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "mxl111sf-phy.h" +#include "mxl111sf-reg.h" + +int mxl111sf_init_tuner_demod(struct mxl111sf_state *state) +{ + struct mxl111sf_reg_ctrl_info mxl_111_overwrite_default[] = { + {0x07, 0xff, 0x0c}, + {0x58, 0xff, 0x9d}, + {0x09, 0xff, 0x00}, + {0x06, 0xff, 0x06}, + {0xc8, 0xff, 0x40}, /* ED_LE_WIN_OLD = 0 */ + {0x8d, 0x01, 0x01}, /* NEGATE_Q */ + {0x32, 0xff, 0xac}, /* DIG_RFREFSELECT = 12 */ + {0x42, 0xff, 0x43}, /* DIG_REG_AMP = 4 */ + {0x74, 0xff, 0xc4}, /* SSPUR_FS_PRIO = 4 */ + {0x71, 0xff, 0xe6}, /* SPUR_ROT_PRIO_VAL = 1 */ + {0x83, 0xff, 0x64}, /* INF_FILT1_THD_SC = 100 */ + {0x85, 0xff, 0x64}, /* INF_FILT2_THD_SC = 100 */ + {0x88, 0xff, 0xf0}, /* INF_THD = 240 */ + {0x6f, 0xf0, 0xb0}, /* DFE_DLY = 11 */ + {0x00, 0xff, 0x01}, /* Change to page 1 */ + {0x81, 0xff, 0x11}, /* DSM_FERR_BYPASS = 1 */ + {0xf4, 0xff, 0x07}, /* DIG_FREQ_CORR = 1 */ + {0xd4, 0x1f, 0x0f}, /* SPUR_TEST_NOISE_TH = 15 */ + {0xd6, 0xff, 0x0c}, /* SPUR_TEST_NOISE_PAPR = 12 */ + {0x00, 0xff, 0x00}, /* Change to page 0 */ + {0, 0, 0} + }; + + mxl_debug("()"); + + return mxl111sf_ctrl_program_regs(state, mxl_111_overwrite_default); +} + +int mxl1x1sf_soft_reset(struct mxl111sf_state *state) +{ + int ret; + mxl_debug("()"); + + ret = mxl111sf_write_reg(state, 0xff, 0x00); /* AIC */ + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x02, 0x01); /* get out of reset */ + mxl_fail(ret); +fail: + return ret; +} + +int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode) +{ + int ret; + + mxl_debug("(%s)", MXL_SOC_MODE == mode ? + "MXL_SOC_MODE" : "MXL_TUNER_MODE"); + + /* set device mode */ + ret = mxl111sf_write_reg(state, 0x03, + MXL_SOC_MODE == mode ? 0x01 : 0x00); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg_mask(state, + 0x7d, 0x40, MXL_SOC_MODE == mode ? + 0x00 : /* enable impulse noise filter, + INF_BYP = 0 */ + 0x40); /* disable impulse noise filter, + INF_BYP = 1 */ + if (mxl_fail(ret)) + goto fail; + + state->device_mode = mode; +fail: + return ret; +} + +/* power up tuner */ +int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff) +{ + mxl_debug("(%d)", onoff); + + return mxl111sf_write_reg(state, 0x01, onoff ? 0x01 : 0x00); +} + +int mxl111sf_disable_656_port(struct mxl111sf_state *state) +{ + mxl_debug("()"); + + return mxl111sf_write_reg_mask(state, 0x12, 0x04, 0x00); +} + +int mxl111sf_enable_usb_output(struct mxl111sf_state *state) +{ + mxl_debug("()"); + + return mxl111sf_write_reg_mask(state, 0x17, 0x40, 0x00); +} + +/* initialize TSIF as input port of MxL1X1SF for MPEG2 data transfer */ +int mxl111sf_config_mpeg_in(struct mxl111sf_state *state, + unsigned int parallel_serial, + unsigned int msb_lsb_1st, + unsigned int clock_phase, + unsigned int mpeg_valid_pol, + unsigned int mpeg_sync_pol) +{ + int ret; + u8 mode, tmp; + + mxl_debug("(%u,%u,%u,%u,%u)", parallel_serial, msb_lsb_1st, + clock_phase, mpeg_valid_pol, mpeg_sync_pol); + + /* Enable PIN MUX */ + ret = mxl111sf_write_reg(state, V6_PIN_MUX_MODE_REG, V6_ENABLE_PIN_MUX); + mxl_fail(ret); + + /* Configure MPEG Clock phase */ + mxl111sf_read_reg(state, V6_MPEG_IN_CLK_INV_REG, &mode); + + if (clock_phase == TSIF_NORMAL) + mode &= ~V6_INVERTED_CLK_PHASE; + else + mode |= V6_INVERTED_CLK_PHASE; + + ret = mxl111sf_write_reg(state, V6_MPEG_IN_CLK_INV_REG, mode); + mxl_fail(ret); + + /* Configure data input mode, MPEG Valid polarity, MPEG Sync polarity + * Get current configuration */ + ret = mxl111sf_read_reg(state, V6_MPEG_IN_CTRL_REG, &mode); + mxl_fail(ret); + + /* Data Input mode */ + if (parallel_serial == TSIF_INPUT_PARALLEL) { + /* Disable serial mode */ + mode &= ~V6_MPEG_IN_DATA_SERIAL; + + /* Enable Parallel mode */ + mode |= V6_MPEG_IN_DATA_PARALLEL; + } else { + /* Disable Parallel mode */ + mode &= ~V6_MPEG_IN_DATA_PARALLEL; + + /* Enable Serial Mode */ + mode |= V6_MPEG_IN_DATA_SERIAL; + + /* If serial interface is chosen, configure + MSB or LSB order in transmission */ + ret = mxl111sf_read_reg(state, + V6_MPEG_INOUT_BIT_ORDER_CTRL_REG, + &tmp); + mxl_fail(ret); + + if (msb_lsb_1st == MPEG_SER_MSB_FIRST_ENABLED) + tmp |= V6_MPEG_SER_MSB_FIRST; + else + tmp &= ~V6_MPEG_SER_MSB_FIRST; + + ret = mxl111sf_write_reg(state, + V6_MPEG_INOUT_BIT_ORDER_CTRL_REG, + tmp); + mxl_fail(ret); + } + + /* MPEG Sync polarity */ + if (mpeg_sync_pol == TSIF_NORMAL) + mode &= ~V6_INVERTED_MPEG_SYNC; + else + mode |= V6_INVERTED_MPEG_SYNC; + + /* MPEG Valid polarity */ + if (mpeg_valid_pol == 0) + mode &= ~V6_INVERTED_MPEG_VALID; + else + mode |= V6_INVERTED_MPEG_VALID; + + ret = mxl111sf_write_reg(state, V6_MPEG_IN_CTRL_REG, mode); + mxl_fail(ret); + + return ret; +} + +int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size) +{ + static struct mxl111sf_reg_ctrl_info init_i2s[] = { + {0x1b, 0xff, 0x1e}, /* pin mux mode, Choose 656/I2S input */ + {0x15, 0x60, 0x60}, /* Enable I2S */ + {0x17, 0xe0, 0x20}, /* Input, MPEG MODE USB, + Inverted 656 Clock, I2S_SOFT_RESET, + 0 : Normal operation, 1 : Reset State */ +#if 0 + {0x12, 0x01, 0x00}, /* AUDIO_IRQ_CLR (Overflow Indicator) */ +#endif + {0x00, 0xff, 0x02}, /* Change to Control Page */ + {0x26, 0x0d, 0x0d}, /* I2S_MODE & BT656_SRC_SEL for FPGA only */ + {0x00, 0xff, 0x00}, + {0, 0, 0} + }; + int ret; + + mxl_debug("(0x%02x)", sample_size); + + ret = mxl111sf_ctrl_program_regs(state, init_i2s); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, V6_I2S_NUM_SAMPLES_REG, sample_size); + mxl_fail(ret); +fail: + return ret; +} + +int mxl111sf_disable_i2s_port(struct mxl111sf_state *state) +{ + static struct mxl111sf_reg_ctrl_info disable_i2s[] = { + {0x15, 0x40, 0x00}, + {0, 0, 0} + }; + + mxl_debug("()"); + + return mxl111sf_ctrl_program_regs(state, disable_i2s); +} + +int mxl111sf_config_i2s(struct mxl111sf_state *state, + u8 msb_start_pos, u8 data_width) +{ + int ret; + u8 tmp; + + mxl_debug("(0x%02x, 0x%02x)", msb_start_pos, data_width); + + ret = mxl111sf_read_reg(state, V6_I2S_STREAM_START_BIT_REG, &tmp); + if (mxl_fail(ret)) + goto fail; + + tmp &= 0xe0; + tmp |= msb_start_pos; + ret = mxl111sf_write_reg(state, V6_I2S_STREAM_START_BIT_REG, tmp); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_read_reg(state, V6_I2S_STREAM_END_BIT_REG, &tmp); + if (mxl_fail(ret)) + goto fail; + + tmp &= 0xe0; + tmp |= data_width; + ret = mxl111sf_write_reg(state, V6_I2S_STREAM_END_BIT_REG, tmp); + mxl_fail(ret); +fail: + return ret; +} + +int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff) +{ + u8 val; + int ret; + + mxl_debug("(%d)", onoff); + + ret = mxl111sf_write_reg(state, 0x00, 0x02); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_read_reg(state, V8_SPI_MODE_REG, &val); + if (mxl_fail(ret)) + goto fail; + + if (onoff) + val |= 0x04; + else + val &= ~0x04; + + ret = mxl111sf_write_reg(state, V8_SPI_MODE_REG, val); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, 0x00, 0x00); + mxl_fail(ret); +fail: + return ret; +} + +int mxl111sf_idac_config(struct mxl111sf_state *state, + u8 control_mode, u8 current_setting, + u8 current_value, u8 hysteresis_value) +{ + int ret; + u8 val; + /* current value will be set for both automatic & manual IDAC control */ + val = current_value; + + if (control_mode == IDAC_MANUAL_CONTROL) { + /* enable manual control of IDAC */ + val |= IDAC_MANUAL_CONTROL_BIT_MASK; + + if (current_setting == IDAC_CURRENT_SINKING_ENABLE) + /* enable current sinking in manual mode */ + val |= IDAC_CURRENT_SINKING_BIT_MASK; + else + /* disable current sinking in manual mode */ + val &= ~IDAC_CURRENT_SINKING_BIT_MASK; + } else { + /* disable manual control of IDAC */ + val &= ~IDAC_MANUAL_CONTROL_BIT_MASK; + + /* set hysteresis value reg: 0x0B<5:0> */ + ret = mxl111sf_write_reg(state, V6_IDAC_HYSTERESIS_REG, + (hysteresis_value & 0x3F)); + mxl_fail(ret); + } + + ret = mxl111sf_write_reg(state, V6_IDAC_SETTINGS_REG, val); + mxl_fail(ret); + + return ret; +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.h new file mode 100644 index 000000000000..f0756071d347 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.h @@ -0,0 +1,53 @@ +/* + * mxl111sf-phy.h - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _DVB_USB_MXL111SF_PHY_H_ +#define _DVB_USB_MXL111SF_PHY_H_ + +#include "mxl111sf.h" + +int mxl1x1sf_soft_reset(struct mxl111sf_state *state); +int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode); +int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff); +int mxl111sf_disable_656_port(struct mxl111sf_state *state); +int mxl111sf_init_tuner_demod(struct mxl111sf_state *state); +int mxl111sf_enable_usb_output(struct mxl111sf_state *state); +int mxl111sf_config_mpeg_in(struct mxl111sf_state *state, + unsigned int parallel_serial, + unsigned int msb_lsb_1st, + unsigned int clock_phase, + unsigned int mpeg_valid_pol, + unsigned int mpeg_sync_pol); +int mxl111sf_config_i2s(struct mxl111sf_state *state, + u8 msb_start_pos, u8 data_width); +int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size); +int mxl111sf_disable_i2s_port(struct mxl111sf_state *state); +int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff); +int mxl111sf_idac_config(struct mxl111sf_state *state, + u8 control_mode, u8 current_setting, + u8 current_value, u8 hysteresis_value); + +#endif /* _DVB_USB_MXL111SF_PHY_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-reg.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-reg.h new file mode 100644 index 000000000000..17831b0fb9db --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/mxl111sf-reg.h @@ -0,0 +1,179 @@ +/* + * mxl111sf-reg.h - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _DVB_USB_MXL111SF_REG_H_ +#define _DVB_USB_MXL111SF_REG_H_ + +#define CHIP_ID_REG 0xFC +#define TOP_CHIP_REV_ID_REG 0xFA + +#define V6_SNR_RB_LSB_REG 0x27 +#define V6_SNR_RB_MSB_REG 0x28 + +#define V6_N_ACCUMULATE_REG 0x11 +#define V6_RS_AVG_ERRORS_LSB_REG 0x2C +#define V6_RS_AVG_ERRORS_MSB_REG 0x2D + +#define V6_IRQ_STATUS_REG 0x24 +#define IRQ_MASK_FEC_LOCK 0x10 + +#define V6_SYNC_LOCK_REG 0x28 +#define SYNC_LOCK_MASK 0x10 + +#define V6_RS_LOCK_DET_REG 0x28 +#define RS_LOCK_DET_MASK 0x08 + +#define V6_INITACQ_NODETECT_REG 0x20 +#define V6_FORCE_NFFT_CPSIZE_REG 0x20 + +#define V6_CODE_RATE_TPS_REG 0x29 +#define V6_CODE_RATE_TPS_MASK 0x07 + + +#define V6_CP_LOCK_DET_REG 0x28 +#define V6_CP_LOCK_DET_MASK 0x04 + +#define V6_TPS_HIERACHY_REG 0x29 +#define V6_TPS_HIERARCHY_INFO_MASK 0x40 + +#define V6_MODORDER_TPS_REG 0x2A +#define V6_PARAM_CONSTELLATION_MASK 0x30 + +#define V6_MODE_TPS_REG 0x2A +#define V6_PARAM_FFT_MODE_MASK 0x0C + + +#define V6_CP_TPS_REG 0x29 +#define V6_PARAM_GI_MASK 0x30 + +#define V6_TPS_LOCK_REG 0x2A +#define V6_PARAM_TPS_LOCK_MASK 0x40 + +#define V6_FEC_PER_COUNT_REG 0x2E +#define V6_FEC_PER_SCALE_REG 0x2B +#define V6_FEC_PER_SCALE_MASK 0x03 +#define V6_FEC_PER_CLR_REG 0x20 +#define V6_FEC_PER_CLR_MASK 0x01 + +#define V6_PIN_MUX_MODE_REG 0x1B +#define V6_ENABLE_PIN_MUX 0x1E + +#define V6_I2S_NUM_SAMPLES_REG 0x16 + +#define V6_MPEG_IN_CLK_INV_REG 0x17 +#define V6_MPEG_IN_CTRL_REG 0x18 + +#define V6_INVERTED_CLK_PHASE 0x20 +#define V6_MPEG_IN_DATA_PARALLEL 0x01 +#define V6_MPEG_IN_DATA_SERIAL 0x02 + +#define V6_INVERTED_MPEG_SYNC 0x04 +#define V6_INVERTED_MPEG_VALID 0x08 + +#define TSIF_INPUT_PARALLEL 0 +#define TSIF_INPUT_SERIAL 1 +#define TSIF_NORMAL 0 + +#define V6_MPEG_INOUT_BIT_ORDER_CTRL_REG 0x19 +#define V6_MPEG_SER_MSB_FIRST 0x80 +#define MPEG_SER_MSB_FIRST_ENABLED 0x01 + +#define V6_656_I2S_BUFF_STATUS_REG 0x2F +#define V6_656_OVERFLOW_MASK_BIT 0x08 +#define V6_I2S_OVERFLOW_MASK_BIT 0x01 + +#define V6_I2S_STREAM_START_BIT_REG 0x14 +#define V6_I2S_STREAM_END_BIT_REG 0x15 +#define I2S_RIGHT_JUSTIFIED 0 +#define I2S_LEFT_JUSTIFIED 1 +#define I2S_DATA_FORMAT 2 + +#define V6_TUNER_LOOP_THRU_CONTROL_REG 0x09 +#define V6_ENABLE_LOOP_THRU 0x01 + +#define TOTAL_NUM_IF_OUTPUT_FREQ 16 + +#define TUNER_NORMAL_IF_SPECTRUM 0x0 +#define TUNER_INVERT_IF_SPECTRUM 0x10 + +#define V6_TUNER_IF_SEL_REG 0x06 +#define V6_TUNER_IF_FCW_REG 0x3C +#define V6_TUNER_IF_FCW_BYP_REG 0x3D +#define V6_RF_LOCK_STATUS_REG 0x23 + +#define NUM_DIG_TV_CHANNEL 1000 + +#define V6_DIG_CLK_FREQ_SEL_REG 0x07 +#define V6_REF_SYNTH_INT_REG 0x5C +#define V6_REF_SYNTH_REMAIN_REG 0x58 +#define V6_DIG_RFREFSELECT_REG 0x32 +#define V6_XTAL_CLK_OUT_GAIN_REG 0x31 +#define V6_TUNER_LOOP_THRU_CTRL_REG 0x09 +#define V6_DIG_XTAL_ENABLE_REG 0x06 +#define V6_DIG_XTAL_BIAS_REG 0x66 +#define V6_XTAL_CAP_REG 0x08 + +#define V6_GPO_CTRL_REG 0x18 +#define MXL_GPO_0 0x00 +#define MXL_GPO_1 0x01 +#define V6_GPO_0_MASK 0x10 +#define V6_GPO_1_MASK 0x20 + +#define V6_111SF_GPO_CTRL_REG 0x19 +#define MXL_111SF_GPO_1 0x00 +#define MXL_111SF_GPO_2 0x01 +#define MXL_111SF_GPO_3 0x02 +#define MXL_111SF_GPO_4 0x03 +#define MXL_111SF_GPO_5 0x04 +#define MXL_111SF_GPO_6 0x05 +#define MXL_111SF_GPO_7 0x06 + +#define MXL_111SF_GPO_0_MASK 0x01 +#define MXL_111SF_GPO_1_MASK 0x02 +#define MXL_111SF_GPO_2_MASK 0x04 +#define MXL_111SF_GPO_3_MASK 0x08 +#define MXL_111SF_GPO_4_MASK 0x10 +#define MXL_111SF_GPO_5_MASK 0x20 +#define MXL_111SF_GPO_6_MASK 0x40 + +#define V6_ATSC_CONFIG_REG 0x0A + +#define MXL_MODE_REG 0x03 +#define START_TUNE_REG 0x1C + +#define V6_IDAC_HYSTERESIS_REG 0x0B +#define V6_IDAC_SETTINGS_REG 0x0C +#define IDAC_MANUAL_CONTROL 1 +#define IDAC_CURRENT_SINKING_ENABLE 1 +#define IDAC_MANUAL_CONTROL_BIT_MASK 0x80 +#define IDAC_CURRENT_SINKING_BIT_MASK 0x40 + +#define V8_SPI_MODE_REG 0xE9 + +#define V6_DIG_RF_PWR_LSB_REG 0x46 +#define V6_DIG_RF_PWR_MSB_REG 0x47 + +#endif /* _DVB_USB_MXL111SF_REG_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.c new file mode 100644 index 000000000000..ef4c65fcbb73 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.c @@ -0,0 +1,527 @@ +/* + * mxl111sf-tuner.c - driver for the MaxLinear MXL111SF CMOS tuner + * + * Copyright (C) 2010 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "mxl111sf-tuner.h" +#include "mxl111sf-phy.h" +#include "mxl111sf-reg.h" + +/* debug */ +static int mxl111sf_tuner_debug; +module_param_named(debug, mxl111sf_tuner_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); + +#define mxl_dbg(fmt, arg...) \ + if (mxl111sf_tuner_debug) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +#define err pr_err + +/* ------------------------------------------------------------------------ */ + +struct mxl111sf_tuner_state { + struct mxl111sf_state *mxl_state; + + struct mxl111sf_tuner_config *cfg; + + enum mxl_if_freq if_freq; + + u32 frequency; + u32 bandwidth; +}; + +static int mxl111sf_tuner_read_reg(struct mxl111sf_tuner_state *state, + u8 addr, u8 *data) +{ + return (state->cfg->read_reg) ? + state->cfg->read_reg(state->mxl_state, addr, data) : + -EINVAL; +} + +static int mxl111sf_tuner_write_reg(struct mxl111sf_tuner_state *state, + u8 addr, u8 data) +{ + return (state->cfg->write_reg) ? + state->cfg->write_reg(state->mxl_state, addr, data) : + -EINVAL; +} + +static int mxl111sf_tuner_program_regs(struct mxl111sf_tuner_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info) +{ + return (state->cfg->program_regs) ? + state->cfg->program_regs(state->mxl_state, ctrl_reg_info) : + -EINVAL; +} + +static int mxl1x1sf_tuner_top_master_ctrl(struct mxl111sf_tuner_state *state, + int onoff) +{ + return (state->cfg->top_master_ctrl) ? + state->cfg->top_master_ctrl(state->mxl_state, onoff) : + -EINVAL; +} + +/* ------------------------------------------------------------------------ */ + +static struct mxl111sf_reg_ctrl_info mxl_phy_tune_rf[] = { + {0x1d, 0x7f, 0x00}, /* channel bandwidth section 1/2/3, + DIG_MODEINDEX, _A, _CSF, */ + {0x1e, 0xff, 0x00}, /* channel frequency (lo and fractional) */ + {0x1f, 0xff, 0x00}, /* channel frequency (hi for integer portion) */ + {0, 0, 0} +}; + +/* ------------------------------------------------------------------------ */ + +static struct mxl111sf_reg_ctrl_info *mxl111sf_calc_phy_tune_regs(u32 freq, + u8 bw) +{ + u8 filt_bw; + + /* set channel bandwidth */ + switch (bw) { + case 0: /* ATSC */ + filt_bw = 25; + break; + case 1: /* QAM */ + filt_bw = 69; + break; + case 6: + filt_bw = 21; + break; + case 7: + filt_bw = 42; + break; + case 8: + filt_bw = 63; + break; + default: + err("%s: invalid bandwidth setting!", __func__); + return NULL; + } + + /* calculate RF channel */ + freq /= 1000000; + + freq *= 64; +#if 0 + /* do round */ + freq += 0.5; +#endif + /* set bandwidth */ + mxl_phy_tune_rf[0].data = filt_bw; + + /* set RF */ + mxl_phy_tune_rf[1].data = (freq & 0xff); + mxl_phy_tune_rf[2].data = (freq >> 8) & 0xff; + + /* start tune */ + return mxl_phy_tune_rf; +} + +static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state) +{ + int ret; + u8 ctrl; +#if 0 + u16 iffcw; + u32 if_freq; +#endif + mxl_dbg("(IF polarity = %d, IF freq = 0x%02x)", + state->cfg->invert_spectrum, state->cfg->if_freq); + + /* set IF polarity */ + ctrl = state->cfg->invert_spectrum; + + ctrl |= state->cfg->if_freq; + + ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_SEL_REG, ctrl); + if (mxl_fail(ret)) + goto fail; + +#if 0 + if_freq /= 1000000; + + /* do round */ + if_freq += 0.5; + + if (MXL_IF_LO == state->cfg->if_freq) { + ctrl = 0x08; + iffcw = (u16)(if_freq / (108 * 4096)); + } else if (MXL_IF_HI == state->cfg->if_freq) { + ctrl = 0x08; + iffcw = (u16)(if_freq / (216 * 4096)); + } else { + ctrl = 0; + iffcw = 0; + } + + ctrl |= (iffcw >> 8); +#endif + ret = mxl111sf_tuner_read_reg(state, V6_TUNER_IF_FCW_BYP_REG, &ctrl); + if (mxl_fail(ret)) + goto fail; + + ctrl &= 0xf0; + ctrl |= 0x90; + + ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_BYP_REG, ctrl); + if (mxl_fail(ret)) + goto fail; + +#if 0 + ctrl = iffcw & 0x00ff; +#endif + ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl); + if (mxl_fail(ret)) + goto fail; + + state->if_freq = state->cfg->if_freq; +fail: + return ret; +} + +static int mxl1x1sf_tune_rf(struct dvb_frontend *fe, u32 freq, u8 bw) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + static struct mxl111sf_reg_ctrl_info *reg_ctrl_array; + int ret; + u8 mxl_mode; + + mxl_dbg("(freq = %d, bw = 0x%x)", freq, bw); + + /* stop tune */ + ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 0); + if (mxl_fail(ret)) + goto fail; + + /* check device mode */ + ret = mxl111sf_tuner_read_reg(state, MXL_MODE_REG, &mxl_mode); + if (mxl_fail(ret)) + goto fail; + + /* Fill out registers for channel tune */ + reg_ctrl_array = mxl111sf_calc_phy_tune_regs(freq, bw); + if (!reg_ctrl_array) + return -EINVAL; + + ret = mxl111sf_tuner_program_regs(state, reg_ctrl_array); + if (mxl_fail(ret)) + goto fail; + + if ((mxl_mode & MXL_DEV_MODE_MASK) == MXL_TUNER_MODE) { + /* IF tuner mode only */ + mxl1x1sf_tuner_top_master_ctrl(state, 0); + mxl1x1sf_tuner_top_master_ctrl(state, 1); + mxl1x1sf_tuner_set_if_output_freq(state); + } + + ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 1); + if (mxl_fail(ret)) + goto fail; + + if (state->cfg->ant_hunt) + state->cfg->ant_hunt(fe); +fail: + return ret; +} + +static int mxl1x1sf_tuner_get_lock_status(struct mxl111sf_tuner_state *state, + int *rf_synth_lock, + int *ref_synth_lock) +{ + int ret; + u8 data; + + *rf_synth_lock = 0; + *ref_synth_lock = 0; + + ret = mxl111sf_tuner_read_reg(state, V6_RF_LOCK_STATUS_REG, &data); + if (mxl_fail(ret)) + goto fail; + + *ref_synth_lock = ((data & 0x03) == 0x03) ? 1 : 0; + *rf_synth_lock = ((data & 0x0c) == 0x0c) ? 1 : 0; +fail: + return ret; +} + +#if 0 +static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state, + int onoff) +{ + return mxl111sf_tuner_write_reg(state, V6_TUNER_LOOP_THRU_CTRL_REG, + onoff ? 1 : 0); +} +#endif + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + struct mxl111sf_tuner_state *state = fe->tuner_priv; + int ret; + u8 bw; + + mxl_dbg("()"); + + switch (delsys) { + case SYS_ATSC: + case SYS_ATSCMH: + bw = 0; /* ATSC */ + break; + case SYS_DVBC_ANNEX_B: + bw = 1; /* US CABLE */ + break; + case SYS_DVBT: + switch (c->bandwidth_hz) { + case 6000000: + bw = 6; + break; + case 7000000: + bw = 7; + break; + case 8000000: + bw = 8; + break; + default: + err("%s: bandwidth not set!", __func__); + return -EINVAL; + } + break; + default: + err("%s: modulation type not supported!", __func__); + return -EINVAL; + } + ret = mxl1x1sf_tune_rf(fe, c->frequency, bw); + if (mxl_fail(ret)) + goto fail; + + state->frequency = c->frequency; + state->bandwidth = c->bandwidth_hz; +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +#if 0 +static int mxl111sf_tuner_init(struct dvb_frontend *fe) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + int ret; + + /* wake from standby handled by usb driver */ + + return ret; +} + +static int mxl111sf_tuner_sleep(struct dvb_frontend *fe) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + int ret; + + /* enter standby mode handled by usb driver */ + + return ret; +} +#endif + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_tuner_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + int rf_locked, ref_locked, ret; + + *status = 0; + + ret = mxl1x1sf_tuner_get_lock_status(state, &rf_locked, &ref_locked); + if (mxl_fail(ret)) + goto fail; + mxl_info("%s%s", rf_locked ? "rf locked " : "", + ref_locked ? "ref locked" : ""); + + if ((rf_locked) || (ref_locked)) + *status |= TUNER_STATUS_LOCKED; +fail: + return ret; +} + +static int mxl111sf_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + u8 val1, val2; + int ret; + + *strength = 0; + + ret = mxl111sf_tuner_write_reg(state, 0x00, 0x02); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_LSB_REG, &val1); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_MSB_REG, &val2); + if (mxl_fail(ret)) + goto fail; + + *strength = val1 | ((val2 & 0x07) << 8); +fail: + ret = mxl111sf_tuner_write_reg(state, 0x00, 0x00); + mxl_fail(ret); + + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_tuner_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + *frequency = state->frequency; + return 0; +} + +static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + *bandwidth = state->bandwidth; + return 0; +} + +static int mxl111sf_tuner_get_if_frequency(struct dvb_frontend *fe, + u32 *frequency) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + + *frequency = 0; + + switch (state->if_freq) { + case MXL_IF_4_0: /* 4.0 MHz */ + *frequency = 4000000; + break; + case MXL_IF_4_5: /* 4.5 MHz */ + *frequency = 4500000; + break; + case MXL_IF_4_57: /* 4.57 MHz */ + *frequency = 4570000; + break; + case MXL_IF_5_0: /* 5.0 MHz */ + *frequency = 5000000; + break; + case MXL_IF_5_38: /* 5.38 MHz */ + *frequency = 5380000; + break; + case MXL_IF_6_0: /* 6.0 MHz */ + *frequency = 6000000; + break; + case MXL_IF_6_28: /* 6.28 MHz */ + *frequency = 6280000; + break; + case MXL_IF_7_2: /* 7.2 MHz */ + *frequency = 7200000; + break; + case MXL_IF_35_25: /* 35.25 MHz */ + *frequency = 35250000; + break; + case MXL_IF_36: /* 36 MHz */ + *frequency = 36000000; + break; + case MXL_IF_36_15: /* 36.15 MHz */ + *frequency = 36150000; + break; + case MXL_IF_44: /* 44 MHz */ + *frequency = 44000000; + break; + } + return 0; +} + +static int mxl111sf_tuner_release(struct dvb_frontend *fe) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + mxl_dbg("()"); + kfree(state); + fe->tuner_priv = NULL; + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = { + .info = { + .name = "MaxLinear MxL111SF", +#if 0 + .frequency_min = , + .frequency_max = , + .frequency_step = , +#endif + }, +#if 0 + .init = mxl111sf_tuner_init, + .sleep = mxl111sf_tuner_sleep, +#endif + .set_params = mxl111sf_tuner_set_params, + .get_status = mxl111sf_tuner_get_status, + .get_rf_strength = mxl111sf_get_rf_strength, + .get_frequency = mxl111sf_tuner_get_frequency, + .get_bandwidth = mxl111sf_tuner_get_bandwidth, + .get_if_frequency = mxl111sf_tuner_get_if_frequency, + .release = mxl111sf_tuner_release, +}; + +struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, + struct mxl111sf_state *mxl_state, + struct mxl111sf_tuner_config *cfg) +{ + struct mxl111sf_tuner_state *state = NULL; + + mxl_dbg("()"); + + state = kzalloc(sizeof(struct mxl111sf_tuner_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + state->mxl_state = mxl_state; + state->cfg = cfg; + + memcpy(&fe->ops.tuner_ops, &mxl111sf_tuner_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = state; + return fe; +} +EXPORT_SYMBOL_GPL(mxl111sf_tuner_attach); + +MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver"); +MODULE_AUTHOR("Michael Krufky "); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.h new file mode 100644 index 000000000000..ff333960b184 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.h @@ -0,0 +1,89 @@ +/* + * mxl111sf-tuner.h - driver for the MaxLinear MXL111SF CMOS tuner + * + * Copyright (C) 2010 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __MXL111SF_TUNER_H__ +#define __MXL111SF_TUNER_H__ + +#include "dvb_frontend.h" + +#include "mxl111sf.h" + +enum mxl_if_freq { +#if 0 + MXL_IF_LO = 0x00, /* other IF < 9MHz */ +#endif + MXL_IF_4_0 = 0x01, /* 4.0 MHz */ + MXL_IF_4_5 = 0x02, /* 4.5 MHz */ + MXL_IF_4_57 = 0x03, /* 4.57 MHz */ + MXL_IF_5_0 = 0x04, /* 5.0 MHz */ + MXL_IF_5_38 = 0x05, /* 5.38 MHz */ + MXL_IF_6_0 = 0x06, /* 6.0 MHz */ + MXL_IF_6_28 = 0x07, /* 6.28 MHz */ + MXL_IF_7_2 = 0x08, /* 7.2 MHz */ + MXL_IF_35_25 = 0x09, /* 35.25 MHz */ + MXL_IF_36 = 0x0a, /* 36 MHz */ + MXL_IF_36_15 = 0x0b, /* 36.15 MHz */ + MXL_IF_44 = 0x0c, /* 44 MHz */ +#if 0 + MXL_IF_HI = 0x0f, /* other IF > 35 MHz and < 45 MHz */ +#endif +}; + +struct mxl111sf_tuner_config { + enum mxl_if_freq if_freq; + unsigned int invert_spectrum:1; + + int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data); + int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data); + int (*program_regs)(struct mxl111sf_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info); + int (*top_master_ctrl)(struct mxl111sf_state *state, int onoff); + int (*ant_hunt)(struct dvb_frontend *fe); +}; + +/* ------------------------------------------------------------------------ */ + +#if defined(CONFIG_DVB_USB_MXL111SF) || \ + (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE)) +extern +struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, + struct mxl111sf_state *mxl_state, + struct mxl111sf_tuner_config *cfg); +#else +static inline +struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, + struct mxl111sf_state *mxl_state + struct mxl111sf_tuner_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __MXL111SF_TUNER_H__ */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ + diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf.c new file mode 100644 index 000000000000..1fb017ecee74 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/mxl111sf.c @@ -0,0 +1,1463 @@ +/* + * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ + +#include +#include + +#include "mxl111sf.h" +#include "mxl111sf-reg.h" +#include "mxl111sf-phy.h" +#include "mxl111sf-i2c.h" +#include "mxl111sf-gpio.h" + +#include "mxl111sf-demod.h" +#include "mxl111sf-tuner.h" + +#include "lgdt3305.h" +#include "lg2160.h" + +int dvb_usb_mxl111sf_debug; +module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level " + "(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able))."); + +int dvb_usb_mxl111sf_isoc; +module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644); +MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc)."); + +int dvb_usb_mxl111sf_spi; +module_param_named(spi, dvb_usb_mxl111sf_spi, int, 0644); +MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi)."); + +#define ANT_PATH_AUTO 0 +#define ANT_PATH_EXTERNAL 1 +#define ANT_PATH_INTERNAL 2 + +int dvb_usb_mxl111sf_rfswitch = +#if 0 + ANT_PATH_AUTO; +#else + ANT_PATH_EXTERNAL; +#endif + +module_param_named(rfswitch, dvb_usb_mxl111sf_rfswitch, int, 0644); +MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int)."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define deb_info pr_debug +#define deb_reg pr_debug +#define deb_adv pr_debug +#define err pr_err +#define info pr_info + +int mxl111sf_ctrl_msg(struct dvb_usb_device *d, + u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + int wo = (rbuf == NULL || rlen == 0); /* write-only */ + int ret; + u8 sndbuf[1+wlen]; + + deb_adv("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen); + + memset(sndbuf, 0, 1+wlen); + + sndbuf[0] = cmd; + memcpy(&sndbuf[1], wbuf, wlen); + + ret = (wo) ? dvb_usbv2_generic_write(d, sndbuf, 1+wlen) : + dvb_usbv2_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen); + mxl_fail(ret); + + return ret; +} + +/* ------------------------------------------------------------------------ */ + +#define MXL_CMD_REG_READ 0xaa +#define MXL_CMD_REG_WRITE 0x55 + +int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data) +{ + u8 buf[2]; + int ret; + + ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_READ, &addr, 1, buf, 2); + if (mxl_fail(ret)) { + mxl_debug("error reading reg: 0x%02x", addr); + goto fail; + } + + if (buf[0] == addr) + *data = buf[1]; + else { + err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x", + addr, buf[0], buf[1]); + ret = -EINVAL; + } + + deb_reg("R: (0x%02x, 0x%02x)\n", addr, *data); +fail: + return ret; +} + +int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data) +{ + u8 buf[] = { addr, data }; + int ret; + + deb_reg("W: (0x%02x, 0x%02x)\n", addr, data); + + ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0); + if (mxl_fail(ret)) + err("error writing reg: 0x%02x, val: 0x%02x", addr, data); + return ret; +} + +/* ------------------------------------------------------------------------ */ + +int mxl111sf_write_reg_mask(struct mxl111sf_state *state, + u8 addr, u8 mask, u8 data) +{ + int ret; + u8 val; + + if (mask != 0xff) { + ret = mxl111sf_read_reg(state, addr, &val); +#if 1 + /* dont know why this usually errors out on the first try */ + if (mxl_fail(ret)) + err("error writing addr: 0x%02x, mask: 0x%02x, " + "data: 0x%02x, retrying...", addr, mask, data); + + ret = mxl111sf_read_reg(state, addr, &val); +#endif + if (mxl_fail(ret)) + goto fail; + } + val &= ~mask; + val |= data; + + ret = mxl111sf_write_reg(state, addr, val); + mxl_fail(ret); +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info) +{ + int i, ret = 0; + + for (i = 0; ctrl_reg_info[i].addr | + ctrl_reg_info[i].mask | + ctrl_reg_info[i].data; i++) { + + ret = mxl111sf_write_reg_mask(state, + ctrl_reg_info[i].addr, + ctrl_reg_info[i].mask, + ctrl_reg_info[i].data); + if (mxl_fail(ret)) { + err("failed on reg #%d (0x%02x)", i, + ctrl_reg_info[i].addr); + break; + } + } + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int mxl1x1sf_get_chip_info(struct mxl111sf_state *state) +{ + int ret; + u8 id, ver; + char *mxl_chip, *mxl_rev; + + if ((state->chip_id) && (state->chip_ver)) + return 0; + + ret = mxl111sf_read_reg(state, CHIP_ID_REG, &id); + if (mxl_fail(ret)) + goto fail; + state->chip_id = id; + + ret = mxl111sf_read_reg(state, TOP_CHIP_REV_ID_REG, &ver); + if (mxl_fail(ret)) + goto fail; + state->chip_ver = ver; + + switch (id) { + case 0x61: + mxl_chip = "MxL101SF"; + break; + case 0x63: + mxl_chip = "MxL111SF"; + break; + default: + mxl_chip = "UNKNOWN MxL1X1"; + break; + } + switch (ver) { + case 0x36: + state->chip_rev = MXL111SF_V6; + mxl_rev = "v6"; + break; + case 0x08: + state->chip_rev = MXL111SF_V8_100; + mxl_rev = "v8_100"; + break; + case 0x18: + state->chip_rev = MXL111SF_V8_200; + mxl_rev = "v8_200"; + break; + default: + state->chip_rev = 0; + mxl_rev = "UNKNOWN REVISION"; + break; + } + info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver); +fail: + return ret; +} + +#define get_chip_info(state) \ +({ \ + int ___ret; \ + ___ret = mxl1x1sf_get_chip_info(state); \ + if (mxl_fail(___ret)) { \ + mxl_debug("failed to get chip info" \ + " on first probe attempt"); \ + ___ret = mxl1x1sf_get_chip_info(state); \ + if (mxl_fail(___ret)) \ + err("failed to get chip info during probe"); \ + else \ + mxl_debug("probe needed a retry " \ + "in order to succeed."); \ + } \ + ___ret; \ +}) + +/* ------------------------------------------------------------------------ */ +#if 0 +static int mxl111sf_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + /* power control depends on which adapter is being woken: + * save this for init, instead, via mxl111sf_adap_fe_init */ + return 0; +} +#endif + +static int mxl111sf_adap_fe_init(struct dvb_frontend *fe) +{ + struct dvb_usb_device *d = fe_to_d(fe); + struct mxl111sf_state *state = fe_to_priv(fe); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id]; + int err; + + /* exit if we didnt initialize the driver yet */ + if (!state->chip_id) { + mxl_debug("driver not yet initialized, exit."); + goto fail; + } + + deb_info("%s()\n", __func__); + + mutex_lock(&state->fe_lock); + + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + err = mxl1x1sf_soft_reset(state); + mxl_fail(err); + err = mxl111sf_init_tuner_demod(state); + mxl_fail(err); + err = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + + mxl_fail(err); + mxl111sf_enable_usb_output(state); + mxl_fail(err); + mxl1x1sf_top_master_ctrl(state, 1); + mxl_fail(err); + + if ((MXL111SF_GPIO_MOD_DVBT != adap_state->gpio_mode) && + (state->chip_rev > MXL111SF_V6)) { + mxl111sf_config_pin_mux_modes(state, + PIN_MUX_TS_SPI_IN_MODE_1); + mxl_fail(err); + } + err = mxl111sf_init_port_expander(state); + if (!mxl_fail(err)) { + state->gpio_mode = adap_state->gpio_mode; + err = mxl111sf_gpio_mode_switch(state, state->gpio_mode); + mxl_fail(err); +#if 0 + err = fe->ops.init(fe); +#endif + msleep(100); /* add short delay after enabling + * the demod before touching it */ + } + + return (adap_state->fe_init) ? adap_state->fe_init(fe) : 0; +fail: + return -ENODEV; +} + +static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe) +{ + struct mxl111sf_state *state = fe_to_priv(fe); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id]; + int err; + + /* exit if we didnt initialize the driver yet */ + if (!state->chip_id) { + mxl_debug("driver not yet initialized, exit."); + goto fail; + } + + deb_info("%s()\n", __func__); + + err = (adap_state->fe_sleep) ? adap_state->fe_sleep(fe) : 0; + + mutex_unlock(&state->fe_lock); + + return err; +fail: + return -ENODEV; +} + + +static int mxl111sf_ep6_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct mxl111sf_state *state = fe_to_priv(fe); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id]; + int ret = 0; + + deb_info("%s(%d)\n", __func__, onoff); + + if (onoff) { + ret = mxl111sf_enable_usb_output(state); + mxl_fail(ret); + ret = mxl111sf_config_mpeg_in(state, 1, 1, + adap_state->ep6_clockphase, + 0, 0); + mxl_fail(ret); +#if 0 + } else { + ret = mxl111sf_disable_656_port(state); + mxl_fail(ret); +#endif + } + + return ret; +} + +static int mxl111sf_ep5_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct mxl111sf_state *state = fe_to_priv(fe); + int ret = 0; + + deb_info("%s(%d)\n", __func__, onoff); + + if (onoff) { + ret = mxl111sf_enable_usb_output(state); + mxl_fail(ret); + + ret = mxl111sf_init_i2s_port(state, 200); + mxl_fail(ret); + ret = mxl111sf_config_i2s(state, 0, 15); + mxl_fail(ret); + } else { + ret = mxl111sf_disable_i2s_port(state); + mxl_fail(ret); + } + if (state->chip_rev > MXL111SF_V6) + ret = mxl111sf_config_spi(state, onoff); + mxl_fail(ret); + + return ret; +} + +static int mxl111sf_ep4_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct mxl111sf_state *state = fe_to_priv(fe); + int ret = 0; + + deb_info("%s(%d)\n", __func__, onoff); + + if (onoff) { + ret = mxl111sf_enable_usb_output(state); + mxl_fail(ret); + } + + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static struct lgdt3305_config hauppauge_lgdt3305_config = { + .i2c_addr = 0xb2 >> 1, + .mpeg_mode = LGDT3305_MPEG_SERIAL, + .tpclk_edge = LGDT3305_TPCLK_RISING_EDGE, + .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .qam_if_khz = 6000, + .vsb_if_khz = 6000, +}; + +static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct mxl111sf_state *state = d_to_priv(d); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; + int ret; + + deb_adv("%s()\n", __func__); + + /* save a pointer to the dvb_usb_device in device state */ + state->d = d; + adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + state->gpio_mode = MXL111SF_GPIO_MOD_ATSC; + adap_state->gpio_mode = state->gpio_mode; + adap_state->device_mode = MXL_TUNER_MODE; + adap_state->ep6_clockphase = 1; + + ret = mxl1x1sf_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_init_tuner_demod(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_enable_usb_output(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_top_master_ctrl(state, 1); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_init_port_expander(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); + if (mxl_fail(ret)) + goto fail; + + adap->fe[fe_id] = dvb_attach(lgdt3305_attach, + &hauppauge_lgdt3305_config, + &d->i2c_adap); + if (adap->fe[fe_id]) { + state->num_frontends++; + adap_state->fe_init = adap->fe[fe_id]->ops.init; + adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; + adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; + return 0; + } + ret = -EIO; +fail: + return ret; +} + +static struct lg2160_config hauppauge_lg2160_config = { + .lg_chip = LG2160, + .i2c_addr = 0x1c >> 1, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .if_khz = 6000, +}; + +static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct mxl111sf_state *state = d_to_priv(d); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; + int ret; + + deb_adv("%s()\n", __func__); + + /* save a pointer to the dvb_usb_device in device state */ + state->d = d; + adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + state->gpio_mode = MXL111SF_GPIO_MOD_MH; + adap_state->gpio_mode = state->gpio_mode; + adap_state->device_mode = MXL_TUNER_MODE; + adap_state->ep6_clockphase = 1; + + ret = mxl1x1sf_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_init_tuner_demod(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_enable_usb_output(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_top_master_ctrl(state, 1); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_init_port_expander(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); + if (mxl_fail(ret)) + goto fail; + + ret = get_chip_info(state); + if (mxl_fail(ret)) + goto fail; + + adap->fe[fe_id] = dvb_attach(lg2160_attach, + &hauppauge_lg2160_config, + &d->i2c_adap); + if (adap->fe[fe_id]) { + state->num_frontends++; + adap_state->fe_init = adap->fe[fe_id]->ops.init; + adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; + adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; + return 0; + } + ret = -EIO; +fail: + return ret; +} + +static struct lg2160_config hauppauge_lg2161_1019_config = { + .lg_chip = LG2161_1019, + .i2c_addr = 0x1c >> 1, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .if_khz = 6000, + .output_if = 2, /* LG2161_OIF_SPI_MAS */ +}; + +static struct lg2160_config hauppauge_lg2161_1040_config = { + .lg_chip = LG2161_1040, + .i2c_addr = 0x1c >> 1, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .if_khz = 6000, + .output_if = 4, /* LG2161_OIF_SPI_MAS */ +}; + +static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct mxl111sf_state *state = d_to_priv(d); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; + int ret; + + deb_adv("%s()\n", __func__); + + /* save a pointer to the dvb_usb_device in device state */ + state->d = d; + adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + state->gpio_mode = MXL111SF_GPIO_MOD_MH; + adap_state->gpio_mode = state->gpio_mode; + adap_state->device_mode = MXL_TUNER_MODE; + adap_state->ep6_clockphase = 1; + + ret = mxl1x1sf_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_init_tuner_demod(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_enable_usb_output(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_top_master_ctrl(state, 1); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_init_port_expander(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); + if (mxl_fail(ret)) + goto fail; + + ret = get_chip_info(state); + if (mxl_fail(ret)) + goto fail; + + adap->fe[fe_id] = dvb_attach(lg2160_attach, + (MXL111SF_V8_200 == state->chip_rev) ? + &hauppauge_lg2161_1040_config : + &hauppauge_lg2161_1019_config, + &d->i2c_adap); + if (adap->fe[fe_id]) { + state->num_frontends++; + adap_state->fe_init = adap->fe[fe_id]->ops.init; + adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; + adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; + return 0; + } + ret = -EIO; +fail: + return ret; +} + +static struct lg2160_config hauppauge_lg2161_1019_ep6_config = { + .lg_chip = LG2161_1019, + .i2c_addr = 0x1c >> 1, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .if_khz = 6000, + .output_if = 1, /* LG2161_OIF_SERIAL_TS */ +}; + +static struct lg2160_config hauppauge_lg2161_1040_ep6_config = { + .lg_chip = LG2161_1040, + .i2c_addr = 0x1c >> 1, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .if_khz = 6000, + .output_if = 7, /* LG2161_OIF_SERIAL_TS */ +}; + +static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct mxl111sf_state *state = d_to_priv(d); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; + int ret; + + deb_adv("%s()\n", __func__); + + /* save a pointer to the dvb_usb_device in device state */ + state->d = d; + adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + state->gpio_mode = MXL111SF_GPIO_MOD_MH; + adap_state->gpio_mode = state->gpio_mode; + adap_state->device_mode = MXL_TUNER_MODE; + adap_state->ep6_clockphase = 0; + + ret = mxl1x1sf_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_init_tuner_demod(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_enable_usb_output(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_top_master_ctrl(state, 1); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_init_port_expander(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); + if (mxl_fail(ret)) + goto fail; + + ret = get_chip_info(state); + if (mxl_fail(ret)) + goto fail; + + adap->fe[fe_id] = dvb_attach(lg2160_attach, + (MXL111SF_V8_200 == state->chip_rev) ? + &hauppauge_lg2161_1040_ep6_config : + &hauppauge_lg2161_1019_ep6_config, + &d->i2c_adap); + if (adap->fe[fe_id]) { + state->num_frontends++; + adap_state->fe_init = adap->fe[fe_id]->ops.init; + adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; + adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; + return 0; + } + ret = -EIO; +fail: + return ret; +} + +static struct mxl111sf_demod_config mxl_demod_config = { + .read_reg = mxl111sf_read_reg, + .write_reg = mxl111sf_write_reg, + .program_regs = mxl111sf_ctrl_program_regs, +}; + +static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap, u8 fe_id) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct mxl111sf_state *state = d_to_priv(d); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; + int ret; + + deb_adv("%s()\n", __func__); + + /* save a pointer to the dvb_usb_device in device state */ + state->d = d; + adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 1 : 2; + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + state->gpio_mode = MXL111SF_GPIO_MOD_DVBT; + adap_state->gpio_mode = state->gpio_mode; + adap_state->device_mode = MXL_SOC_MODE; + adap_state->ep6_clockphase = 1; + + ret = mxl1x1sf_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_init_tuner_demod(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_enable_usb_output(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_top_master_ctrl(state, 1); + if (mxl_fail(ret)) + goto fail; + + /* dont care if this fails */ + mxl111sf_init_port_expander(state); + + adap->fe[fe_id] = dvb_attach(mxl111sf_demod_attach, state, + &mxl_demod_config); + if (adap->fe[fe_id]) { + state->num_frontends++; + adap_state->fe_init = adap->fe[fe_id]->ops.init; + adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; + adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; + return 0; + } + ret = -EIO; +fail: + return ret; +} + +static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state, + int antpath) +{ + return mxl111sf_idac_config(state, 1, 1, + (antpath == ANT_PATH_INTERNAL) ? + 0x3f : 0x00, 0); +} + +#define DbgAntHunt(x, pwr0, pwr1, pwr2, pwr3) \ + err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \ + __func__, __LINE__, \ + (ANT_PATH_EXTERNAL == x) ? "EXTERNAL" : "INTERNAL", \ + pwr0, pwr1, pwr2, pwr3) + +#define ANT_HUNT_SLEEP 90 +#define ANT_EXT_TWEAK 0 + +static int mxl111sf_ant_hunt(struct dvb_frontend *fe) +{ + struct mxl111sf_state *state = fe_to_priv(fe); + int antctrl = dvb_usb_mxl111sf_rfswitch; + + u16 rxPwrA, rxPwr0, rxPwr1, rxPwr2; + + /* FIXME: must force EXTERNAL for QAM - done elsewhere */ + mxl111sf_set_ant_path(state, antctrl == ANT_PATH_AUTO ? + ANT_PATH_EXTERNAL : antctrl); + + if (antctrl == ANT_PATH_AUTO) { +#if 0 + msleep(ANT_HUNT_SLEEP); +#endif + fe->ops.tuner_ops.get_rf_strength(fe, &rxPwrA); + + mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); + msleep(ANT_HUNT_SLEEP); + fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr0); + + mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); + msleep(ANT_HUNT_SLEEP); + fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr1); + + mxl111sf_set_ant_path(state, ANT_PATH_INTERNAL); + msleep(ANT_HUNT_SLEEP); + fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr2); + + if (rxPwr1+ANT_EXT_TWEAK >= rxPwr2) { + /* return with EXTERNAL enabled */ + mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); + DbgAntHunt(ANT_PATH_EXTERNAL, rxPwrA, + rxPwr0, rxPwr1, rxPwr2); + } else { + /* return with INTERNAL enabled */ + DbgAntHunt(ANT_PATH_INTERNAL, rxPwrA, + rxPwr0, rxPwr1, rxPwr2); + } + } + return 0; +} + +static struct mxl111sf_tuner_config mxl_tuner_config = { + .if_freq = MXL_IF_6_0, /* applies to external IF output, only */ + .invert_spectrum = 0, + .read_reg = mxl111sf_read_reg, + .write_reg = mxl111sf_write_reg, + .program_regs = mxl111sf_ctrl_program_regs, + .top_master_ctrl = mxl1x1sf_top_master_ctrl, + .ant_hunt = mxl111sf_ant_hunt, +}; + +static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap) +{ + struct mxl111sf_state *state = adap_to_priv(adap); + int i; + + deb_adv("%s()\n", __func__); + + for (i = 0; i < state->num_frontends; i++) { + if (dvb_attach(mxl111sf_tuner_attach, adap->fe[i], state, + &mxl_tuner_config) == NULL) + return -EIO; + } + + return 0; +} + +static int mxl111sf_fe_ioctl_override(struct dvb_frontend *fe, + unsigned int cmd, void *parg, + unsigned int stage) +{ + int err = 0; + + switch (stage) { + case DVB_FE_IOCTL_PRE: + + switch (cmd) { + case FE_READ_SIGNAL_STRENGTH: + err = fe->ops.tuner_ops.get_rf_strength(fe, parg); + /* If no error occurs, prevent dvb-core from handling + * this IOCTL, otherwise return the error */ + if (0 == err) + err = 1; + break; + } + break; + + case DVB_FE_IOCTL_POST: + /* no post-ioctl handling required */ + break; + } + return err; +}; + +static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +struct i2c_algorithm mxl111sf_i2c_algo = { + .master_xfer = mxl111sf_i2c_xfer, + .functionality = mxl111sf_i2c_func, +#ifdef NEED_ALGO_CONTROL + .algo_control = dummy_algo_control, +#endif +}; + +static int mxl111sf_init(struct dvb_usb_device *d) +{ + struct mxl111sf_state *state = d_to_priv(d); + int ret; + static u8 eeprom[256]; + struct i2c_client c; + + ret = get_chip_info(state); + if (mxl_fail(ret)) + err("failed to get chip info during probe"); + + mutex_init(&state->fe_lock); + + if (state->chip_rev > MXL111SF_V6) + mxl111sf_config_pin_mux_modes(state, PIN_MUX_TS_SPI_IN_MODE_1); + + c.adapter = &d->i2c_adap; + c.addr = 0xa0 >> 1; + + ret = tveeprom_read(&c, eeprom, sizeof(eeprom)); + if (mxl_fail(ret)) + return 0; + tveeprom_hauppauge_analog(&c, &state->tv, (0x84 == eeprom[0xa0]) ? + eeprom + 0xa0 : eeprom + 0x80); +#if 0 + switch (state->tv.model) { + case 117001: + case 126001: + case 138001: + break; + default: + printk(KERN_WARNING "%s: warning: " + "unknown hauppauge model #%d\n", + __func__, state->tv.model); + } +#endif + return 0; +} + +static int mxl111sf_frontend_attach_dvbt(struct dvb_usb_adapter *adap) +{ + return mxl111sf_attach_demod(adap, 0); +} + +static int mxl111sf_frontend_attach_atsc(struct dvb_usb_adapter *adap) +{ + return mxl111sf_lgdt3305_frontend_attach(adap, 0); +} + +static int mxl111sf_frontend_attach_mh(struct dvb_usb_adapter *adap) +{ + return mxl111sf_lg2160_frontend_attach(adap, 0); +} + +static int mxl111sf_frontend_attach_atsc_mh(struct dvb_usb_adapter *adap) +{ + int ret; + deb_info("%s\n", __func__); + + ret = mxl111sf_lgdt3305_frontend_attach(adap, 0); + if (ret < 0) + return ret; + + ret = mxl111sf_attach_demod(adap, 1); + if (ret < 0) + return ret; + + ret = mxl111sf_lg2160_frontend_attach(adap, 2); + if (ret < 0) + return ret; + + return ret; +} + +static int mxl111sf_frontend_attach_mercury(struct dvb_usb_adapter *adap) +{ + int ret; + deb_info("%s\n", __func__); + + ret = mxl111sf_lgdt3305_frontend_attach(adap, 0); + if (ret < 0) + return ret; + + ret = mxl111sf_attach_demod(adap, 1); + if (ret < 0) + return ret; + + ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 2); + if (ret < 0) + return ret; + + return ret; +} + +static int mxl111sf_frontend_attach_mercury_mh(struct dvb_usb_adapter *adap) +{ + int ret; + deb_info("%s\n", __func__); + + ret = mxl111sf_attach_demod(adap, 0); + if (ret < 0) + return ret; + + if (dvb_usb_mxl111sf_spi) + ret = mxl111sf_lg2161_frontend_attach(adap, 1); + else + ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 1); + + return ret; +} + +static void mxl111sf_stream_config_bulk(struct usb_data_stream_properties *stream, u8 endpoint) +{ + deb_info("%s: endpoint=%d size=8192\n", __func__, endpoint); + stream->type = USB_BULK; + stream->count = 5; + stream->endpoint = endpoint; + stream->u.bulk.buffersize = 8192; +} + +static void mxl111sf_stream_config_isoc(struct usb_data_stream_properties *stream, + u8 endpoint, int framesperurb, int framesize) +{ + deb_info("%s: endpoint=%d size=%d\n", __func__, endpoint, + framesperurb * framesize); + stream->type = USB_ISOC; + stream->count = 5; + stream->endpoint = endpoint; + stream->u.isoc.framesperurb = framesperurb; + stream->u.isoc.framesize = framesize; + stream->u.isoc.interval = 1; +} + +/* DVB USB Driver stuff */ + +/* dvbt mxl111sf + * bulk EP4/BULK/5/8192 + * isoc EP4/ISOC/5/96/564 + */ +static int mxl111sf_get_stream_config_dvbt(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 4, 96, 564); + else + mxl111sf_stream_config_bulk(stream, 4); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_dvbt = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_dvbt, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, + .get_stream_config = mxl111sf_get_stream_config_dvbt, + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } + } +}; + +/* atsc lgdt3305 + * bulk EP6/BULK/5/8192 + * isoc EP6/ISOC/5/24/3072 + */ +static int mxl111sf_get_stream_config_atsc(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 6, 24, 3072); + else + mxl111sf_stream_config_bulk(stream, 6); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_atsc = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_atsc, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, + .get_stream_config = mxl111sf_get_stream_config_atsc, + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } + } +}; + +/* mh lg2160 + * bulk EP5/BULK/5/8192/RAW + * isoc EP5/ISOC/5/96/200/RAW + */ +static int mxl111sf_get_stream_config_mh(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 5, 96, 200); + else + mxl111sf_stream_config_bulk(stream, 5); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_mh = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_mh, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_ep5_streaming_ctrl, + .get_stream_config = mxl111sf_get_stream_config_mh, + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } + } +}; + +/* atsc mh lgdt3305 mxl111sf lg2160 + * bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP5/BULK/5/8192/RAW + * isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW + */ +static int mxl111sf_get_stream_config_atsc_mh(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + if (fe->id == 0) { + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 6, 24, 3072); + else + mxl111sf_stream_config_bulk(stream, 6); + } else if (fe->id == 1) { + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 4, 96, 564); + else + mxl111sf_stream_config_bulk(stream, 4); + } else if (fe->id == 2) { + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 5, 96, 200); + else + mxl111sf_stream_config_bulk(stream, 5); + } + return 0; +} + +static int mxl111sf_streaming_ctrl_atsc_mh(struct dvb_frontend *fe, int onoff) +{ + deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); + + if (fe->id == 0) + return mxl111sf_ep6_streaming_ctrl(fe, onoff); + else if (fe->id == 1) + return mxl111sf_ep4_streaming_ctrl(fe, onoff); + else if (fe->id == 2) + return mxl111sf_ep5_streaming_ctrl(fe, onoff); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_atsc_mh = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_atsc_mh, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_streaming_ctrl_atsc_mh, + .get_stream_config = mxl111sf_get_stream_config_atsc_mh, + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } + } +}; + +/* mercury lgdt3305 mxl111sf lg2161 + * tp bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP6/BULK/5/8192/RAW + * tp isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP6/ISOC/5/24/3072/RAW + * spi bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP5/BULK/5/8192/RAW + * spi isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW + */ +static int mxl111sf_get_stream_config_mercury(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + if (fe->id == 0) { + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 6, 24, 3072); + else + mxl111sf_stream_config_bulk(stream, 6); + } else if (fe->id == 1) { + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 4, 96, 564); + else + mxl111sf_stream_config_bulk(stream, 4); + } else if (fe->id == 2 && dvb_usb_mxl111sf_spi) { + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 5, 96, 200); + else + mxl111sf_stream_config_bulk(stream, 5); + } else if (fe->id == 2 && !dvb_usb_mxl111sf_spi) { + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 6, 24, 3072); + else + mxl111sf_stream_config_bulk(stream, 6); + } + return 0; +} + +static int mxl111sf_streaming_ctrl_mercury(struct dvb_frontend *fe, int onoff) +{ + deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); + + if (fe->id == 0) + return mxl111sf_ep6_streaming_ctrl(fe, onoff); + else if (fe->id == 1) + return mxl111sf_ep4_streaming_ctrl(fe, onoff); + else if (fe->id == 2 && dvb_usb_mxl111sf_spi) + return mxl111sf_ep5_streaming_ctrl(fe, onoff); + else if (fe->id == 2 && !dvb_usb_mxl111sf_spi) + return mxl111sf_ep6_streaming_ctrl(fe, onoff); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_mercury = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_mercury, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_streaming_ctrl_mercury, + .get_stream_config = mxl111sf_get_stream_config_mercury, + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } + } +}; + +/* mercury mh mxl111sf lg2161 + * tp bulk EP4/BULK/5/8192 EP6/BULK/5/8192/RAW + * tp isoc EP4/ISOC/5/96/564 EP6/ISOC/5/24/3072/RAW + * spi bulk EP4/BULK/5/8192 EP5/BULK/5/8192/RAW + * spi isoc EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW + */ +static int mxl111sf_get_stream_config_mercury_mh(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + if (fe->id == 0) { + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 4, 96, 564); + else + mxl111sf_stream_config_bulk(stream, 4); + } else if (fe->id == 1 && dvb_usb_mxl111sf_spi) { + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 5, 96, 200); + else + mxl111sf_stream_config_bulk(stream, 5); + } else if (fe->id == 1 && !dvb_usb_mxl111sf_spi) { + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 6, 24, 3072); + else + mxl111sf_stream_config_bulk(stream, 6); + } + return 0; +} + +static int mxl111sf_streaming_ctrl_mercury_mh(struct dvb_frontend *fe, int onoff) +{ + deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); + + if (fe->id == 0) + return mxl111sf_ep4_streaming_ctrl(fe, onoff); + else if (fe->id == 1 && dvb_usb_mxl111sf_spi) + return mxl111sf_ep5_streaming_ctrl(fe, onoff); + else if (fe->id == 1 && !dvb_usb_mxl111sf_spi) + return mxl111sf_ep6_streaming_ctrl(fe, onoff); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_mercury_mh = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_mercury_mh, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_streaming_ctrl_mercury_mh, + .get_stream_config = mxl111sf_get_stream_config_mercury_mh, + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } + } +}; + +static const struct usb_device_id mxl111sf_id_table[] = { + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc600, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc601, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc602, &mxl111sf_props_mh, "HCW 126xxx", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc603, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc604, &mxl111sf_props_dvbt, "Hauppauge 126xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc609, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60a, &mxl111sf_props_mh, "HCW 126xxx", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60b, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60c, &mxl111sf_props_dvbt, "Hauppauge 126xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc653, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc65b, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb700, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb701, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb702, &mxl111sf_props_mh, "HCW 117xxx", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb703, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb704, &mxl111sf_props_dvbt, "Hauppauge 117xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb753, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb763, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb764, &mxl111sf_props_dvbt, "Hauppauge 117xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd853, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd854, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd863, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd864, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d3, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d4, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e3, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e4, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8ff, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc612, &mxl111sf_props_mercury_mh, "Hauppauge 126xxx", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc613, &mxl111sf_props_mercury, "Hauppauge WinTV-Aero-M", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61a, &mxl111sf_props_mercury_mh, "Hauppauge 126xxx", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61b, &mxl111sf_props_mercury, "Hauppauge WinTV-Aero-M", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb757, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb767, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { } +}; +MODULE_DEVICE_TABLE(usb, mxl111sf_id_table); + +static struct usb_driver mxl111sf_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = mxl111sf_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(mxl111sf_usb_driver); + +MODULE_AUTHOR("Michael Krufky "); +MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf.h new file mode 100644 index 000000000000..9816de86e48c --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/mxl111sf.h @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ + +#ifndef _DVB_USB_MXL111SF_H_ +#define _DVB_USB_MXL111SF_H_ + +#ifdef DVB_USB_LOG_PREFIX +#undef DVB_USB_LOG_PREFIX +#endif +#define DVB_USB_LOG_PREFIX "mxl111sf" +#include "dvb_usb.h" +#include + +#define MXL_EP1_REG_READ 1 +#define MXL_EP2_REG_WRITE 2 +#define MXL_EP3_INTERRUPT 3 +#define MXL_EP4_MPEG2 4 +#define MXL_EP5_I2S 5 +#define MXL_EP6_656 6 +#define MXL_EP6_MPEG2 6 + +#ifdef USING_ENUM_mxl111sf_current_mode +enum mxl111sf_current_mode { + mxl_mode_dvbt = MXL_EP4_MPEG2, + mxl_mode_mh = MXL_EP5_I2S, + mxl_mode_atsc = MXL_EP6_MPEG2, +}; +#endif + +enum mxl111sf_gpio_port_expander { + mxl111sf_gpio_hw, + mxl111sf_PCA9534, +}; + +struct mxl111sf_adap_state { + int alt_mode; + int gpio_mode; + int device_mode; + int ep6_clockphase; + int (*fe_init)(struct dvb_frontend *); + int (*fe_sleep)(struct dvb_frontend *); +}; + +struct mxl111sf_state { + struct dvb_usb_device *d; + + enum mxl111sf_gpio_port_expander gpio_port_expander; + u8 port_expander_addr; + + u8 chip_id; + u8 chip_ver; +#define MXL111SF_V6 1 +#define MXL111SF_V8_100 2 +#define MXL111SF_V8_200 3 + u8 chip_rev; + +#ifdef USING_ENUM_mxl111sf_current_mode + enum mxl111sf_current_mode current_mode; +#endif + +#define MXL_TUNER_MODE 0 +#define MXL_SOC_MODE 1 +#define MXL_DEV_MODE_MASK 0x01 +#if 1 + int device_mode; +#endif + /* use usb alt setting 1 for EP4 ISOC transfer (dvb-t), + EP5 BULK transfer (atsc-mh), + EP6 BULK transfer (atsc/qam), + use usb alt setting 2 for EP4 BULK transfer (dvb-t), + EP5 ISOC transfer (atsc-mh), + EP6 ISOC transfer (atsc/qam), + */ + int alt_mode; + int gpio_mode; + struct tveeprom tv; + + struct mutex fe_lock; + u8 num_frontends; + struct mxl111sf_adap_state adap_state[3]; +}; + +int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data); +int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data); + +struct mxl111sf_reg_ctrl_info { + u8 addr; + u8 mask; + u8 data; +}; + +int mxl111sf_write_reg_mask(struct mxl111sf_state *state, + u8 addr, u8 mask, u8 data); +int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info); + +/* needed for hardware i2c functions in mxl111sf-i2c.c: + * mxl111sf_i2c_send_data / mxl111sf_i2c_get_data */ +int mxl111sf_ctrl_msg(struct dvb_usb_device *d, + u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen); + +#define mxl_printk(kern, fmt, arg...) \ + printk(kern "%s: " fmt "\n", __func__, ##arg) + +#define mxl_info(fmt, arg...) \ + mxl_printk(KERN_INFO, fmt, ##arg) + +extern int dvb_usb_mxl111sf_debug; +#define mxl_debug(fmt, arg...) \ + if (dvb_usb_mxl111sf_debug) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +#define MXL_I2C_DBG 0x04 +#define MXL_ADV_DBG 0x10 +#define mxl_debug_adv(fmt, arg...) \ + if (dvb_usb_mxl111sf_debug & MXL_ADV_DBG) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +#define mxl_i2c(fmt, arg...) \ + if (dvb_usb_mxl111sf_debug & MXL_I2C_DBG) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +#define mxl_i2c_adv(fmt, arg...) \ + if ((dvb_usb_mxl111sf_debug & (MXL_I2C_DBG | MXL_ADV_DBG)) == \ + (MXL_I2C_DBG | MXL_ADV_DBG)) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +/* The following allows the mxl_fail() macro defined below to work + * in externel modules, such as mxl111sf-tuner.ko, even though + * dvb_usb_mxl111sf_debug is not defined within those modules */ +#if (defined(__MXL111SF_TUNER_H__)) || (defined(__MXL111SF_DEMOD_H__)) +#define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG +#else +#define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug +#endif + +#define mxl_fail(ret) \ +({ \ + int __ret; \ + __ret = (ret < 0); \ + if ((__ret) && (MXL_ADV_DEBUG_ENABLED & MXL_ADV_DBG)) \ + mxl_printk(KERN_ERR, "error %d on line %d", \ + ret, __LINE__); \ + __ret; \ +}) + +#endif /* _DVB_USB_MXL111SF_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb-v2/usb_urb.c b/drivers/media/dvb/dvb-usb-v2/usb_urb.c new file mode 100644 index 000000000000..eaf673a3978d --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/usb_urb.c @@ -0,0 +1,357 @@ +/* usb-urb.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file keeps functions for initializing and handling the + * BULK and ISOC USB data transfers in a generic way. + * Can be used for DVB-only and also, that's the plan, for + * Hybrid USB devices (analog and DVB). + */ +#include "dvb_usb_common.h" + +/* URB stuff for streaming */ + +int usb_urb_reconfig(struct usb_data_stream *stream, + struct usb_data_stream_properties *props); + +static void usb_urb_complete(struct urb *urb) +{ + struct usb_data_stream *stream = urb->context; + int ptype = usb_pipetype(urb->pipe); + int i; + u8 *b; + + dev_dbg(&stream->udev->dev, "%s: %s urb completed status=%d " \ + "length=%d/%d pack_num=%d errors=%d\n", __func__, + ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", + urb->status, urb->actual_length, + urb->transfer_buffer_length, + urb->number_of_packets, urb->error_count); + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + dev_dbg(&stream->udev->dev, "%s: urb completition failed=%d\n", + __func__, urb->status); + break; + } + + b = (u8 *) urb->transfer_buffer; + switch (ptype) { + case PIPE_ISOCHRONOUS: + for (i = 0; i < urb->number_of_packets; i++) { + if (urb->iso_frame_desc[i].status != 0) + dev_dbg(&stream->udev->dev, "%s: iso frame " \ + "descriptor has an error=%d\n", + __func__, + urb->iso_frame_desc[i].status); + else if (urb->iso_frame_desc[i].actual_length > 0) + stream->complete(stream, + b + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); + + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + break; + case PIPE_BULK: + if (urb->actual_length > 0) + stream->complete(stream, b, urb->actual_length); + break; + default: + dev_err(&stream->udev->dev, "%s: unknown endpoint type in " \ + "completition handler\n", KBUILD_MODNAME); + return; + } + usb_submit_urb(urb, GFP_ATOMIC); +} + +int usb_urb_killv2(struct usb_data_stream *stream) +{ + int i; + for (i = 0; i < stream->urbs_submitted; i++) { + dev_dbg(&stream->udev->dev, "%s: kill urb=%d\n", __func__, i); + /* stop the URB */ + usb_kill_urb(stream->urb_list[i]); + } + stream->urbs_submitted = 0; + return 0; +} + +int usb_urb_submitv2(struct usb_data_stream *stream, + struct usb_data_stream_properties *props) +{ + int i, ret; + + if (props) { + ret = usb_urb_reconfig(stream, props); + if (ret < 0) + return ret; + } + + for (i = 0; i < stream->urbs_initialized; i++) { + dev_dbg(&stream->udev->dev, "%s: submit urb=%d\n", __func__, i); + ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC); + if (ret) { + dev_err(&stream->udev->dev, "%s: could not submit " \ + "urb no. %d - get them all back\n", + KBUILD_MODNAME, i); + usb_urb_killv2(stream); + return ret; + } + stream->urbs_submitted++; + } + return 0; +} + +int usb_urb_free_urbs(struct usb_data_stream *stream) +{ + int i; + + usb_urb_killv2(stream); + + for (i = stream->urbs_initialized - 1; i >= 0; i--) { + if (stream->urb_list[i]) { + dev_dbg(&stream->udev->dev, "%s: free urb=%d\n", + __func__, i); + /* free the URBs */ + usb_free_urb(stream->urb_list[i]); + } + } + stream->urbs_initialized = 0; + + return 0; +} + +static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream) +{ + int i, j; + + /* allocate the URBs */ + for (i = 0; i < stream->props.count; i++) { + dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i); + stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); + if (!stream->urb_list[i]) { + dev_dbg(&stream->udev->dev, "%s: failed\n", __func__); + for (j = 0; j < i; j++) + usb_free_urb(stream->urb_list[j]); + return -ENOMEM; + } + usb_fill_bulk_urb(stream->urb_list[i], + stream->udev, + usb_rcvbulkpipe(stream->udev, + stream->props.endpoint), + stream->buf_list[i], + stream->props.u.bulk.buffersize, + usb_urb_complete, stream); + + stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + stream->urb_list[i]->transfer_dma = stream->dma_addr[i]; + stream->urbs_initialized++; + } + return 0; +} + +static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream) +{ + int i, j; + + /* allocate the URBs */ + for (i = 0; i < stream->props.count; i++) { + struct urb *urb; + int frame_offset = 0; + dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i); + stream->urb_list[i] = usb_alloc_urb( + stream->props.u.isoc.framesperurb, GFP_ATOMIC); + if (!stream->urb_list[i]) { + dev_dbg(&stream->udev->dev, "%s: failed\n", __func__); + for (j = 0; j < i; j++) + usb_free_urb(stream->urb_list[j]); + return -ENOMEM; + } + + urb = stream->urb_list[i]; + + urb->dev = stream->udev; + urb->context = stream; + urb->complete = usb_urb_complete; + urb->pipe = usb_rcvisocpipe(stream->udev, + stream->props.endpoint); + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + urb->interval = stream->props.u.isoc.interval; + urb->number_of_packets = stream->props.u.isoc.framesperurb; + urb->transfer_buffer_length = stream->props.u.isoc.framesize * + stream->props.u.isoc.framesperurb; + urb->transfer_buffer = stream->buf_list[i]; + urb->transfer_dma = stream->dma_addr[i]; + + for (j = 0; j < stream->props.u.isoc.framesperurb; j++) { + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = + stream->props.u.isoc.framesize; + frame_offset += stream->props.u.isoc.framesize; + } + + stream->urbs_initialized++; + } + return 0; +} + +int usb_free_stream_buffers(struct usb_data_stream *stream) +{ + if (stream->state & USB_STATE_URB_BUF) { + while (stream->buf_num) { + stream->buf_num--; + dev_dbg(&stream->udev->dev, "%s: free buf=%d\n", + __func__, stream->buf_num); + usb_free_coherent(stream->udev, stream->buf_size, + stream->buf_list[stream->buf_num], + stream->dma_addr[stream->buf_num]); + } + } + + stream->state &= ~USB_STATE_URB_BUF; + + return 0; +} + +int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num, + unsigned long size) +{ + stream->buf_num = 0; + stream->buf_size = size; + + dev_dbg(&stream->udev->dev, "%s: all in all I will use %lu bytes for " \ + "streaming\n", __func__, num * size); + + for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { + stream->buf_list[stream->buf_num] = usb_alloc_coherent( + stream->udev, size, GFP_ATOMIC, + &stream->dma_addr[stream->buf_num]); + if (!stream->buf_list[stream->buf_num]) { + dev_dbg(&stream->udev->dev, "%s: alloc buf=%d failed\n", + __func__, stream->buf_num); + usb_free_stream_buffers(stream); + return -ENOMEM; + } + + dev_dbg(&stream->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n", + __func__, stream->buf_num, + stream->buf_list[stream->buf_num], + (long long)stream->dma_addr[stream->buf_num]); + memset(stream->buf_list[stream->buf_num], 0, size); + stream->state |= USB_STATE_URB_BUF; + } + + return 0; +} + +int usb_urb_reconfig(struct usb_data_stream *stream, + struct usb_data_stream_properties *props) +{ + int buf_size; + + if (!props) + return 0; + + /* check allocated buffers are large enough for the request */ + if (props->type == USB_BULK) { + buf_size = stream->props.u.bulk.buffersize; + } else if (props->type == USB_ISOC) { + buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb; + } else { + dev_err(&stream->udev->dev, "%s: invalid endpoint type=%d\n", + KBUILD_MODNAME, props->type); + return -EINVAL; + } + + if (stream->buf_num < props->count || stream->buf_size < buf_size) { + dev_err(&stream->udev->dev, "%s: cannot reconfigure as " \ + "allocated buffers are too small\n", + KBUILD_MODNAME); + return -EINVAL; + } + + /* check if all fields are same */ + if (stream->props.type == props->type && + stream->props.count == props->count && + stream->props.endpoint == props->endpoint) { + if (props->type == USB_BULK && + props->u.bulk.buffersize == + stream->props.u.bulk.buffersize) + return 0; + else if (props->type == USB_ISOC && + props->u.isoc.framesperurb == + stream->props.u.isoc.framesperurb && + props->u.isoc.framesize == + stream->props.u.isoc.framesize && + props->u.isoc.interval == + stream->props.u.isoc.interval) + return 0; + } + + dev_dbg(&stream->udev->dev, "%s: re-alloc urbs\n", __func__); + + usb_urb_free_urbs(stream); + memcpy(&stream->props, props, sizeof(*props)); + if (props->type == USB_BULK) + return usb_urb_alloc_bulk_urbs(stream); + else if (props->type == USB_ISOC) + return usb_urb_alloc_isoc_urbs(stream); + + return 0; +} + +int usb_urb_initv2(struct usb_data_stream *stream, + const struct usb_data_stream_properties *props) +{ + int ret; + + if (!stream || !props) + return -EINVAL; + + memcpy(&stream->props, props, sizeof(*props)); + + if (!stream->complete) { + dev_err(&stream->udev->dev, "%s: there is no data callback - " \ + "this doesn't make sense\n", KBUILD_MODNAME); + return -EINVAL; + } + + switch (stream->props.type) { + case USB_BULK: + ret = usb_alloc_stream_buffers(stream, stream->props.count, + stream->props.u.bulk.buffersize); + if (ret < 0) + return ret; + + return usb_urb_alloc_bulk_urbs(stream); + case USB_ISOC: + ret = usb_alloc_stream_buffers(stream, stream->props.count, + stream->props.u.isoc.framesize * + stream->props.u.isoc.framesperurb); + if (ret < 0) + return ret; + + return usb_urb_alloc_isoc_urbs(stream); + default: + dev_err(&stream->udev->dev, "%s: unknown urb-type for data " \ + "transfer\n", KBUILD_MODNAME); + return -EINVAL; + } +} + +int usb_urb_exitv2(struct usb_data_stream *stream) +{ + usb_urb_free_urbs(stream); + usb_free_stream_buffers(stream); + + return 0; +} diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 09fded4eb0b4..67b91b74976f 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -13,25 +13,6 @@ config DVB_USB Say Y if you own a USB DVB device. -config DVB_USB_V2 - tristate "Support for various USB DVB devices v2" - depends on DVB_CORE && USB && I2C && RC_CORE - help - By enabling this you will be able to choose the various supported - USB1.1 and USB2.0 DVB devices. - - Almost every USB device needs a firmware, please look into - . - - For a complete list of supported USB devices see the LinuxTV DVB Wiki: - - - Say Y if you own a USB DVB device. - -config DVB_USB_FIRMWARE - tristate "Firmware helper routines" - depends on DVB_USB - config DVB_USB_DEBUG bool "Enable extended debug support for all DVB-USB devices" depends on DVB_USB @@ -162,23 +143,6 @@ config DVB_USB_M920X "DTV USB MINI" (in cold state) are supported. Firmware required. -config DVB_USB_GL861 - tristate "Genesys Logic GL861 USB2.0 support" - depends on DVB_USB_V2 - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0 - receiver with USB ID 0db0:5581. - -config DVB_USB_AU6610 - tristate "Alcor Micro AU6610 USB2.0 support" - depends on DVB_USB_V2 - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver. - config DVB_USB_DIGITV tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" depends on DVB_USB @@ -318,23 +282,6 @@ config DVB_USB_CINERGY_T2 Say Y if you own such a device and want to use it. -config DVB_USB_ANYSEE - tristate "Anysee DVB-T/C USB2.0 support" - depends on DVB_USB_V2 - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA18212 if !MEDIA_TUNER_CUSTOMISE - select DVB_CX24116 if !DVB_FE_CUSTOMISE - select DVB_STV0900 if !DVB_FE_CUSTOMISE - select DVB_STV6110 if !DVB_FE_CUSTOMISE - select DVB_ISL6423 if !DVB_FE_CUSTOMISE - select DVB_CXD2820R if !DVB_FE_CUSTOMISE - help - Say Y here to support the Anysee E30, Anysee E30 Plus or - Anysee E30 C Plus DVB USB2.0 receiver. - config DVB_USB_DTV5100 tristate "AME DTV-5100 USB2.0 DVB-T support" depends on DVB_USB @@ -343,43 +290,12 @@ config DVB_USB_DTV5100 help Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver. -config DVB_USB_AF9015 - tristate "Afatech AF9015 DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_AF9013 - select DVB_PLL if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver - -config DVB_USB_CE6230 - tristate "Intel CE6230 DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_ZL10353 - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver - config DVB_USB_FRIIO tristate "Friio ISDB-T USB2.0 Receiver support" depends on DVB_USB help Say Y here to support the Japanese DTV receiver Friio. -config DVB_USB_EC168 - tristate "E3C EC168 DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_EC100 - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the E3C EC168 DVB-T USB2.0 receiver. - config DVB_USB_AZ6007 tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support" depends on DVB_USB @@ -424,15 +340,6 @@ config DVB_USB_IT913X help Say Y here to support the it913x device -config DVB_USB_MXL111SF - tristate "MxL111SF DTV USB2.0 support" - depends on DVB_USB_V2 - select DVB_LGDT3305 if !DVB_FE_CUSTOMISE - select DVB_LG2160 if !DVB_FE_CUSTOMISE - select VIDEO_TVEEPROM - help - Say Y here to support the MxL111SF USB2.0 DTV receiver. - config DVB_USB_RTL28XXU tristate "Realtek RTL28xxU DVB USB support" depends on DVB_USB && EXPERIMENTAL @@ -446,14 +353,3 @@ config DVB_USB_RTL28XXU help Say Y here to support the Realtek RTL28xxU DVB USB receiver. -config DVB_USB_AF9035 - tristate "Afatech AF9035 DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_AF9033 - select MEDIA_TUNER_TUA9001 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_FC0011 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Afatech AF9035 based DVB USB receiver. - diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 50f506e0632a..29fa0f0637e5 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -1,11 +1,6 @@ dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o obj-$(CONFIG_DVB_USB) += dvb-usb.o -dvb_usbv2-objs = dvb_usb_core.o dvb_usb_urb.o usb_urb.o -obj-$(CONFIG_DVB_USB_V2) += dvb_usbv2.o - -obj-$(CONFIG_DVB_USB_FIRMWARE) += dvb_usb_firmware.o - dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o @@ -38,12 +33,6 @@ obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o dvb-usb-m920x-objs = m920x.o obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o -dvb-usb-gl861-objs = gl861.o -obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o - -dvb-usb-au6610-objs = au6610.o -obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o - dvb-usb-digitv-objs = digitv.o obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o @@ -65,9 +54,6 @@ obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o dvb-usb-af9005-remote-objs = af9005-remote.o obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o -dvb-usb-anysee-objs = anysee.o -obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o - dvb-usb-pctv452e-objs = pctv452e.o obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o @@ -77,21 +63,12 @@ obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o dvb-usb-dtv5100-objs = dtv5100.o obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o -dvb-usb-af9015-objs = af9015.o -obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o - dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o -dvb-usb-ce6230-objs = ce6230.o -obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o - dvb-usb-friio-objs = friio.o friio-fe.o obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o -dvb-usb-ec168-objs = ec168.o -obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o - dvb-usb-az6007-objs = az6007.o obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o @@ -107,17 +84,9 @@ obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o dvb-usb-it913x-objs := it913x.o obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o -dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o -obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o -obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o -obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o - dvb-usb-rtl28xxu-objs = rtl28xxu.o obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o -dvb-usb-af9035-objs = af9035.o -obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o - ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/ # due to tuner-xc3028 diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c deleted file mode 100644 index bbe1d3382195..000000000000 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ /dev/null @@ -1,1426 +0,0 @@ -/* - * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver - * - * Copyright (C) 2007 Antti Palosaari - * - * Thanks to Afatech who kindly provided information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "af9015.h" - -static int dvb_usb_af9015_debug; -module_param_named(debug, dvb_usb_af9015_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); -static int dvb_usb_af9015_remote; -module_param_named(remote, dvb_usb_af9015_remote, int, 0644); -MODULE_PARM_DESC(remote, "select remote"); -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) -{ -#define BUF_LEN 63 -#define REQ_HDR_LEN 8 /* send header size */ -#define ACK_HDR_LEN 2 /* rece header size */ - struct af9015_state *state = d_to_priv(d); - int ret, wlen, rlen; - u8 buf[BUF_LEN]; - u8 write = 1; - - buf[0] = req->cmd; - buf[1] = state->seq++; - buf[2] = req->i2c_addr; - buf[3] = req->addr >> 8; - buf[4] = req->addr & 0xff; - buf[5] = req->mbox; - buf[6] = req->addr_len; - buf[7] = req->data_len; - - switch (req->cmd) { - case GET_CONFIG: - case READ_MEMORY: - case RECONNECT_USB: - write = 0; - break; - case READ_I2C: - write = 0; - buf[2] |= 0x01; /* set I2C direction */ - case WRITE_I2C: - buf[0] = READ_WRITE_I2C; - break; - case WRITE_MEMORY: - if (((req->addr & 0xff00) == 0xff00) || - ((req->addr & 0xff00) == 0xae00)) - buf[0] = WRITE_VIRTUAL_MEMORY; - case WRITE_VIRTUAL_MEMORY: - case COPY_FIRMWARE: - case DOWNLOAD_FIRMWARE: - case BOOT: - break; - default: - err("unknown command:%d", req->cmd); - ret = -1; - goto error; - } - - /* buffer overflow check */ - if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) || - (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { - err("too much data; cmd:%d len:%d", req->cmd, req->data_len); - ret = -EINVAL; - goto error; - } - - /* write receives seq + status = 2 bytes - read receives seq + status + data = 2 + N bytes */ - wlen = REQ_HDR_LEN; - rlen = ACK_HDR_LEN; - if (write) { - wlen += req->data_len; - memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len); - } else { - rlen += req->data_len; - } - - /* no ack for these packets */ - if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) - rlen = 0; - - ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen); - if (ret) - goto error; - - /* check status */ - if (rlen && buf[1]) { - err("command failed:%d", buf[1]); - ret = -1; - goto error; - } - - /* read request, copy returned data to return buf */ - if (!write) - memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len); -error: - return ret; -} - -static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val, - u8 len) -{ - struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, - val}; - return af9015_ctrl_msg(d, &req); -} - -static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len) -{ - struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, - val}; - return af9015_ctrl_msg(d, &req); -} - -static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val) -{ - return af9015_write_regs(d, addr, &val, 1); -} - -static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val) -{ - return af9015_read_regs(d, addr, val, 1); -} - -static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, - u8 val) -{ - struct af9015_state *state = d_to_priv(d); - struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; - - if (addr == state->af9013_config[0].i2c_addr || - addr == state->af9013_config[1].i2c_addr) - req.addr_len = 3; - - return af9015_ctrl_msg(d, &req); -} - -static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, - u8 *val) -{ - struct af9015_state *state = d_to_priv(d); - struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; - - if (addr == state->af9013_config[0].i2c_addr || - addr == state->af9013_config[1].i2c_addr) - req.addr_len = 3; - - return af9015_ctrl_msg(d, &req); -} - -static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op) -{ - int ret; - u8 val, mask = 0x01; - - ret = af9015_read_reg(d, addr, &val); - if (ret) - return ret; - - mask <<= bit; - if (op) { - /* set bit */ - val |= mask; - } else { - /* clear bit */ - mask ^= 0xff; - val &= mask; - } - - return af9015_write_reg(d, addr, val); -} - -static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) -{ - return af9015_do_reg_bit(d, addr, bit, 1); -} - -static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) -{ - return af9015_do_reg_bit(d, addr, bit, 0); -} - -static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct af9015_state *state = d_to_priv(d); - int ret = 0, i = 0; - u16 addr; - u8 uninitialized_var(mbox), addr_len; - struct req_t req; - -/* -The bus lock is needed because there is two tuners both using same I2C-address. -Due to that the only way to select correct tuner is use demodulator I2C-gate. - -................................................ -. AF9015 includes integrated AF9013 demodulator. -. ____________ ____________ . ____________ -.| uC | | demod | . | tuner | -.|------------| |------------| . |------------| -.| AF9015 | | AF9013/5 | . | MXL5003 | -.| |--+----I2C-------|-----/ -----|-.-----I2C-------| | -.| | | | addr 0x38 | . | addr 0xc6 | -.|____________| | |____________| . |____________| -.................|.............................. - | ____________ ____________ - | | demod | | tuner | - | |------------| |------------| - | | AF9013 | | MXL5003 | - +----I2C-------|-----/ -----|-------I2C-------| | - | addr 0x3a | | addr 0xc6 | - |____________| |____________| -*/ - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - while (i < num) { - if (msg[i].addr == state->af9013_config[0].i2c_addr || - msg[i].addr == state->af9013_config[1].i2c_addr) { - addr = msg[i].buf[0] << 8; - addr += msg[i].buf[1]; - mbox = msg[i].buf[2]; - addr_len = 3; - } else { - addr = msg[i].buf[0]; - addr_len = 1; - /* mbox is don't care in that case */ - } - - if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { - if (msg[i].len > 3 || msg[i+1].len > 61) { - ret = -EOPNOTSUPP; - goto error; - } - if (msg[i].addr == state->af9013_config[0].i2c_addr) - req.cmd = READ_MEMORY; - else - req.cmd = READ_I2C; - req.i2c_addr = msg[i].addr; - req.addr = addr; - req.mbox = mbox; - req.addr_len = addr_len; - req.data_len = msg[i+1].len; - req.data = &msg[i+1].buf[0]; - ret = af9015_ctrl_msg(d, &req); - i += 2; - } else if (msg[i].flags & I2C_M_RD) { - if (msg[i].len > 61) { - ret = -EOPNOTSUPP; - goto error; - } - if (msg[i].addr == state->af9013_config[0].i2c_addr) { - ret = -EINVAL; - goto error; - } - req.cmd = READ_I2C; - req.i2c_addr = msg[i].addr; - req.addr = addr; - req.mbox = mbox; - req.addr_len = addr_len; - req.data_len = msg[i].len; - req.data = &msg[i].buf[0]; - ret = af9015_ctrl_msg(d, &req); - i += 1; - } else { - if (msg[i].len > 21) { - ret = -EOPNOTSUPP; - goto error; - } - if (msg[i].addr == state->af9013_config[0].i2c_addr) - req.cmd = WRITE_MEMORY; - else - req.cmd = WRITE_I2C; - req.i2c_addr = msg[i].addr; - req.addr = addr; - req.mbox = mbox; - req.addr_len = addr_len; - req.data_len = msg[i].len-addr_len; - req.data = &msg[i].buf[addr_len]; - ret = af9015_ctrl_msg(d, &req); - i += 1; - } - if (ret) - goto error; - - } - ret = i; - -error: - mutex_unlock(&d->i2c_mutex); - - return ret; -} - -static u32 af9015_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm af9015_i2c_algo = { - .master_xfer = af9015_i2c_xfer, - .functionality = af9015_i2c_func, -}; - -static int af9015_identify_state(struct dvb_usb_device *d, const char **name) -{ - int ret; - u8 reply; - struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply}; - - ret = af9015_ctrl_msg(d, &req); - if (ret) - return ret; - - deb_info("%s: reply:%02x\n", __func__, reply); - if (reply == 0x02) - ret = WARM; - else - ret = COLD; - - return ret; -} - -static int af9015_download_firmware(struct dvb_usb_device *d, - const struct firmware *fw) -{ - struct af9015_state *state = d_to_priv(d); - int i, len, remaining, ret; - struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; - u16 checksum = 0; - - deb_info("%s:\n", __func__); - - /* calc checksum */ - for (i = 0; i < fw->size; i++) - checksum += fw->data[i]; - - state->firmware_size = fw->size; - state->firmware_checksum = checksum; - - #define FW_ADDR 0x5100 /* firmware start address */ - #define LEN_MAX 55 /* max packet size */ - for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { - len = remaining; - if (len > LEN_MAX) - len = LEN_MAX; - - req.data_len = len; - req.data = (u8 *) &fw->data[fw->size - remaining]; - req.addr = FW_ADDR + fw->size - remaining; - - ret = af9015_ctrl_msg(d, &req); - if (ret) { - err("firmware download failed:%d", ret); - goto error; - } - } - - /* firmware loaded, request boot */ - req.cmd = BOOT; - req.data_len = 0; - ret = af9015_ctrl_msg(d, &req); - if (ret) { - err("firmware boot failed:%d", ret); - goto error; - } - -error: - return ret; -} - -/* hash (and dump) eeprom */ -static int af9015_eeprom_hash(struct dvb_usb_device *d) -{ - struct af9015_state *state = d_to_priv(d); - int ret; - static const unsigned int eeprom_size = 256; - unsigned int reg; - u8 val, *eeprom; - struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; - - eeprom = kmalloc(eeprom_size, GFP_KERNEL); - if (eeprom == NULL) - return -ENOMEM; - - for (reg = 0; reg < eeprom_size; reg++) { - req.addr = reg; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto free; - - eeprom[reg] = val; - } - - if (dvb_usb_af9015_debug & 0x01) - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, eeprom, - eeprom_size); - - BUG_ON(eeprom_size % 4); - - state->eeprom_sum = 0; - for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) { - state->eeprom_sum *= GOLDEN_RATIO_PRIME_32; - state->eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]); - } - - deb_info("%s: eeprom sum=%.8x\n", __func__, state->eeprom_sum); - - ret = 0; -free: - kfree(eeprom); - return ret; -} - -static int af9015_read_config(struct dvb_usb_device *d) -{ - struct af9015_state *state = d_to_priv(d); - int ret; - u8 val, i, offset = 0; - struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; - - deb_info("%s:\n", __func__); - - /* IR remote controller */ - req.addr = AF9015_EEPROM_IR_MODE; - /* first message will timeout often due to possible hw bug */ - for (i = 0; i < 4; i++) { - ret = af9015_ctrl_msg(d, &req); - if (!ret) - break; - } - if (ret) - goto error; - - ret = af9015_eeprom_hash(d); - if (ret) - goto error; - - deb_info("%s: IR mode=%d\n", __func__, val); - state->ir_mode = val; - - /* TS mode - one or two receivers */ - req.addr = AF9015_EEPROM_TS_MODE; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto error; - - state->dual_mode = val; - deb_info("%s: TS mode=%d\n", __func__, state->dual_mode); - - /* disable 2nd adapter because we don't have PID-filters */ - if (d->udev->speed == USB_SPEED_FULL) - state->dual_mode = 0; - - if (state->dual_mode) { - /* read 2nd demodulator I2C address */ - req.addr = AF9015_EEPROM_DEMOD2_I2C; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto error; - - state->af9013_config[1].i2c_addr = val; - } - - for (i = 0; i < state->dual_mode + 1; i++) { - if (i == 1) - offset = AF9015_EEPROM_OFFSET; - /* xtal */ - req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto error; - switch (val) { - case 0: - state->af9013_config[i].clock = 28800000; - break; - case 1: - state->af9013_config[i].clock = 20480000; - break; - case 2: - state->af9013_config[i].clock = 28000000; - break; - case 3: - state->af9013_config[i].clock = 25000000; - break; - }; - deb_info("%s: [%d] xtal=%d set clock=%d\n", __func__, i, - val, state->af9013_config[i].clock); - - /* IF frequency */ - req.addr = AF9015_EEPROM_IF1H + offset; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto error; - - state->af9013_config[i].if_frequency = val << 8; - - req.addr = AF9015_EEPROM_IF1L + offset; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto error; - - state->af9013_config[i].if_frequency += val; - state->af9013_config[i].if_frequency *= 1000; - deb_info("%s: [%d] IF frequency=%d\n", __func__, i, - state->af9013_config[i].if_frequency); - - /* MT2060 IF1 */ - req.addr = AF9015_EEPROM_MT2060_IF1H + offset; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto error; - state->mt2060_if1[i] = val << 8; - req.addr = AF9015_EEPROM_MT2060_IF1L + offset; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto error; - state->mt2060_if1[i] += val; - deb_info("%s: [%d] MT2060 IF1=%d\n", __func__, i, - state->mt2060_if1[i]); - - /* tuner */ - req.addr = AF9015_EEPROM_TUNER_ID1 + offset; - ret = af9015_ctrl_msg(d, &req); - if (ret) - goto error; - switch (val) { - case AF9013_TUNER_ENV77H11D5: - case AF9013_TUNER_MT2060: - case AF9013_TUNER_QT1010: - case AF9013_TUNER_UNKNOWN: - case AF9013_TUNER_MT2060_2: - case AF9013_TUNER_TDA18271: - case AF9013_TUNER_QT1010A: - case AF9013_TUNER_TDA18218: - state->af9013_config[i].spec_inv = 1; - break; - case AF9013_TUNER_MXL5003D: - case AF9013_TUNER_MXL5005D: - case AF9013_TUNER_MXL5005R: - case AF9013_TUNER_MXL5007T: - state->af9013_config[i].spec_inv = 0; - break; - case AF9013_TUNER_MC44S803: - state->af9013_config[i].gpio[1] = AF9013_GPIO_LO; - state->af9013_config[i].spec_inv = 1; - break; - default: - warn("tuner id=%d not supported, please report!", val); - return -ENODEV; - }; - - state->af9013_config[i].tuner = val; - deb_info("%s: [%d] tuner id=%d\n", __func__, i, val); - } - -error: - if (ret) - err("eeprom read failed=%d", ret); - - /* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM - content :-( Override some wrong values here. Ditto for the - AVerTV Red HD+ (A850T) device. */ - if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA && - ((le16_to_cpu(d->udev->descriptor.idProduct) == - USB_PID_AVERMEDIA_A850) || - (le16_to_cpu(d->udev->descriptor.idProduct) == - USB_PID_AVERMEDIA_A850T))) { - deb_info("%s: AverMedia A850: overriding config\n", __func__); - /* disable dual mode */ - state->dual_mode = 0; - - /* set correct IF */ - state->af9013_config[0].if_frequency = 4570000; - } - - return ret; -} - -static int af9015_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, - struct usb_data_stream_properties *stream) -{ - deb_info("%s: adap=%d\n", __func__, fe_to_adap(fe)->id); - - if (fe_to_d(fe)->udev->speed == USB_SPEED_FULL) - stream->u.bulk.buffersize = TS_USB11_FRAME_SIZE; - - return 0; -} - -static int af9015_get_adapter_count(struct dvb_usb_device *d) -{ - struct af9015_state *state = d_to_priv(d); - return state->dual_mode + 1; -} - -/* override demod callbacks for resource locking */ -static int af9015_af9013_set_frontend(struct dvb_frontend *fe) -{ - int ret; - struct af9015_state *state = fe_to_priv(fe); - - if (mutex_lock_interruptible(&state->fe_mutex)) - return -EAGAIN; - - ret = state->set_frontend[fe_to_adap(fe)->id](fe); - - mutex_unlock(&state->fe_mutex); - - return ret; -} - -/* override demod callbacks for resource locking */ -static int af9015_af9013_read_status(struct dvb_frontend *fe, - fe_status_t *status) -{ - int ret; - struct af9015_state *state = fe_to_priv(fe); - - if (mutex_lock_interruptible(&state->fe_mutex)) - return -EAGAIN; - - ret = state->read_status[fe_to_adap(fe)->id](fe, status); - - mutex_unlock(&state->fe_mutex); - - return ret; -} - -/* override demod callbacks for resource locking */ -static int af9015_af9013_init(struct dvb_frontend *fe) -{ - int ret; - struct af9015_state *state = fe_to_priv(fe); - - if (mutex_lock_interruptible(&state->fe_mutex)) - return -EAGAIN; - - ret = state->init[fe_to_adap(fe)->id](fe); - - mutex_unlock(&state->fe_mutex); - - return ret; -} - -/* override demod callbacks for resource locking */ -static int af9015_af9013_sleep(struct dvb_frontend *fe) -{ - int ret; - struct af9015_state *state = fe_to_priv(fe); - - if (mutex_lock_interruptible(&state->fe_mutex)) - return -EAGAIN; - - ret = state->sleep[fe_to_adap(fe)->id](fe); - - mutex_unlock(&state->fe_mutex); - - return ret; -} - -/* override tuner callbacks for resource locking */ -static int af9015_tuner_init(struct dvb_frontend *fe) -{ - int ret; - struct af9015_state *state = fe_to_priv(fe); - - if (mutex_lock_interruptible(&state->fe_mutex)) - return -EAGAIN; - - ret = state->tuner_init[fe_to_adap(fe)->id](fe); - - mutex_unlock(&state->fe_mutex); - - return ret; -} - -/* override tuner callbacks for resource locking */ -static int af9015_tuner_sleep(struct dvb_frontend *fe) -{ - int ret; - struct af9015_state *state = fe_to_priv(fe); - - if (mutex_lock_interruptible(&state->fe_mutex)) - return -EAGAIN; - - ret = state->tuner_sleep[fe_to_adap(fe)->id](fe); - - mutex_unlock(&state->fe_mutex); - - return ret; -} - -static int af9015_copy_firmware(struct dvb_usb_device *d) -{ - struct af9015_state *state = d_to_priv(d); - int ret; - u8 fw_params[4]; - u8 val, i; - struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params), - fw_params }; - deb_info("%s:\n", __func__); - - fw_params[0] = state->firmware_size >> 8; - fw_params[1] = state->firmware_size & 0xff; - fw_params[2] = state->firmware_checksum >> 8; - fw_params[3] = state->firmware_checksum & 0xff; - - /* wait 2nd demodulator ready */ - msleep(100); - - ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr, - 0x98be, &val); - if (ret) - goto error; - else - deb_info("%s: firmware status:%02x\n", __func__, val); - - if (val == 0x0c) /* fw is running, no need for download */ - goto exit; - - /* set I2C master clock to fast (to speed up firmware copy) */ - ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */ - if (ret) - goto error; - - msleep(50); - - /* copy firmware */ - ret = af9015_ctrl_msg(d, &req); - if (ret) - err("firmware copy cmd failed:%d", ret); - deb_info("%s: firmware copy done\n", __func__); - - /* set I2C master clock back to normal */ - ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */ - if (ret) - goto error; - - /* request boot firmware */ - ret = af9015_write_reg_i2c(d, state->af9013_config[1].i2c_addr, - 0xe205, 1); - deb_info("%s: firmware boot cmd status:%d\n", __func__, ret); - if (ret) - goto error; - - for (i = 0; i < 15; i++) { - msleep(100); - - /* check firmware status */ - ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr, - 0x98be, &val); - deb_info("%s: firmware status cmd status:%d fw status:%02x\n", - __func__, ret, val); - if (ret) - goto error; - - if (val == 0x0c || val == 0x04) /* success or fail */ - break; - } - - if (val == 0x04) { - err("firmware did not run"); - ret = -1; - } else if (val != 0x0c) { - err("firmware boot timeout"); - ret = -1; - } - -error: -exit: - return ret; -} - -static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) -{ - int ret; - struct af9015_state *state = adap_to_priv(adap); - - if (adap->id == 0) { - state->af9013_config[0].ts_mode = AF9013_TS_USB; - memcpy(state->af9013_config[0].api_version, "\x0\x1\x9\x0", 4); - state->af9013_config[0].gpio[0] = AF9013_GPIO_HI; - state->af9013_config[0].gpio[3] = AF9013_GPIO_TUNER_ON; - } else if (adap->id == 1) { - state->af9013_config[1].ts_mode = AF9013_TS_SERIAL; - memcpy(state->af9013_config[1].api_version, "\x0\x1\x9\x0", 4); - state->af9013_config[1].gpio[0] = AF9013_GPIO_TUNER_ON; - state->af9013_config[1].gpio[1] = AF9013_GPIO_LO; - - /* copy firmware to 2nd demodulator */ - if (state->dual_mode) { - ret = af9015_copy_firmware(adap_to_d(adap)); - if (ret) { - err("firmware copy to 2nd frontend " \ - "failed, will disable it"); - state->dual_mode = 0; - return -ENODEV; - } - } else { - return -ENODEV; - } - } - - /* attach demodulator */ - adap->fe[0] = dvb_attach(af9013_attach, - &state->af9013_config[adap->id], &adap_to_d(adap)->i2c_adap); - - /* - * AF9015 firmware does not like if it gets interrupted by I2C adapter - * request on some critical phases. During normal operation I2C adapter - * is used only 2nd demodulator and tuner on dual tuner devices. - * Override demodulator callbacks and use mutex for limit access to - * those "critical" paths to keep AF9015 happy. - */ - if (adap->fe[0]) { - state->set_frontend[adap->id] = - adap->fe[0]->ops.set_frontend; - adap->fe[0]->ops.set_frontend = - af9015_af9013_set_frontend; - - state->read_status[adap->id] = - adap->fe[0]->ops.read_status; - adap->fe[0]->ops.read_status = - af9015_af9013_read_status; - - state->init[adap->id] = adap->fe[0]->ops.init; - adap->fe[0]->ops.init = af9015_af9013_init; - - state->sleep[adap->id] = adap->fe[0]->ops.sleep; - adap->fe[0]->ops.sleep = af9015_af9013_sleep; - } - - return adap->fe[0] == NULL ? -ENODEV : 0; -} - -static struct mt2060_config af9015_mt2060_config = { - .i2c_address = 0xc0, - .clock_out = 0, -}; - -static struct qt1010_config af9015_qt1010_config = { - .i2c_address = 0xc4, -}; - -static struct tda18271_config af9015_tda18271_config = { - .gate = TDA18271_GATE_DIGITAL, - .small_i2c = TDA18271_16_BYTE_CHUNK_INIT, -}; - -static struct mxl5005s_config af9015_mxl5003_config = { - .i2c_address = 0xc6, - .if_freq = IF_FREQ_4570000HZ, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_DEFAULT, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .AgcMasterByte = 0x00, -}; - -static struct mxl5005s_config af9015_mxl5005_config = { - .i2c_address = 0xc6, - .if_freq = IF_FREQ_4570000HZ, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_OFF, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .AgcMasterByte = 0x00, -}; - -static struct mc44s803_config af9015_mc44s803_config = { - .i2c_address = 0xc0, - .dig_out = 1, -}; - -static struct tda18218_config af9015_tda18218_config = { - .i2c_address = 0xc0, - .i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */ -}; - -static struct mxl5007t_config af9015_mxl5007t_config = { - .xtal_freq_hz = MxL_XTAL_24_MHZ, - .if_freq_hz = MxL_IF_4_57_MHZ, -}; - -static int af9015_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct af9015_state *state = adap_to_priv(adap); - int ret; - deb_info("%s:\n", __func__); - - switch (state->af9013_config[adap->id].tuner) { - case AF9013_TUNER_MT2060: - case AF9013_TUNER_MT2060_2: - ret = dvb_attach(mt2060_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, &af9015_mt2060_config, - state->mt2060_if1[adap->id]) - == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_QT1010: - case AF9013_TUNER_QT1010A: - ret = dvb_attach(qt1010_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &af9015_qt1010_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_TDA18271: - ret = dvb_attach(tda18271_attach, adap->fe[0], 0xc0, - &adap_to_d(adap)->i2c_adap, - &af9015_tda18271_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_TDA18218: - ret = dvb_attach(tda18218_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &af9015_tda18218_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_MXL5003D: - ret = dvb_attach(mxl5005s_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &af9015_mxl5003_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_MXL5005D: - case AF9013_TUNER_MXL5005R: - ret = dvb_attach(mxl5005s_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &af9015_mxl5005_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_ENV77H11D5: - ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0xc0, - &adap_to_d(adap)->i2c_adap, - DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_MC44S803: - ret = dvb_attach(mc44s803_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &af9015_mc44s803_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_MXL5007T: - ret = dvb_attach(mxl5007t_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_UNKNOWN: - default: - ret = -ENODEV; - err("Unknown tuner id:%d", - state->af9013_config[adap->id].tuner); - } - - if (adap->fe[0]->ops.tuner_ops.init) { - state->tuner_init[adap->id] = - adap->fe[0]->ops.tuner_ops.init; - adap->fe[0]->ops.tuner_ops.init = af9015_tuner_init; - } - - if (adap->fe[0]->ops.tuner_ops.sleep) { - state->tuner_sleep[adap->id] = - adap->fe[0]->ops.tuner_ops.sleep; - adap->fe[0]->ops.tuner_ops.sleep = af9015_tuner_sleep; - } - - return ret; -} - -static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - int ret; - deb_info("%s: onoff:%d\n", __func__, onoff); - - if (onoff) - ret = af9015_set_reg_bit(adap_to_d(adap), 0xd503, 0); - else - ret = af9015_clear_reg_bit(adap_to_d(adap), 0xd503, 0); - - return ret; -} - -static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, - int onoff) -{ - int ret; - u8 idx; - - deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n", - __func__, index, pid, onoff); - - ret = af9015_write_reg(adap_to_d(adap), 0xd505, (pid & 0xff)); - if (ret) - goto error; - - ret = af9015_write_reg(adap_to_d(adap), 0xd506, (pid >> 8)); - if (ret) - goto error; - - idx = ((index & 0x1f) | (1 << 5)); - ret = af9015_write_reg(adap_to_d(adap), 0xd504, idx); - -error: - return ret; -} - -static int af9015_init_endpoint(struct dvb_usb_device *d) -{ - struct af9015_state *state = d_to_priv(d); - int ret; - u16 frame_size; - u8 packet_size; - deb_info("%s: USB speed:%d\n", __func__, d->udev->speed); - - if (d->udev->speed == USB_SPEED_FULL) { - frame_size = TS_USB11_FRAME_SIZE/4; - packet_size = TS_USB11_MAX_PACKET_SIZE/4; - } else { - frame_size = TS_USB20_FRAME_SIZE/4; - packet_size = TS_USB20_MAX_PACKET_SIZE/4; - } - - ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */ - if (ret) - goto error; - ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */ - if (ret) - goto error; - ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */ - if (ret) - goto error; - if (state->dual_mode) { - ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */ - if (ret) - goto error; - } - ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */ - if (ret) - goto error; - if (state->dual_mode) { - ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */ - if (ret) - goto error; - } - /* EP4 xfer length */ - ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd89, frame_size >> 8); - if (ret) - goto error; - /* EP5 xfer length */ - ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */ - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */ - if (ret) - goto error; - if (state->dual_mode) { - ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */ - if (ret) - goto error; - } - - /* enable / disable mp2if2 */ - if (state->dual_mode) - ret = af9015_set_reg_bit(d, 0xd50b, 0); - else - ret = af9015_clear_reg_bit(d, 0xd50b, 0); - -error: - if (ret) - err("endpoint init failed:%d", ret); - return ret; -} - -static int af9015_init(struct dvb_usb_device *d) -{ - struct af9015_state *state = d_to_priv(d); - int ret; - deb_info("%s:\n", __func__); - - mutex_init(&state->fe_mutex); - - /* init RC canary */ - ret = af9015_write_reg(d, 0x98e9, 0xff); - if (ret) - goto error; - - ret = af9015_init_endpoint(d); - if (ret) - goto error; - -error: - return ret; -} - -struct af9015_rc_setup { - unsigned int id; - char *rc_codes; -}; - -static char *af9015_rc_setup_match(unsigned int id, - const struct af9015_rc_setup *table) -{ - for (; table->rc_codes; table++) - if (table->id == id) - return table->rc_codes; - return NULL; -} - -static const struct af9015_rc_setup af9015_rc_setup_modparam[] = { - { AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M }, - { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II }, - { AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND }, - { AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE }, - { AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS }, - { } -}; - -static const struct af9015_rc_setup af9015_rc_setup_hashes[] = { - { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II }, - { 0xa3703d00, RC_MAP_ALINK_DTU_M }, - { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */ - { 0x5d49e3db, RC_MAP_DIGITTRADE }, /* LC-Power LC-USB-DVBT */ - { } -}; - -static int af9015_rc_query(struct dvb_usb_device *d) -{ - struct af9015_state *state = d_to_priv(d); - int ret; - u8 buf[17]; - - deb_info("%s:\n", __func__); - - /* read registers needed to detect remote controller code */ - ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf)); - if (ret) - goto error; - - /* If any of these are non-zero, assume invalid data */ - if (buf[1] || buf[2] || buf[3]) - return ret; - - /* Check for repeat of previous code */ - if ((state->rc_repeat != buf[6] || buf[0]) && - !memcmp(&buf[12], state->rc_last, 4)) { - deb_rc("%s: key repeated\n", __func__); - rc_keydown(d->rc_dev, state->rc_keycode, 0); - state->rc_repeat = buf[6]; - return ret; - } - - /* Only process key if canary killed */ - if (buf[16] != 0xff && buf[0] != 0x01) { - deb_rc("%s: key pressed %02x %02x %02x %02x\n", __func__, - buf[12], buf[13], buf[14], buf[15]); - - /* Reset the canary */ - ret = af9015_write_reg(d, 0x98e9, 0xff); - if (ret) - goto error; - - /* Remember this key */ - memcpy(state->rc_last, &buf[12], 4); - if (buf[14] == (u8) ~buf[15]) { - if (buf[12] == (u8) ~buf[13]) { - /* NEC */ - state->rc_keycode = buf[12] << 8 | buf[14]; - } else { - /* NEC extended*/ - state->rc_keycode = buf[12] << 16 | - buf[13] << 8 | buf[14]; - } - } else { - /* 32 bit NEC */ - state->rc_keycode = buf[12] << 24 | buf[13] << 16 | - buf[14] << 8 | buf[15]; - } - rc_keydown(d->rc_dev, state->rc_keycode, 0); - } else { - deb_rc("%s: no key press\n", __func__); - /* Invalidate last keypress */ - /* Not really needed, but helps with debug */ - state->rc_last[2] = state->rc_last[3]; - } - - state->rc_repeat = buf[6]; - -error: - if (ret) - err("%s: failed:%d", __func__, ret); - - return ret; -} - -static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) -{ - struct af9015_state *state = d_to_priv(d); - u16 vid = le16_to_cpu(d->udev->descriptor.idVendor); - - if (state->ir_mode == AF9015_IR_MODE_DISABLED) - return 0; - - /* try to load remote based module param */ - rc->map_name = af9015_rc_setup_match(dvb_usb_af9015_remote, - af9015_rc_setup_modparam); - - /* try to load remote based eeprom hash */ - if (!rc->map_name) - rc->map_name = af9015_rc_setup_match(state->eeprom_sum, - af9015_rc_setup_hashes); - - /* try to load remote based USB iManufacturer string */ - if (!rc->map_name && vid == USB_VID_AFATECH) { - /* Check USB manufacturer and product strings and try - to determine correct remote in case of chip vendor - reference IDs are used. - DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */ - char manufacturer[10]; - memset(manufacturer, 0, sizeof(manufacturer)); - usb_string(d->udev, d->udev->descriptor.iManufacturer, - manufacturer, sizeof(manufacturer)); - if (!strcmp("MSI", manufacturer)) { - /* iManufacturer 1 MSI - iProduct 2 MSI K-VOX */ - rc->map_name = af9015_rc_setup_match( - AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, - af9015_rc_setup_modparam); - } - } - - /* load empty to enable rc */ - if (!rc->map_name) - rc->map_name = RC_MAP_EMPTY; - - rc->allowed_protos = RC_TYPE_NEC; - rc->query = af9015_rc_query; - rc->interval = 500; - - return 0; -} - -/* interface 0 is used by DVB-T receiver and - interface 1 is for remote controller (HID) */ -static struct dvb_usb_device_properties af9015_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct af9015_state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .identify_state = af9015_identify_state, - .firmware = "dvb-usb-af9015.fw", - .download_firmware = af9015_download_firmware, - - .i2c_algo = &af9015_i2c_algo, - .read_config = af9015_read_config, - .frontend_attach = af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .init = af9015_init, - .get_rc_config = af9015_get_rc_config, - .get_stream_config = af9015_get_stream_config, - - .get_adapter_count = af9015_get_adapter_count, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = af9015_pid_filter, - .pid_filter_ctrl = af9015_pid_filter_ctrl, - - .stream = DVB_USB_STREAM_BULK(0x84, 8, TS_USB20_FRAME_SIZE), - }, { - .stream = DVB_USB_STREAM_BULK(0x85, 8, TS_USB20_FRAME_SIZE), - }, - }, -}; - -static const struct usb_device_id af9015_id_table[] = { - { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015, - &af9015_props, "Afatech AF9015 reference design", NULL) }, - { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016, - &af9015_props, "Afatech AF9015 reference design", NULL) }, - { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD, - &af9015_props, "Leadtek WinFast DTV Dongle Gold", RC_MAP_LEADTEK_Y04G0051) }, - { DVB_USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E, - &af9015_props, "Pinnacle PCTV 71e", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U, - &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) }, - { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN, - &af9015_props, "DigitalNow TinyTwin", RC_MAP_AZUREWAVE_AD_TU700) }, - { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700, - &af9015_props, "TwinHan AzureWave AD-TU700(704J)", RC_MAP_AZUREWAVE_AD_TU700) }, - { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2, - &af9015_props, "TerraTec Cinergy T USB XE", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T, - &af9015_props, "KWorld PlusTV Dual DVB-T PCI (DVB-T PC160-2T)", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X, - &af9015_props, "AVerMedia AVerTV DVB-T Volar X", RC_MAP_AVERMEDIA_M135A) }, - { DVB_USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380, - &af9015_props, "Xtensions XD-380", NULL) }, - { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO, - &af9015_props, "MSI DIGIVOX Duo", RC_MAP_MSI_DIGIVOX_III) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2, - &af9015_props, "Fujitsu-Siemens Slim Mobile USB DVB-T", NULL) }, - { DVB_USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2, - &af9015_props, "Telestar Starstick 2", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309, - &af9015_props, "AVerMedia A309", NULL) }, - { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III, - &af9015_props, "MSI Digi VOX mini III", RC_MAP_MSI_DIGIVOX_III) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U, - &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2, - &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3, - &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, - { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT, - &af9015_props, "TrekStor DVB-T USB Stick", RC_MAP_TREKSTOR) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850, - &af9015_props, "AverMedia AVerTV Volar Black HD (A850)", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805, - &af9015_props, "AverMedia AVerTV Volar GPS 805 (A805)", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU, - &af9015_props, "Conceptronic USB2.0 DVB-T CTVDIGRCU V3.0", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810, - &af9015_props, "KWorld Digial MC-810", NULL) }, - { DVB_USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03, - &af9015_props, "Genius TVGo DVB-T03", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2, - &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T, - &af9015_props, "KWorld PlusTV DVB-T PCI Pro Card (DVB-T PC160-T)", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20, - &af9015_props, "Sveon STV20 Tuner USB DVB-T HDTV", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2, - &af9015_props, "DigitalNow TinyTwin v2", RC_MAP_DIGITALNOW_TINYTWIN) }, - { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS, - &af9015_props, "Leadtek WinFast DTV2000DS", RC_MAP_LEADTEK_Y04G0051) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T, - &af9015_props, "KWorld USB DVB-T Stick Mobile (UB383-T)", NULL) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4, - &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M, - &af9015_props, "AverMedia AVerTV Volar M (A815Mac)", NULL) }, - { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC, - &af9015_props, "TerraTec Cinergy T Stick RC", RC_MAP_TERRATEC_SLIM_2) }, - { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC, - &af9015_props, "TerraTec Cinergy T Stick Dual RC", RC_MAP_TERRATEC_SLIM) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T, - &af9015_props, "AverMedia AVerTV Red HD+ (A850T)", NULL) }, - { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3, - &af9015_props, "DigitalNow TinyTwin v3", RC_MAP_DIGITALNOW_TINYTWIN) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22, - &af9015_props, "Sveon STV22 Dual USB DVB-T Tuner HDTV", RC_MAP_MSI_DIGIVOX_III) }, - { } -}; -MODULE_DEVICE_TABLE(usb, af9015_id_table); - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver af9015_usb_driver = { - .name = KBUILD_MODNAME, - .id_table = af9015_id_table, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(af9015_usb_driver); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Afatech AF9015 driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h deleted file mode 100644 index b41ee73b26dc..000000000000 --- a/drivers/media/dvb/dvb-usb/af9015.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver - * - * Copyright (C) 2007 Antti Palosaari - * - * Thanks to Afatech who kindly provided information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef AF9015_H -#define AF9015_H - -#include -#include "dvb_usb.h" -#include "af9013.h" -#include "dvb-pll.h" -#include "mt2060.h" -#include "qt1010.h" -#include "tda18271.h" -#include "mxl5005s.h" -#include "mc44s803.h" -#include "tda18218.h" -#include "mxl5007t.h" - -#define DVB_USB_LOG_PREFIX "af9015" - -#ifdef CONFIG_DVB_USB_DEBUG -#define dprintk(var, level, args...) \ - do { if ((var & level)) printk(args); } while (0) -#define DVB_USB_DEBUG_STATUS -#else -#define dprintk(args...) -#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" -#endif - -#define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args) -#define deb_rc(args...) dprintk(dvb_usb_af9015_debug, 0x02, args) - -#undef err -#define err(format, arg...) \ - printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) -#undef warn -#define warn(format, arg...) \ - printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) - -/* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0. - We use smaller - about 1/4 from the original, 5 and 87. */ -#define TS_PACKET_SIZE 188 - -#define TS_USB20_PACKET_COUNT 87 -#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT) - -#define TS_USB11_PACKET_COUNT 5 -#define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT) - -#define TS_USB20_MAX_PACKET_SIZE 512 -#define TS_USB11_MAX_PACKET_SIZE 64 - -#define AF9015_I2C_EEPROM 0xa0 -#define AF9015_I2C_DEMOD 0x38 -#define AF9015_USB_TIMEOUT 2000 - -/* EEPROM locations */ -#define AF9015_EEPROM_IR_MODE 0x18 -#define AF9015_EEPROM_IR_REMOTE_TYPE 0x34 -#define AF9015_EEPROM_TS_MODE 0x31 -#define AF9015_EEPROM_DEMOD2_I2C 0x32 - -#define AF9015_EEPROM_SAW_BW1 0x35 -#define AF9015_EEPROM_XTAL_TYPE1 0x36 -#define AF9015_EEPROM_SPEC_INV1 0x37 -#define AF9015_EEPROM_IF1L 0x38 -#define AF9015_EEPROM_IF1H 0x39 -#define AF9015_EEPROM_MT2060_IF1L 0x3a -#define AF9015_EEPROM_MT2060_IF1H 0x3b -#define AF9015_EEPROM_TUNER_ID1 0x3c - -#define AF9015_EEPROM_SAW_BW2 0x45 -#define AF9015_EEPROM_XTAL_TYPE2 0x46 -#define AF9015_EEPROM_SPEC_INV2 0x47 -#define AF9015_EEPROM_IF2L 0x48 -#define AF9015_EEPROM_IF2H 0x49 -#define AF9015_EEPROM_MT2060_IF2L 0x4a -#define AF9015_EEPROM_MT2060_IF2H 0x4b -#define AF9015_EEPROM_TUNER_ID2 0x4c - -#define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1) - -struct req_t { - u8 cmd; /* [0] */ - /* seq */ /* [1] */ - u8 i2c_addr; /* [2] */ - u16 addr; /* [3|4] */ - u8 mbox; /* [5] */ - u8 addr_len; /* [6] */ - u8 data_len; /* [7] */ - u8 *data; -}; - -enum af9015_cmd { - GET_CONFIG = 0x10, - DOWNLOAD_FIRMWARE = 0x11, - BOOT = 0x13, - READ_MEMORY = 0x20, - WRITE_MEMORY = 0x21, - READ_WRITE_I2C = 0x22, - COPY_FIRMWARE = 0x23, - RECONNECT_USB = 0x5a, - WRITE_VIRTUAL_MEMORY = 0x26, - GET_IR_CODE = 0x27, - READ_I2C, - WRITE_I2C, -}; - -enum af9015_ir_mode { - AF9015_IR_MODE_DISABLED = 0, - AF9015_IR_MODE_HID, - AF9015_IR_MODE_RLC, - AF9015_IR_MODE_RC6, - AF9015_IR_MODE_POLLING, /* just guess */ -}; - -struct af9015_state { - u8 ir_mode; - u8 rc_repeat; - u32 rc_keycode; - u8 rc_last[4]; - u8 dual_mode; - u8 seq; /* packet sequence number */ - u16 mt2060_if1[2]; - u16 firmware_size; - u16 firmware_checksum; - u32 eeprom_sum; - struct af9013_config af9013_config[2]; - - /* for demod callback override */ - int (*set_frontend[2]) (struct dvb_frontend *fe); - int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status); - int (*init[2]) (struct dvb_frontend *fe); - int (*sleep[2]) (struct dvb_frontend *fe); - int (*tuner_init[2]) (struct dvb_frontend *fe); - int (*tuner_sleep[2]) (struct dvb_frontend *fe); - struct mutex fe_mutex; -}; - -enum af9015_remote { - AF9015_REMOTE_NONE = 0, -/* 1 */ AF9015_REMOTE_A_LINK_DTU_M, - AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, - AF9015_REMOTE_MYGICTV_U718, - AF9015_REMOTE_DIGITTRADE_DVB_T, -/* 5 */ AF9015_REMOTE_AVERMEDIA_KS, -}; - -#endif diff --git a/drivers/media/dvb/dvb-usb/af9035.c b/drivers/media/dvb/dvb-usb/af9035.c deleted file mode 100644 index 79197f46aa95..000000000000 --- a/drivers/media/dvb/dvb-usb/af9035.c +++ /dev/null @@ -1,1087 +0,0 @@ -/* - * Afatech AF9035 DVB USB driver - * - * Copyright (C) 2009 Antti Palosaari - * Copyright (C) 2012 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "af9035.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static u16 af9035_checksum(const u8 *buf, size_t len) -{ - size_t i; - u16 checksum = 0; - - for (i = 1; i < len; i++) { - if (i % 2) - checksum += buf[i] << 8; - else - checksum += buf[i]; - } - checksum = ~checksum; - - return checksum; -} - -static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) -{ -#define BUF_LEN 64 -#define REQ_HDR_LEN 4 /* send header size */ -#define ACK_HDR_LEN 3 /* rece header size */ -#define CHECKSUM_LEN 2 -#define USB_TIMEOUT 2000 - struct state *state = d_to_priv(d); - int ret, wlen, rlen; - u8 buf[BUF_LEN]; - u16 checksum, tmp_checksum; - - /* buffer overflow check */ - if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) || - req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) { - pr_debug("%s: too much data wlen=%d rlen=%d\n", __func__, - req->wlen, req->rlen); - return -EINVAL; - } - - buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1; - buf[1] = req->mbox; - buf[2] = req->cmd; - buf[3] = state->seq++; - memcpy(&buf[REQ_HDR_LEN], req->wbuf, req->wlen); - - wlen = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN; - rlen = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN; - - /* calc and add checksum */ - checksum = af9035_checksum(buf, buf[0] - 1); - buf[buf[0] - 1] = (checksum >> 8); - buf[buf[0] - 0] = (checksum & 0xff); - - /* no ack for these packets */ - if (req->cmd == CMD_FW_DL) - rlen = 0; - - ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen); - if (ret) - goto err; - - /* no ack for those packets */ - if (req->cmd == CMD_FW_DL) - goto exit; - - /* verify checksum */ - checksum = af9035_checksum(buf, rlen - 2); - tmp_checksum = (buf[rlen - 2] << 8) | buf[rlen - 1]; - if (tmp_checksum != checksum) { - pr_err("%s: command=%02x checksum mismatch (%04x != %04x)\n", - KBUILD_MODNAME, req->cmd, tmp_checksum, - checksum); - ret = -EIO; - goto err; - } - - /* check status */ - if (buf[2]) { - pr_debug("%s: command=%02x failed fw error=%d\n", __func__, - req->cmd, buf[2]); - ret = -EIO; - goto err; - } - - /* read request, copy returned data to return buf */ - if (req->rlen) - memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen); - -exit: - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -/* write multiple registers */ -static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) -{ - u8 wbuf[6 + len]; - u8 mbox = (reg >> 16) & 0xff; - struct usb_req req = { CMD_MEM_WR, mbox, sizeof(wbuf), wbuf, 0, NULL }; - - wbuf[0] = len; - wbuf[1] = 2; - wbuf[2] = 0; - wbuf[3] = 0; - wbuf[4] = (reg >> 8) & 0xff; - wbuf[5] = (reg >> 0) & 0xff; - memcpy(&wbuf[6], val, len); - - return af9035_ctrl_msg(d, &req); -} - -/* read multiple registers */ -static int af9035_rd_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) -{ - u8 wbuf[] = { len, 2, 0, 0, (reg >> 8) & 0xff, reg & 0xff }; - u8 mbox = (reg >> 16) & 0xff; - struct usb_req req = { CMD_MEM_RD, mbox, sizeof(wbuf), wbuf, len, val }; - - return af9035_ctrl_msg(d, &req); -} - -/* write single register */ -static int af9035_wr_reg(struct dvb_usb_device *d, u32 reg, u8 val) -{ - return af9035_wr_regs(d, reg, &val, 1); -} - -/* read single register */ -static int af9035_rd_reg(struct dvb_usb_device *d, u32 reg, u8 *val) -{ - return af9035_rd_regs(d, reg, val, 1); -} - -/* write single register with mask */ -static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val, - u8 mask) -{ - int ret; - u8 tmp; - - /* no need for read if whole reg is written */ - if (mask != 0xff) { - ret = af9035_rd_regs(d, reg, &tmp, 1); - if (ret) - return ret; - - val &= mask; - tmp &= ~mask; - val |= tmp; - } - - return af9035_wr_regs(d, reg, &val, 1); -} - -static int af9035_i2c_master_xfer(struct i2c_adapter *adap, - struct i2c_msg msg[], int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct state *state = d_to_priv(d); - int ret; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - /* - * I2C sub header is 5 bytes long. Meaning of those bytes are: - * 0: data len - * 1: I2C addr << 1 - * 2: reg addr len - * byte 3 and 4 can be used as reg addr - * 3: reg addr MSB - * used when reg addr len is set to 2 - * 4: reg addr LSB - * used when reg addr len is set to 1 or 2 - * - * For the simplify we do not use register addr at all. - * NOTE: As a firmware knows tuner type there is very small possibility - * there could be some tuner I2C hacks done by firmware and this may - * lead problems if firmware expects those bytes are used. - */ - if (num == 2 && !(msg[0].flags & I2C_M_RD) && - (msg[1].flags & I2C_M_RD)) { - if (msg[0].len > 40 || msg[1].len > 40) { - /* TODO: correct limits > 40 */ - ret = -EOPNOTSUPP; - } else if (msg[0].addr == state->af9033_config[0].i2c_addr) { - /* integrated demod */ - u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | - msg[0].buf[2]; - ret = af9035_rd_regs(d, reg, &msg[1].buf[0], - msg[1].len); - } else { - /* I2C */ - u8 buf[5 + msg[0].len]; - struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf), - buf, msg[1].len, msg[1].buf }; - buf[0] = msg[1].len; - buf[1] = msg[0].addr << 1; - buf[2] = 0x00; /* reg addr len */ - buf[3] = 0x00; /* reg addr MSB */ - buf[4] = 0x00; /* reg addr LSB */ - memcpy(&buf[5], msg[0].buf, msg[0].len); - ret = af9035_ctrl_msg(d, &req); - } - } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) { - if (msg[0].len > 40) { - /* TODO: correct limits > 40 */ - ret = -EOPNOTSUPP; - } else if (msg[0].addr == state->af9033_config[0].i2c_addr) { - /* integrated demod */ - u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | - msg[0].buf[2]; - ret = af9035_wr_regs(d, reg, &msg[0].buf[3], - msg[0].len - 3); - } else { - /* I2C */ - u8 buf[5 + msg[0].len]; - struct usb_req req = { CMD_I2C_WR, 0, sizeof(buf), buf, - 0, NULL }; - buf[0] = msg[0].len; - buf[1] = msg[0].addr << 1; - buf[2] = 0x00; /* reg addr len */ - buf[3] = 0x00; /* reg addr MSB */ - buf[4] = 0x00; /* reg addr LSB */ - memcpy(&buf[5], msg[0].buf, msg[0].len); - ret = af9035_ctrl_msg(d, &req); - } - } else { - /* - * We support only two kind of I2C transactions: - * 1) 1 x read + 1 x write - * 2) 1 x write - */ - ret = -EOPNOTSUPP; - } - - mutex_unlock(&d->i2c_mutex); - - if (ret < 0) - return ret; - else - return num; -} - -static u32 af9035_i2c_functionality(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm af9035_i2c_algo = { - .master_xfer = af9035_i2c_master_xfer, - .functionality = af9035_i2c_functionality, -}; - -static int af9035_identify_state(struct dvb_usb_device *d, const char **name) -{ - int ret; - u8 wbuf[1] = { 1 }; - u8 rbuf[4]; - struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf, - sizeof(rbuf), rbuf }; - - ret = af9035_ctrl_msg(d, &req); - if (ret < 0) - goto err; - - pr_debug("%s: reply=%02x %02x %02x %02x\n", __func__, - rbuf[0], rbuf[1], rbuf[2], rbuf[3]); - if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3]) - ret = WARM; - else - ret = COLD; - - return ret; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_download_firmware(struct dvb_usb_device *d, - const struct firmware *fw) -{ - int ret, i, j, len; - u8 wbuf[1]; - u8 rbuf[4]; - struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; - struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL }; - struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ; - u8 hdr_core; - u16 hdr_addr, hdr_data_len, hdr_checksum; - #define MAX_DATA 58 - #define HDR_SIZE 7 - - /* - * Thanks to Daniel Glöckner about that info! - * - * byte 0: MCS 51 core - * There are two inside the AF9035 (1=Link and 2=OFDM) with separate - * address spaces - * byte 1-2: Big endian destination address - * byte 3-4: Big endian number of data bytes following the header - * byte 5-6: Big endian header checksum, apparently ignored by the chip - * Calculated as ~(h[0]*256+h[1]+h[2]*256+h[3]+h[4]*256) - */ - - for (i = fw->size; i > HDR_SIZE;) { - hdr_core = fw->data[fw->size - i + 0]; - hdr_addr = fw->data[fw->size - i + 1] << 8; - hdr_addr |= fw->data[fw->size - i + 2] << 0; - hdr_data_len = fw->data[fw->size - i + 3] << 8; - hdr_data_len |= fw->data[fw->size - i + 4] << 0; - hdr_checksum = fw->data[fw->size - i + 5] << 8; - hdr_checksum |= fw->data[fw->size - i + 6] << 0; - - pr_debug("%s: core=%d addr=%04x data_len=%d checksum=%04x\n", - __func__, hdr_core, hdr_addr, hdr_data_len, - hdr_checksum); - - if (((hdr_core != 1) && (hdr_core != 2)) || - (hdr_data_len > i)) { - pr_debug("%s: bad firmware\n", __func__); - break; - } - - /* download begin packet */ - req.cmd = CMD_FW_DL_BEGIN; - ret = af9035_ctrl_msg(d, &req); - if (ret < 0) - goto err; - - /* download firmware packet(s) */ - for (j = HDR_SIZE + hdr_data_len; j > 0; j -= MAX_DATA) { - len = j; - if (len > MAX_DATA) - len = MAX_DATA; - req_fw_dl.wlen = len; - req_fw_dl.wbuf = (u8 *) &fw->data[fw->size - i + - HDR_SIZE + hdr_data_len - j]; - ret = af9035_ctrl_msg(d, &req_fw_dl); - if (ret < 0) - goto err; - } - - /* download end packet */ - req.cmd = CMD_FW_DL_END; - ret = af9035_ctrl_msg(d, &req); - if (ret < 0) - goto err; - - i -= hdr_data_len + HDR_SIZE; - - pr_debug("%s: data uploaded=%zu\n", __func__, fw->size - i); - } - - /* firmware loaded, request boot */ - req.cmd = CMD_FW_BOOT; - ret = af9035_ctrl_msg(d, &req); - if (ret < 0) - goto err; - - /* ensure firmware starts */ - wbuf[0] = 1; - ret = af9035_ctrl_msg(d, &req_fw_ver); - if (ret < 0) - goto err; - - if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { - pr_err("%s: firmware did not run\n", KBUILD_MODNAME); - ret = -ENODEV; - goto err; - } - - pr_info("%s: firmware version=%d.%d.%d.%d", KBUILD_MODNAME, - rbuf[0], rbuf[1], rbuf[2], rbuf[3]); - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_download_firmware_it9135(struct dvb_usb_device *d, - const struct firmware *fw) -{ - int ret, i, i_prev; - u8 wbuf[1]; - u8 rbuf[4]; - struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; - struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL }; - struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ; - #define HDR_SIZE 7 - - /* - * There seems to be following firmware header. Meaning of bytes 0-3 - * is unknown. - * - * 0: 3 - * 1: 0, 1 - * 2: 0 - * 3: 1, 2, 3 - * 4: addr MSB - * 5: addr LSB - * 6: count of data bytes ? - */ - - for (i = HDR_SIZE, i_prev = 0; i <= fw->size; i++) { - if (i == fw->size || - (fw->data[i + 0] == 0x03 && - (fw->data[i + 1] == 0x00 || - fw->data[i + 1] == 0x01) && - fw->data[i + 2] == 0x00)) { - req_fw_dl.wlen = i - i_prev; - req_fw_dl.wbuf = (u8 *) &fw->data[i_prev]; - i_prev = i; - ret = af9035_ctrl_msg(d, &req_fw_dl); - if (ret < 0) - goto err; - - pr_debug("%s: data uploaded=%d\n", __func__, i); - } - } - - /* firmware loaded, request boot */ - req.cmd = CMD_FW_BOOT; - ret = af9035_ctrl_msg(d, &req); - if (ret < 0) - goto err; - - /* ensure firmware starts */ - wbuf[0] = 1; - ret = af9035_ctrl_msg(d, &req_fw_ver); - if (ret < 0) - goto err; - - if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { - pr_err("%s: firmware did not run\n", KBUILD_MODNAME); - ret = -ENODEV; - goto err; - } - - pr_info("%s: firmware version=%d.%d.%d.%d", KBUILD_MODNAME, - rbuf[0], rbuf[1], rbuf[2], rbuf[3]); - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_read_config(struct dvb_usb_device *d) -{ - struct state *state = d_to_priv(d); - int ret, i, eeprom_shift = 0; - u8 tmp; - u16 tmp16; - - /* check if there is dual tuners */ - ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp); - if (ret < 0) - goto err; - - state->dual_mode = tmp; - pr_debug("%s: dual mode=%d\n", __func__, state->dual_mode); - - for (i = 0; i < state->dual_mode + 1; i++) { - /* tuner */ - ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp); - if (ret < 0) - goto err; - - state->af9033_config[i].tuner = tmp; - pr_debug("%s: [%d]tuner=%02x\n", __func__, i, tmp); - - switch (tmp) { - case AF9033_TUNER_TUA9001: - case AF9033_TUNER_FC0011: - case AF9033_TUNER_MXL5007T: - case AF9033_TUNER_TDA18218: - state->af9033_config[i].spec_inv = 1; - break; - default: - pr_info("%s: tuner ID=%02x not supported, please " \ - "report!", KBUILD_MODNAME, tmp); - }; - - /* tuner IF frequency */ - ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp); - if (ret < 0) - goto err; - - tmp16 = tmp; - - ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_H + eeprom_shift, &tmp); - if (ret < 0) - goto err; - - tmp16 |= tmp << 8; - - pr_debug("%s: [%d]IF=%d\n", __func__, i, tmp16); - - eeprom_shift = 0x10; /* shift for the 2nd tuner params */ - } - - /* get demod clock */ - ret = af9035_rd_reg(d, 0x00d800, &tmp); - if (ret < 0) - goto err; - - tmp = (tmp >> 0) & 0x0f; - - for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++) - state->af9033_config[i].clock = clock_lut[tmp]; - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_read_config_it9135(struct dvb_usb_device *d) -{ - struct state *state = d_to_priv(d); - int ret, i; - u8 tmp; - - state->dual_mode = false; - - /* get demod clock */ - ret = af9035_rd_reg(d, 0x00d800, &tmp); - if (ret < 0) - goto err; - - tmp = (tmp >> 0) & 0x0f; - - for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++) - state->af9033_config[i].clock = clock_lut_it9135[tmp]; - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_fc0011_tuner_callback(struct dvb_usb_device *d, - int cmd, int arg) -{ - int ret; - - switch (cmd) { - case FC0011_FE_CALLBACK_POWER: - /* Tuner enable */ - ret = af9035_wr_reg_mask(d, 0xd8eb, 1, 1); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0xd8ec, 1, 1); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0xd8ed, 1, 1); - if (ret < 0) - goto err; - - /* LED */ - ret = af9035_wr_reg_mask(d, 0xd8d0, 1, 1); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0xd8d1, 1, 1); - if (ret < 0) - goto err; - - usleep_range(10000, 50000); - break; - case FC0011_FE_CALLBACK_RESET: - ret = af9035_wr_reg(d, 0xd8e9, 1); - if (ret < 0) - goto err; - - ret = af9035_wr_reg(d, 0xd8e8, 1); - if (ret < 0) - goto err; - - ret = af9035_wr_reg(d, 0xd8e7, 1); - if (ret < 0) - goto err; - - usleep_range(10000, 20000); - - ret = af9035_wr_reg(d, 0xd8e7, 0); - if (ret < 0) - goto err; - - usleep_range(10000, 20000); - break; - default: - ret = -EINVAL; - goto err; - } - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_tuner_callback(struct dvb_usb_device *d, int cmd, int arg) -{ - struct state *state = d_to_priv(d); - - switch (state->af9033_config[0].tuner) { - case AF9033_TUNER_FC0011: - return af9035_fc0011_tuner_callback(d, cmd, arg); - default: - break; - } - - return -ENODEV; -} - -static int af9035_frontend_callback(void *adapter_priv, int component, - int cmd, int arg) -{ - struct i2c_adapter *adap = adapter_priv; - struct dvb_usb_device *d = i2c_get_adapdata(adap); - - switch (component) { - case DVB_FRONTEND_COMPONENT_TUNER: - return af9035_tuner_callback(d, cmd, arg); - default: - break; - } - - return -EINVAL; -} - -static int af9035_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct state *state = adap_to_priv(adap); - struct dvb_usb_device *d = adap_to_d(adap); - int ret; - - if (!state->af9033_config[adap->id].tuner) { - /* unsupported tuner */ - ret = -ENODEV; - goto err; - } - - if (adap->id == 0) { - state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB; - state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL; - - ret = af9035_wr_reg(d, 0x00417f, - state->af9033_config[1].i2c_addr); - if (ret < 0) - goto err; - - ret = af9035_wr_reg(d, 0x00d81a, - state->dual_mode); - if (ret < 0) - goto err; - } - - /* attach demodulator */ - adap->fe[0] = dvb_attach(af9033_attach, - &state->af9033_config[adap->id], &d->i2c_adap); - if (adap->fe[0] == NULL) { - ret = -ENODEV; - goto err; - } - - /* disable I2C-gate */ - adap->fe[0]->ops.i2c_gate_ctrl = NULL; - adap->fe[0]->callback = af9035_frontend_callback; - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static struct tua9001_config af9035_tua9001_config = { - .i2c_addr = 0x60, -}; - -static const struct fc0011_config af9035_fc0011_config = { - .i2c_address = 0x60, -}; - -static struct mxl5007t_config af9035_mxl5007t_config = { - .xtal_freq_hz = MxL_XTAL_24_MHZ, - .if_freq_hz = MxL_IF_4_57_MHZ, - .invert_if = 0, - .loop_thru_enable = 0, - .clk_out_enable = 0, - .clk_out_amp = MxL_CLKOUT_AMP_0_94V, -}; - -static struct tda18218_config af9035_tda18218_config = { - .i2c_address = 0x60, - .i2c_wr_max = 21, -}; - -static int af9035_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct state *state = adap_to_priv(adap); - struct dvb_usb_device *d = adap_to_d(adap); - int ret; - struct dvb_frontend *fe; - - switch (state->af9033_config[adap->id].tuner) { - case AF9033_TUNER_TUA9001: - /* AF9035 gpiot3 = TUA9001 RESETN - AF9035 gpiot2 = TUA9001 RXEN */ - - /* configure gpiot2 and gpiot2 as output */ - ret = af9035_wr_reg_mask(d, 0x00d8ec, 0x01, 0x01); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0x00d8ed, 0x01, 0x01); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0x00d8e8, 0x01, 0x01); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0x00d8e9, 0x01, 0x01); - if (ret < 0) - goto err; - - /* reset tuner */ - ret = af9035_wr_reg_mask(d, 0x00d8e7, 0x00, 0x01); - if (ret < 0) - goto err; - - usleep_range(2000, 20000); - - ret = af9035_wr_reg_mask(d, 0x00d8e7, 0x01, 0x01); - if (ret < 0) - goto err; - - /* activate tuner RX */ - /* TODO: use callback for TUA9001 RXEN */ - ret = af9035_wr_reg_mask(d, 0x00d8eb, 0x01, 0x01); - if (ret < 0) - goto err; - - /* attach tuner */ - fe = dvb_attach(tua9001_attach, adap->fe[0], - &d->i2c_adap, &af9035_tua9001_config); - break; - case AF9033_TUNER_FC0011: - fe = dvb_attach(fc0011_attach, adap->fe[0], - &d->i2c_adap, &af9035_fc0011_config); - break; - case AF9033_TUNER_MXL5007T: - ret = af9035_wr_reg(d, 0x00d8e0, 1); - if (ret < 0) - goto err; - ret = af9035_wr_reg(d, 0x00d8e1, 1); - if (ret < 0) - goto err; - ret = af9035_wr_reg(d, 0x00d8df, 0); - if (ret < 0) - goto err; - - msleep(30); - - ret = af9035_wr_reg(d, 0x00d8df, 1); - if (ret < 0) - goto err; - - msleep(300); - - ret = af9035_wr_reg(d, 0x00d8c0, 1); - if (ret < 0) - goto err; - ret = af9035_wr_reg(d, 0x00d8c1, 1); - if (ret < 0) - goto err; - ret = af9035_wr_reg(d, 0x00d8bf, 0); - if (ret < 0) - goto err; - ret = af9035_wr_reg(d, 0x00d8b4, 1); - if (ret < 0) - goto err; - ret = af9035_wr_reg(d, 0x00d8b5, 1); - if (ret < 0) - goto err; - ret = af9035_wr_reg(d, 0x00d8b3, 1); - if (ret < 0) - goto err; - - /* attach tuner */ - fe = dvb_attach(mxl5007t_attach, adap->fe[0], - &d->i2c_adap, 0x60, &af9035_mxl5007t_config); - break; - case AF9033_TUNER_TDA18218: - /* attach tuner */ - fe = dvb_attach(tda18218_attach, adap->fe[0], - &d->i2c_adap, &af9035_tda18218_config); - break; - default: - fe = NULL; - } - - if (fe == NULL) { - ret = -ENODEV; - goto err; - } - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_init(struct dvb_usb_device *d) -{ - struct state *state = d_to_priv(d); - int ret, i; - u16 frame_size = 87 * 188 / 4; - u8 packet_size = 512 / 4; - struct reg_val_mask tab[] = { - { 0x80f99d, 0x01, 0x01 }, - { 0x80f9a4, 0x01, 0x01 }, - { 0x00dd11, 0x00, 0x20 }, - { 0x00dd11, 0x00, 0x40 }, - { 0x00dd13, 0x00, 0x20 }, - { 0x00dd13, 0x00, 0x40 }, - { 0x00dd11, 0x20, 0x20 }, - { 0x00dd88, (frame_size >> 0) & 0xff, 0xff}, - { 0x00dd89, (frame_size >> 8) & 0xff, 0xff}, - { 0x00dd0c, packet_size, 0xff}, - { 0x00dd11, state->dual_mode << 6, 0x40 }, - { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff}, - { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff}, - { 0x00dd0d, packet_size, 0xff }, - { 0x80f9a3, 0x00, 0x01 }, - { 0x80f9cd, 0x00, 0x01 }, - { 0x80f99d, 0x00, 0x01 }, - { 0x80f9a4, 0x00, 0x01 }, - }; - - pr_debug("%s: USB speed=%d frame_size=%04x packet_size=%02x\n", - __func__, d->udev->speed, frame_size, packet_size); - - /* init endpoints */ - for (i = 0; i < ARRAY_SIZE(tab); i++) { - ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val, - tab[i].mask); - if (ret < 0) - goto err; - } - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_rc_query(struct dvb_usb_device *d) -{ - unsigned int key; - unsigned char b[4]; - int ret; - struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b }; - - ret = af9035_ctrl_msg(d, &req); - if (ret < 0) - goto err; - - if ((b[2] + b[3]) == 0xff) { - if ((b[0] + b[1]) == 0xff) { - /* NEC */ - key = b[0] << 8 | b[2]; - } else { - /* ext. NEC */ - key = b[0] << 16 | b[1] << 8 | b[2]; - } - } else { - key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]; - } - - rc_keydown(d->rc_dev, key, 0); - -err: - /* ignore errors */ - return 0; -} - -static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) -{ - int ret; - u8 tmp; - - ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp); - if (ret < 0) - goto err; - - pr_debug("%s: ir_mode=%02x\n", __func__, tmp); - - /* don't activate rc if in HID mode or if not available */ - if (tmp == 5) { - ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp); - if (ret < 0) - goto err; - - pr_debug("%s: ir_type=%02x\n", __func__, tmp); - - switch (tmp) { - case 0: /* NEC */ - default: - rc->allowed_protos = RC_TYPE_NEC; - break; - case 1: /* RC6 */ - rc->allowed_protos = RC_TYPE_RC6; - break; - } - - rc->query = af9035_rc_query; - rc->interval = 500; - - /* load empty to enable rc */ - if (!rc->map_name) - rc->map_name = RC_MAP_EMPTY; - } - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -/* interface 0 is used by DVB-T receiver and - interface 1 is for remote controller (HID) */ -static const struct dvb_usb_device_properties af9035_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .identify_state = af9035_identify_state, - .firmware = "dvb-usb-af9035-02.fw", - .download_firmware = af9035_download_firmware, - - .i2c_algo = &af9035_i2c_algo, - .read_config = af9035_read_config, - .frontend_attach = af9035_frontend_attach, - .tuner_attach = af9035_tuner_attach, - .init = af9035_init, - .get_rc_config = af9035_get_rc_config, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), - }, { - .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), - }, - }, -}; - -static const struct dvb_usb_device_properties it9135_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .identify_state = af9035_identify_state, - .firmware = "dvb-usb-it9135-01.fw", - .download_firmware = af9035_download_firmware_it9135, - - .i2c_algo = &af9035_i2c_algo, - .read_config = af9035_read_config_it9135, - .frontend_attach = af9035_frontend_attach, - .tuner_attach = af9035_tuner_attach, - .init = af9035_init, - .get_rc_config = af9035_get_rc_config, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), - }, { - .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), - }, - }, -}; - -static const struct usb_device_id af9035_id_table[] = { - { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035, - &af9035_props, "Afatech AF9035 reference design", NULL) }, - { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000, - &af9035_props, "Afatech AF9035 reference design", NULL) }, - { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1001, - &af9035_props, "Afatech AF9035 reference design", NULL) }, - { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1002, - &af9035_props, "Afatech AF9035 reference design", NULL) }, - { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1003, - &af9035_props, "Afatech AF9035 reference design", NULL) }, - { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK, - &af9035_props, "TerraTec Cinergy T Stick", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835, - &af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835, - &af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867, - &af9035_props, "AVerMedia HD Volar (A867)", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867, - &af9035_props, "AVerMedia HD Volar (A867)", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR, - &af9035_props, "AVerMedia Twinstar (A825)", NULL) }, - { } -}; -MODULE_DEVICE_TABLE(usb, af9035_id_table); - -static struct usb_driver af9035_usb_driver = { - .name = KBUILD_MODNAME, - .id_table = af9035_id_table, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(af9035_usb_driver); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Afatech AF9035 driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/af9035.h b/drivers/media/dvb/dvb-usb/af9035.h deleted file mode 100644 index 59ff69ede0f0..000000000000 --- a/drivers/media/dvb/dvb-usb/af9035.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Afatech AF9035 DVB USB driver - * - * Copyright (C) 2009 Antti Palosaari - * Copyright (C) 2012 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef AF9035_H -#define AF9035_H - -#include "dvb_usb.h" -#include "af9033.h" -#include "tua9001.h" -#include "fc0011.h" -#include "mxl5007t.h" -#include "tda18218.h" - -struct reg_val { - u32 reg; - u8 val; -}; - -struct reg_val_mask { - u32 reg; - u8 val; - u8 mask; -}; - -struct usb_req { - u8 cmd; - u8 mbox; - u8 wlen; - u8 *wbuf; - u8 rlen; - u8 *rbuf; -}; - -struct state { - u8 seq; /* packet sequence number */ - bool dual_mode; - - struct af9033_config af9033_config[2]; -}; - -u32 clock_lut[] = { - 20480000, /* FPGA */ - 16384000, /* 16.38 MHz */ - 20480000, /* 20.48 MHz */ - 36000000, /* 36.00 MHz */ - 30000000, /* 30.00 MHz */ - 26000000, /* 26.00 MHz */ - 28000000, /* 28.00 MHz */ - 32000000, /* 32.00 MHz */ - 34000000, /* 34.00 MHz */ - 24000000, /* 24.00 MHz */ - 22000000, /* 22.00 MHz */ - 12000000, /* 12.00 MHz */ -}; - -u32 clock_lut_it9135[] = { - 12000000, /* 12.00 MHz */ - 20480000, /* 20.48 MHz */ - 36000000, /* 36.00 MHz */ - 30000000, /* 30.00 MHz */ - 26000000, /* 26.00 MHz */ - 28000000, /* 28.00 MHz */ - 32000000, /* 32.00 MHz */ - 34000000, /* 34.00 MHz */ - 24000000, /* 24.00 MHz */ - 22000000, /* 22.00 MHz */ -}; - -/* EEPROM locations */ -#define EEPROM_IR_MODE 0x430d -#define EEPROM_DUAL_MODE 0x4326 -#define EEPROM_IR_TYPE 0x4329 -#define EEPROM_1_IFFREQ_L 0x432d -#define EEPROM_1_IFFREQ_H 0x432e -#define EEPROM_1_TUNER_ID 0x4331 -#define EEPROM_2_IFFREQ_L 0x433d -#define EEPROM_2_IFFREQ_H 0x433e -#define EEPROM_2_TUNER_ID 0x4341 - -/* USB commands */ -#define CMD_MEM_RD 0x00 -#define CMD_MEM_WR 0x01 -#define CMD_I2C_RD 0x02 -#define CMD_I2C_WR 0x03 -#define CMD_IR_GET 0x18 -#define CMD_FW_DL 0x21 -#define CMD_FW_QUERYINFO 0x22 -#define CMD_FW_BOOT 0x23 -#define CMD_FW_DL_BEGIN 0x24 -#define CMD_FW_DL_END 0x25 -#define CMD_FW_SCATTER_WR 0x29 - -#endif diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c deleted file mode 100644 index fb3829a73d2d..000000000000 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ /dev/null @@ -1,1324 +0,0 @@ -/* - * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver - * - * Copyright (C) 2007 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * TODO: - * - add smart card reader support for Conditional Access (CA) - * - * Card reader in Anysee is nothing more than ISO 7816 card reader. - * There is no hardware CAM in any Anysee device sold. - * In my understanding it should be implemented by making own module - * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This - * module registers serial interface that can be used to communicate - * with any ISO 7816 smart card. - * - * Any help according to implement serial smart card reader support - * is highly welcome! - */ - -#include "anysee.h" -#include "dvb-pll.h" -#include "tda1002x.h" -#include "mt352.h" -#include "mt352_priv.h" -#include "zl10353.h" -#include "tda18212.h" -#include "cx24116.h" -#include "stv0900.h" -#include "stv6110.h" -#include "isl6423.h" -#include "cxd2820r.h" - -/* debug */ -static int dvb_usb_anysee_debug; -module_param_named(debug, dvb_usb_anysee_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static DEFINE_MUTEX(anysee_usb_mutex); - -static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, - u8 *rbuf, u8 rlen) -{ - struct anysee_state *state = d_to_priv(d); - int act_len, ret, i; - u8 buf[64]; - - memcpy(&buf[0], sbuf, slen); - buf[60] = state->seq++; - - mutex_lock(&anysee_usb_mutex); - - deb_xfer(">>> "); - debug_dump(buf, slen, deb_xfer); - - /* We need receive one message more after dvb_usb_generic_rw due - to weird transaction flow, which is 1 x send + 2 x receive. */ - ret = dvb_usbv2_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf)); - if (ret) - goto error_unlock; - - /* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32 - * (EPIPE, Broken pipe). Function supports currently msleep() as a - * parameter but I would not like to use it, since according to - * Documentation/timers/timers-howto.txt it should not be used such - * short, under < 20ms, sleeps. Repeating failed message would be - * better choice as not to add unwanted delays... - * Fixing that correctly is one of those or both; - * 1) use repeat if possible - * 2) add suitable delay - */ - - /* get answer, retry few times if error returned */ - for (i = 0; i < 3; i++) { - /* receive 2nd answer */ - ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, - d->props->generic_bulk_ctrl_endpoint), buf, sizeof(buf), - &act_len, 2000); - - if (ret) { - deb_info("%s: recv bulk message failed: %d", - __func__, ret); - } else { - deb_xfer("<<< "); - debug_dump(buf, rlen, deb_xfer); - - if (buf[63] != 0x4f) - deb_info("%s: cmd failed\n", __func__); - - break; - } - } - - if (ret) { - /* all retries failed, it is fatal */ - err("%s: recv bulk message failed: %d", __func__, ret); - goto error_unlock; - } - - /* read request, copy returned data to return buf */ - if (rbuf && rlen) - memcpy(rbuf, buf, rlen); - -error_unlock: - mutex_unlock(&anysee_usb_mutex); - - return ret; -} - -static int anysee_read_reg(struct dvb_usb_device *d, u16 reg, u8 *val) -{ - u8 buf[] = {CMD_REG_READ, reg >> 8, reg & 0xff, 0x01}; - int ret; - ret = anysee_ctrl_msg(d, buf, sizeof(buf), val, 1); - deb_info("%s: reg:%04x val:%02x\n", __func__, reg, *val); - return ret; -} - -static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val) -{ - u8 buf[] = {CMD_REG_WRITE, reg >> 8, reg & 0xff, 0x01, val}; - deb_info("%s: reg:%04x val:%02x\n", __func__, reg, val); - return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); -} - -/* write single register with mask */ -static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val, - u8 mask) -{ - int ret; - u8 tmp; - - /* no need for read if whole reg is written */ - if (mask != 0xff) { - ret = anysee_read_reg(d, reg, &tmp); - if (ret) - return ret; - - val &= mask; - tmp &= ~mask; - val |= tmp; - } - - return anysee_write_reg(d, reg, val); -} - -/* read single register with mask */ -static int anysee_rd_reg_mask(struct dvb_usb_device *d, u16 reg, u8 *val, - u8 mask) -{ - int ret, i; - u8 tmp; - - ret = anysee_read_reg(d, reg, &tmp); - if (ret) - return ret; - - tmp &= mask; - - /* find position of the first bit */ - for (i = 0; i < 8; i++) { - if ((mask >> i) & 0x01) - break; - } - *val = tmp >> i; - - return 0; -} - -static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id) -{ - u8 buf[] = {CMD_GET_HW_INFO}; - return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3); -} - -static int anysee_streaming_ctrl(struct dvb_frontend *fe, int onoff) -{ - u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00}; - deb_info("%s: onoff:%02x\n", __func__, onoff); - return anysee_ctrl_msg(fe_to_d(fe), buf, sizeof(buf), NULL, 0); -} - -static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval) -{ - u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x01, mode, interval}; - deb_info("%s: state:%02x interval:%02x\n", __func__, mode, interval); - return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); -} - -static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff) -{ - u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x02, onoff}; - deb_info("%s: onoff:%02x\n", __func__, onoff); - return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); -} - -/* I2C */ -static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int ret = 0, inc, i = 0; - u8 buf[52]; /* 4 + 48 (I2C WR USB command header + I2C WR max) */ - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - while (i < num) { - if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { - if (msg[i].len > 2 || msg[i+1].len > 60) { - ret = -EOPNOTSUPP; - break; - } - buf[0] = CMD_I2C_READ; - buf[1] = (msg[i].addr << 1) | 0x01; - buf[2] = msg[i].buf[0]; - buf[3] = msg[i].buf[1]; - buf[4] = msg[i].len-1; - buf[5] = msg[i+1].len; - ret = anysee_ctrl_msg(d, buf, 6, msg[i+1].buf, - msg[i+1].len); - inc = 2; - } else { - if (msg[i].len > 48) { - ret = -EOPNOTSUPP; - break; - } - buf[0] = CMD_I2C_WRITE; - buf[1] = (msg[i].addr << 1); - buf[2] = msg[i].len; - buf[3] = 0x01; - memcpy(&buf[4], msg[i].buf, msg[i].len); - ret = anysee_ctrl_msg(d, buf, 4 + msg[i].len, NULL, 0); - inc = 1; - } - if (ret) - break; - - i += inc; - } - - mutex_unlock(&d->i2c_mutex); - - return ret ? ret : i; -} - -static u32 anysee_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm anysee_i2c_algo = { - .master_xfer = anysee_master_xfer, - .functionality = anysee_i2c_func, -}; - -static int anysee_mt352_demod_init(struct dvb_frontend *fe) -{ - static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x28 }; - static u8 reset[] = { RESET, 0x80 }; - static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 }; - static u8 agc_cfg[] = { AGC_TARGET, 0x28, 0x20 }; - static u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 }; - static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; - - mt352_write(fe, clock_config, sizeof(clock_config)); - udelay(200); - mt352_write(fe, reset, sizeof(reset)); - mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); - - mt352_write(fe, agc_cfg, sizeof(agc_cfg)); - mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); - mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); - - return 0; -} - -/* Callbacks for DVB USB */ -static struct tda10023_config anysee_tda10023_config = { - .demod_address = (0x1a >> 1), - .invert = 0, - .xtal = 16000000, - .pll_m = 11, - .pll_p = 3, - .pll_n = 1, - .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C, - .deltaf = 0xfeeb, -}; - -static struct mt352_config anysee_mt352_config = { - .demod_address = (0x1e >> 1), - .demod_init = anysee_mt352_demod_init, -}; - -static struct zl10353_config anysee_zl10353_config = { - .demod_address = (0x1e >> 1), - .parallel_ts = 1, -}; - -static struct zl10353_config anysee_zl10353_tda18212_config2 = { - .demod_address = (0x1e >> 1), - .parallel_ts = 1, - .disable_i2c_gate_ctrl = 1, - .no_tuner = 1, - .if2 = 41500, -}; - -static struct zl10353_config anysee_zl10353_tda18212_config = { - .demod_address = (0x18 >> 1), - .parallel_ts = 1, - .disable_i2c_gate_ctrl = 1, - .no_tuner = 1, - .if2 = 41500, -}; - -static struct tda10023_config anysee_tda10023_tda18212_config = { - .demod_address = (0x1a >> 1), - .xtal = 16000000, - .pll_m = 12, - .pll_p = 3, - .pll_n = 1, - .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_B, - .deltaf = 0xba02, -}; - -static struct tda18212_config anysee_tda18212_config = { - .i2c_address = (0xc0 >> 1), - .if_dvbt_6 = 4150, - .if_dvbt_7 = 4150, - .if_dvbt_8 = 4150, - .if_dvbc = 5000, -}; - -static struct tda18212_config anysee_tda18212_config2 = { - .i2c_address = 0x60 /* (0xc0 >> 1) */, - .if_dvbt_6 = 3550, - .if_dvbt_7 = 3700, - .if_dvbt_8 = 4150, - .if_dvbt2_6 = 3250, - .if_dvbt2_7 = 4000, - .if_dvbt2_8 = 4000, - .if_dvbc = 5000, -}; - -static struct cx24116_config anysee_cx24116_config = { - .demod_address = (0xaa >> 1), - .mpg_clk_pos_pol = 0x00, - .i2c_wr_max = 48, -}; - -static struct stv0900_config anysee_stv0900_config = { - .demod_address = (0xd0 >> 1), - .demod_mode = 0, - .xtal = 8000000, - .clkmode = 3, - .diseqc_mode = 2, - .tun1_maddress = 0, - .tun1_adc = 1, /* 1 Vpp */ - .path1_mode = 3, -}; - -static struct stv6110_config anysee_stv6110_config = { - .i2c_address = (0xc0 >> 1), - .mclk = 16000000, - .clk_div = 1, -}; - -static struct isl6423_config anysee_isl6423_config = { - .current_max = SEC_CURRENT_800m, - .curlim = SEC_CURRENT_LIM_OFF, - .mod_extern = 1, - .addr = (0x10 >> 1), -}; - -static struct cxd2820r_config anysee_cxd2820r_config = { - .i2c_address = 0x6d, /* (0xda >> 1) */ - .ts_mode = 0x38, -}; - -/* - * New USB device strings: Mfr=1, Product=2, SerialNumber=0 - * Manufacturer: AMT.CO.KR - * - * E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=???????? - * PCB: ? - * parts: DNOS404ZH102A(MT352, DTT7579(?)) - * - * E30 VID=04b4 PID=861f HW=2 FW=2.1 "anysee-T(LP)" - * PCB: PCB 507T (rev1.61) - * parts: DNOS404ZH103A(ZL10353, DTT7579(?)) - * OEA=0a OEB=00 OEC=00 OED=ff OEE=00 - * IOA=45 IOB=ff IOC=00 IOD=ff IOE=00 - * - * E30 Plus VID=04b4 PID=861f HW=6 FW=1.0 "anysee" - * PCB: 507CD (rev1.1) - * parts: DNOS404ZH103A(ZL10353, DTT7579(?)), CST56I01 - * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe - * IOA=4f IOB=ff IOC=00 IOD=06 IOE=01 - * IOD[0] ZL10353 1=enabled - * IOA[7] TS 0=enabled - * tuner is not behind ZL10353 I2C-gate (no care if gate disabled or not) - * - * E30 C Plus VID=04b4 PID=861f HW=10 FW=1.0 "anysee-DC(LP)" - * PCB: 507DC (rev0.2) - * parts: TDA10023, DTOS403IH102B TM, CST56I01 - * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe - * IOA=4f IOB=ff IOC=00 IOD=26 IOE=01 - * IOD[0] TDA10023 1=enabled - * - * E30 S2 Plus VID=04b4 PID=861f HW=11 FW=0.1 "anysee-S2(LP)" - * PCB: 507SI (rev2.1) - * parts: BS2N10WCC01(CX24116, CX24118), ISL6423, TDA8024 - * OEA=80 OEB=00 OEC=ff OED=ff OEE=fe - * IOA=4d IOB=ff IOC=00 IOD=26 IOE=01 - * IOD[0] CX24116 1=enabled - * - * E30 C Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)" - * PCB: 507FA (rev0.4) - * parts: TDA10023, DTOS403IH102B TM, TDA8024 - * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff - * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0 - * IOD[5] TDA10023 1=enabled - * IOE[0] tuner 1=enabled - * - * E30 Combo Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)" - * PCB: 507FA (rev1.1) - * parts: ZL10353, TDA10023, DTOS403IH102B TM, TDA8024 - * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff - * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0 - * DVB-C: - * IOD[5] TDA10023 1=enabled - * IOE[0] tuner 1=enabled - * DVB-T: - * IOD[0] ZL10353 1=enabled - * IOE[0] tuner 0=enabled - * tuner is behind ZL10353 I2C-gate - * - * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)" - * PCB: 508TC (rev0.6) - * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212) - * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff - * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 - * IOA[7] TS 1=enabled - * IOE[4] TDA18212 1=enabled - * DVB-C: - * IOD[6] ZL10353 0=disabled - * IOD[5] TDA10023 1=enabled - * IOE[0] IF 1=enabled - * DVB-T: - * IOD[5] TDA10023 0=disabled - * IOD[6] ZL10353 1=enabled - * IOE[0] IF 0=enabled - * - * E7 S2 VID=1c73 PID=861f HW=19 FW=0.4 AMTCI=0.5 "anysee-E7S2(LP)" - * PCB: 508S2 (rev0.7) - * parts: DNBU10512IST(STV0903, STV6110), ISL6423 - * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff - * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4 - * IOA[7] TS 1=enabled - * IOE[5] STV0903 1=enabled - * - * E7 T2C VID=1c73 PID=861f HW=20 FW=0.1 AMTCI=0.5 "anysee-E7T2C(LP)" - * PCB: 508T2C (rev0.3) - * parts: DNOQ44QCH106A(CXD2820R, TDA18212), TDA8024 - * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff - * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 - * IOA[7] TS 1=enabled - * IOE[5] CXD2820R 1=enabled - * - * E7 PTC VID=1c73 PID=861f HW=21 FW=0.1 AMTCI=?? "anysee-E7PTC(LP)" - * PCB: 508PTC (rev0.5) - * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212) - * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff - * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 - * IOA[7] TS 1=enabled - * IOE[4] TDA18212 1=enabled - * DVB-C: - * IOD[6] ZL10353 0=disabled - * IOD[5] TDA10023 1=enabled - * IOE[0] IF 1=enabled - * DVB-T: - * IOD[5] TDA10023 0=disabled - * IOD[6] ZL10353 1=enabled - * IOE[0] IF 0=enabled - * - * E7 PS2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)" - * PCB: 508PS2 (rev0.4) - * parts: DNBU10512IST(STV0903, STV6110), ISL6423 - * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff - * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4 - * IOA[7] TS 1=enabled - * IOE[5] STV0903 1=enabled - */ - -static int anysee_read_config(struct dvb_usb_device *d) -{ - struct anysee_state *state = d_to_priv(d); - int ret; - u8 hw_info[3]; - - /* - * Check which hardware we have. - * We must do this call two times to get reliable values (hw/fw bug). - */ - ret = anysee_get_hw_info(d, hw_info); - if (ret) - goto error; - - ret = anysee_get_hw_info(d, hw_info); - if (ret) - goto error; - - /* Meaning of these info bytes are guessed. */ - info("firmware version:%d.%d hardware id:%d", - hw_info[1], hw_info[2], hw_info[0]); - - state->hw = hw_info[0]; -error: - return ret; -} - -/* external I2C gate used for DNOD44CDH086A(TDA18212) tuner module */ -static int anysee_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - /* enable / disable tuner access on IOE[4] */ - return anysee_wr_reg_mask(fe_to_d(fe), REG_IOE, (enable << 4), 0x10); -} - -static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff) -{ - struct anysee_state *state = fe_to_priv(fe); - struct dvb_usb_device *d = fe_to_d(fe); - int ret; - - deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); - - /* no frontend sleep control */ - if (onoff == 0) - return 0; - - switch (state->hw) { - case ANYSEE_HW_507FA: /* 15 */ - /* E30 Combo Plus */ - /* E30 C Plus */ - - if (fe->id == 0) { - /* disable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 0), 0x01); - if (ret) - goto error; - - /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); - if (ret) - goto error; - - /* enable DVB-C tuner on IOE[0] */ - ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 0), 0x01); - if (ret) - goto error; - } else { - /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); - if (ret) - goto error; - - /* enable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); - if (ret) - goto error; - - /* enable DVB-T tuner on IOE[0] */ - ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 0), 0x01); - if (ret) - goto error; - } - - break; - case ANYSEE_HW_508TC: /* 18 */ - case ANYSEE_HW_508PTC: /* 21 */ - /* E7 TC */ - /* E7 PTC */ - - if (fe->id == 0) { - /* disable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 6), 0x40); - if (ret) - goto error; - - /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); - if (ret) - goto error; - - /* enable IF route on IOE[0] */ - ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 0), 0x01); - if (ret) - goto error; - } else { - /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); - if (ret) - goto error; - - /* enable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 6), 0x40); - if (ret) - goto error; - - /* enable IF route on IOE[0] */ - ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 0), 0x01); - if (ret) - goto error; - } - - break; - default: - ret = 0; - } - -error: - return ret; -} - -static int anysee_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct anysee_state *state = adap_to_priv(adap); - struct dvb_usb_device *d = adap_to_d(adap); - int ret; - u8 tmp; - struct i2c_msg msg[2] = { - { - .addr = anysee_tda18212_config.i2c_address, - .flags = 0, - .len = 1, - .buf = "\x00", - }, { - .addr = anysee_tda18212_config.i2c_address, - .flags = I2C_M_RD, - .len = 1, - .buf = &tmp, - } - }; - - switch (state->hw) { - case ANYSEE_HW_507T: /* 2 */ - /* E30 */ - - /* attach demod */ - adap->fe[0] = dvb_attach(mt352_attach, &anysee_mt352_config, - &d->i2c_adap); - if (adap->fe[0]) - break; - - /* attach demod */ - adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, - &d->i2c_adap); - - break; - case ANYSEE_HW_507CD: /* 6 */ - /* E30 Plus */ - - /* enable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); - if (ret) - goto error; - - /* enable transport stream on IOA[7] */ - ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); - if (ret) - goto error; - - /* attach demod */ - adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, - &d->i2c_adap); - - break; - case ANYSEE_HW_507DC: /* 10 */ - /* E30 C Plus */ - - /* enable DVB-C demod on IOD[0] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); - if (ret) - goto error; - - /* attach demod */ - adap->fe[0] = dvb_attach(tda10023_attach, - &anysee_tda10023_config, &d->i2c_adap, 0x48); - - break; - case ANYSEE_HW_507SI: /* 11 */ - /* E30 S2 Plus */ - - /* enable DVB-S/S2 demod on IOD[0] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); - if (ret) - goto error; - - /* attach demod */ - adap->fe[0] = dvb_attach(cx24116_attach, &anysee_cx24116_config, - &d->i2c_adap); - - break; - case ANYSEE_HW_507FA: /* 15 */ - /* E30 Combo Plus */ - /* E30 C Plus */ - - /* enable tuner on IOE[4] */ - ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 4), 0x10); - if (ret) - goto error; - - /* probe TDA18212 */ - tmp = 0; - ret = i2c_transfer(&d->i2c_adap, msg, 2); - if (ret == 2 && tmp == 0xc7) - deb_info("%s: TDA18212 found\n", __func__); - else - tmp = 0; - - /* disable tuner on IOE[4] */ - ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 4), 0x10); - if (ret) - goto error; - - /* disable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 0), 0x01); - if (ret) - goto error; - - /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); - if (ret) - goto error; - - /* attach demod */ - if (tmp == 0xc7) { - /* TDA18212 config */ - adap->fe[0] = dvb_attach(tda10023_attach, - &anysee_tda10023_tda18212_config, - &d->i2c_adap, 0x48); - - /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ - if (adap->fe[0]) - adap->fe[0]->ops.i2c_gate_ctrl = - anysee_i2c_gate_ctrl; - } else { - /* PLL config */ - adap->fe[0] = dvb_attach(tda10023_attach, - &anysee_tda10023_config, - &d->i2c_adap, 0x48); - } - - /* break out if first frontend attaching fails */ - if (!adap->fe[0]) - break; - - /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); - if (ret) - goto error; - - /* enable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); - if (ret) - goto error; - - /* attach demod */ - if (tmp == 0xc7) { - /* TDA18212 config */ - adap->fe[1] = dvb_attach(zl10353_attach, - &anysee_zl10353_tda18212_config2, - &d->i2c_adap); - - /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ - if (adap->fe[1]) - adap->fe[1]->ops.i2c_gate_ctrl = - anysee_i2c_gate_ctrl; - } else { - /* PLL config */ - adap->fe[1] = dvb_attach(zl10353_attach, - &anysee_zl10353_config, - &d->i2c_adap); - } - - break; - case ANYSEE_HW_508TC: /* 18 */ - case ANYSEE_HW_508PTC: /* 21 */ - /* E7 TC */ - /* E7 PTC */ - - /* disable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 6), 0x40); - if (ret) - goto error; - - /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); - if (ret) - goto error; - - /* attach demod */ - adap->fe[0] = dvb_attach(tda10023_attach, - &anysee_tda10023_tda18212_config, - &d->i2c_adap, 0x48); - - /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ - if (adap->fe[0]) - adap->fe[0]->ops.i2c_gate_ctrl = anysee_i2c_gate_ctrl; - - /* break out if first frontend attaching fails */ - if (!adap->fe[0]) - break; - - /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); - if (ret) - goto error; - - /* enable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 6), 0x40); - if (ret) - goto error; - - /* attach demod */ - adap->fe[1] = dvb_attach(zl10353_attach, - &anysee_zl10353_tda18212_config, - &d->i2c_adap); - - /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ - if (adap->fe[1]) - adap->fe[1]->ops.i2c_gate_ctrl = anysee_i2c_gate_ctrl; - - state->has_ci = true; - - break; - case ANYSEE_HW_508S2: /* 19 */ - case ANYSEE_HW_508PS2: /* 22 */ - /* E7 S2 */ - /* E7 PS2 */ - - /* enable DVB-S/S2 demod on IOE[5] */ - ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 5), 0x20); - if (ret) - goto error; - - /* attach demod */ - adap->fe[0] = dvb_attach(stv0900_attach, - &anysee_stv0900_config, &d->i2c_adap, 0); - - state->has_ci = true; - - break; - case ANYSEE_HW_508T2C: /* 20 */ - /* E7 T2C */ - - /* enable DVB-T/T2/C demod on IOE[5] */ - ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 5), 0x20); - if (ret) - goto error; - - /* attach demod */ - adap->fe[0] = dvb_attach(cxd2820r_attach, - &anysee_cxd2820r_config, &d->i2c_adap); - - state->has_ci = true; - - break; - } - - if (!adap->fe[0]) { - /* we have no frontend :-( */ - ret = -ENODEV; - err("Unsupported Anysee version. " \ - "Please report the ."); - } -error: - return ret; -} - -static int anysee_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct anysee_state *state = adap_to_priv(adap); - struct dvb_usb_device *d = adap_to_d(adap); - struct dvb_frontend *fe; - int ret; - deb_info("%s: adap=%d\n", __func__, adap->id); - - switch (state->hw) { - case ANYSEE_HW_507T: /* 2 */ - /* E30 */ - - /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), NULL, - DVB_PLL_THOMSON_DTT7579); - - break; - case ANYSEE_HW_507CD: /* 6 */ - /* E30 Plus */ - - /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), - &d->i2c_adap, DVB_PLL_THOMSON_DTT7579); - - break; - case ANYSEE_HW_507DC: /* 10 */ - /* E30 C Plus */ - - /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), - &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); - - break; - case ANYSEE_HW_507SI: /* 11 */ - /* E30 S2 Plus */ - - /* attach LNB controller */ - fe = dvb_attach(isl6423_attach, adap->fe[0], &d->i2c_adap, - &anysee_isl6423_config); - - break; - case ANYSEE_HW_507FA: /* 15 */ - /* E30 Combo Plus */ - /* E30 C Plus */ - - /* Try first attach TDA18212 silicon tuner on IOE[4], if that - * fails attach old simple PLL. */ - - /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, - &anysee_tda18212_config); - - if (fe && adap->fe[1]) { - /* attach tuner for 2nd FE */ - fe = dvb_attach(tda18212_attach, adap->fe[1], - &d->i2c_adap, &anysee_tda18212_config); - break; - } else if (fe) { - break; - } - - /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), - &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); - - if (fe && adap->fe[1]) { - /* attach tuner for 2nd FE */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], - (0xc0 >> 1), &d->i2c_adap, - DVB_PLL_SAMSUNG_DTOS403IH102A); - } - - break; - case ANYSEE_HW_508TC: /* 18 */ - case ANYSEE_HW_508PTC: /* 21 */ - /* E7 TC */ - /* E7 PTC */ - - /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, - &anysee_tda18212_config); - - if (fe) { - /* attach tuner for 2nd FE */ - fe = dvb_attach(tda18212_attach, adap->fe[1], - &d->i2c_adap, &anysee_tda18212_config); - } - - break; - case ANYSEE_HW_508S2: /* 19 */ - case ANYSEE_HW_508PS2: /* 22 */ - /* E7 S2 */ - /* E7 PS2 */ - - /* attach tuner */ - fe = dvb_attach(stv6110_attach, adap->fe[0], - &anysee_stv6110_config, &d->i2c_adap); - - if (fe) { - /* attach LNB controller */ - fe = dvb_attach(isl6423_attach, adap->fe[0], - &d->i2c_adap, &anysee_isl6423_config); - } - - break; - - case ANYSEE_HW_508T2C: /* 20 */ - /* E7 T2C */ - - /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, - &anysee_tda18212_config2); - - break; - default: - fe = NULL; - } - - if (fe) - ret = 0; - else - ret = -ENODEV; - - return ret; -} - -static int anysee_rc_query(struct dvb_usb_device *d) -{ - u8 buf[] = {CMD_GET_IR_CODE}; - u8 ircode[2]; - int ret; - - /* Remote controller is basic NEC using address byte 0x08. - Anysee device RC query returns only two bytes, status and code, - address byte is dropped. Also it does not return any value for - NEC RCs having address byte other than 0x08. Due to that, we - cannot use that device as standard NEC receiver. - It could be possible make hack which reads whole code directly - from device memory... */ - - ret = anysee_ctrl_msg(d, buf, sizeof(buf), ircode, sizeof(ircode)); - if (ret) - return ret; - - if (ircode[0]) { - deb_rc("%s: key pressed %02x\n", __func__, ircode[1]); - rc_keydown(d->rc_dev, 0x08 << 8 | ircode[1], 0); - } - - return 0; -} - -static int anysee_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) -{ - rc->allowed_protos = RC_TYPE_NEC; - rc->query = anysee_rc_query; - rc->interval = 250; /* windows driver uses 500ms */ - - return 0; -} - -static int anysee_ci_read_attribute_mem(struct dvb_ca_en50221 *ci, int slot, - int addr) -{ - struct dvb_usb_device *d = ci->data; - int ret; - u8 buf[] = {CMD_CI, 0x02, 0x40 | addr >> 8, addr & 0xff, 0x00, 1}; - u8 val; - - ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1); - if (ret) - return ret; - - return val; -} - -static int anysee_ci_write_attribute_mem(struct dvb_ca_en50221 *ci, int slot, - int addr, u8 val) -{ - struct dvb_usb_device *d = ci->data; - int ret; - u8 buf[] = {CMD_CI, 0x03, 0x40 | addr >> 8, addr & 0xff, 0x00, 1, val}; - - ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); - if (ret) - return ret; - - return 0; -} - -static int anysee_ci_read_cam_control(struct dvb_ca_en50221 *ci, int slot, - u8 addr) -{ - struct dvb_usb_device *d = ci->data; - int ret; - u8 buf[] = {CMD_CI, 0x04, 0x40, addr, 0x00, 1}; - u8 val; - - ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1); - if (ret) - return ret; - - return val; -} - -static int anysee_ci_write_cam_control(struct dvb_ca_en50221 *ci, int slot, - u8 addr, u8 val) -{ - struct dvb_usb_device *d = ci->data; - int ret; - u8 buf[] = {CMD_CI, 0x05, 0x40, addr, 0x00, 1, val}; - - ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); - if (ret) - return ret; - - return 0; -} - -static int anysee_ci_slot_reset(struct dvb_ca_en50221 *ci, int slot) -{ - struct dvb_usb_device *d = ci->data; - int ret; - struct anysee_state *state = d_to_priv(d); - - state->ci_cam_ready = jiffies + msecs_to_jiffies(1000); - - ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); - if (ret) - return ret; - - msleep(300); - - ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); - if (ret) - return ret; - - return 0; -} - -static int anysee_ci_slot_shutdown(struct dvb_ca_en50221 *ci, int slot) -{ - struct dvb_usb_device *d = ci->data; - int ret; - - ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); - if (ret) - return ret; - - msleep(30); - - ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); - if (ret) - return ret; - - return 0; -} - -static int anysee_ci_slot_ts_enable(struct dvb_ca_en50221 *ci, int slot) -{ - struct dvb_usb_device *d = ci->data; - int ret; - - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 1), 0x02); - if (ret) - return ret; - - return 0; -} - -static int anysee_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot, - int open) -{ - struct dvb_usb_device *d = ci->data; - struct anysee_state *state = d_to_priv(d); - int ret; - u8 tmp; - - ret = anysee_rd_reg_mask(d, REG_IOC, &tmp, 0x40); - if (ret) - return ret; - - if (tmp == 0) { - ret = DVB_CA_EN50221_POLL_CAM_PRESENT; - if (time_after(jiffies, state->ci_cam_ready)) - ret |= DVB_CA_EN50221_POLL_CAM_READY; - } - - return ret; -} - -static int anysee_ci_init(struct dvb_usb_device *d) -{ - struct anysee_state *state = d_to_priv(d); - int ret; - - state->ci.owner = THIS_MODULE; - state->ci.read_attribute_mem = anysee_ci_read_attribute_mem; - state->ci.write_attribute_mem = anysee_ci_write_attribute_mem; - state->ci.read_cam_control = anysee_ci_read_cam_control; - state->ci.write_cam_control = anysee_ci_write_cam_control; - state->ci.slot_reset = anysee_ci_slot_reset; - state->ci.slot_shutdown = anysee_ci_slot_shutdown; - state->ci.slot_ts_enable = anysee_ci_slot_ts_enable; - state->ci.poll_slot_status = anysee_ci_poll_slot_status; - state->ci.data = d; - - ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); - if (ret) - return ret; - - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 2)|(0 << 1)|(0 << 0), 0x07); - if (ret) - return ret; - - ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 2)|(1 << 1)|(1 << 0), 0x07); - if (ret) - return ret; - - ret = dvb_ca_en50221_init(&d->adapter[0].dvb_adap, &state->ci, 0, 1); - if (ret) - return ret; - - return 0; -} - -static void anysee_ci_release(struct dvb_usb_device *d) -{ - struct anysee_state *state = d_to_priv(d); - - /* detach CI */ - if (state->has_ci) - dvb_ca_en50221_release(&state->ci); - - return; -} - -static int anysee_init(struct dvb_usb_device *d) -{ - struct anysee_state *state = d_to_priv(d); - int ret; - - /* There is one interface with two alternate settings. - Alternate setting 0 is for bulk transfer. - Alternate setting 1 is for isochronous transfer. - We use bulk transfer (alternate setting 0). */ - ret = usb_set_interface(d->udev, 0, 0); - if (ret) - return ret; - - /* LED light */ - ret = anysee_led_ctrl(d, 0x01, 0x03); - if (ret) - return ret; - - /* enable IR */ - ret = anysee_ir_ctrl(d, 1); - if (ret) - return ret; - - /* attach CI */ - if (state->has_ci) { - ret = anysee_ci_init(d); - if (ret) { - state->has_ci = false; - return ret; - } - } - - return 0; -} - -static void anysee_exit(struct dvb_usb_device *d) -{ - return anysee_ci_release(d); -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties anysee_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct anysee_state), - - .generic_bulk_ctrl_endpoint = 0x01, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .i2c_algo = &anysee_i2c_algo, - .read_config = anysee_read_config, - .frontend_attach = anysee_frontend_attach, - .tuner_attach = anysee_tuner_attach, - .init = anysee_init, - .get_rc_config = anysee_get_rc_config, - .frontend_ctrl = anysee_frontend_ctrl, - .streaming_ctrl = anysee_streaming_ctrl, - .exit = anysee_exit, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_BULK(0x82, 8, 16 * 512), - } - } -}; - -static const struct usb_device_id anysee_id_table[] = { - { DVB_USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE, - &anysee_props, "Anysee", RC_MAP_ANYSEE) }, - { DVB_USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE, - &anysee_props, "Anysee", RC_MAP_ANYSEE) }, - { } -}; -MODULE_DEVICE_TABLE(usb, anysee_id_table); - -static struct usb_driver anysee_usb_driver = { - .name = KBUILD_MODNAME, - .id_table = anysee_id_table, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(anysee_usb_driver); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/anysee.h b/drivers/media/dvb/dvb-usb/anysee.h deleted file mode 100644 index dc40dcf7c328..000000000000 --- a/drivers/media/dvb/dvb-usb/anysee.h +++ /dev/null @@ -1,356 +0,0 @@ -/* - * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver - * - * Copyright (C) 2007 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * TODO: - * - add smart card reader support for Conditional Access (CA) - * - * Card reader in Anysee is nothing more than ISO 7816 card reader. - * There is no hardware CAM in any Anysee device sold. - * In my understanding it should be implemented by making own module - * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This - * module registers serial interface that can be used to communicate - * with any ISO 7816 smart card. - * - * Any help according to implement serial smart card reader support - * is highly welcome! - */ - -#ifndef _DVB_USB_ANYSEE_H_ -#define _DVB_USB_ANYSEE_H_ - -#define DVB_USB_LOG_PREFIX "anysee" -#include "dvb_usb.h" -#include "dvb_ca_en50221.h" - -#ifdef CONFIG_DVB_USB_DEBUG -#define dprintk(var, level, args...) \ - do { if ((var & level)) printk(args); } while (0) -#define DVB_USB_DEBUG_STATUS -#else -#define dprintk(args...) -#define debug_dump(b, l, func) -#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" -#endif - -#define debug_dump(b, l, func) {\ - int loop_; \ - for (loop_ = 0; loop_ < l; loop_++) \ - func("%02x ", b[loop_]); \ - func("\n");\ -} - -#define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args) -#define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args) -#define deb_rc(args...) dprintk(dvb_usb_anysee_debug, 0x04, args) -#define deb_reg(args...) dprintk(dvb_usb_anysee_debug, 0x08, args) -#define deb_i2c(args...) dprintk(dvb_usb_anysee_debug, 0x10, args) -#define deb_fw(args...) dprintk(dvb_usb_anysee_debug, 0x20, args) - -#undef err -#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) -#undef info -#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) -#undef warn -#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) - -enum cmd { - CMD_I2C_READ = 0x33, - CMD_I2C_WRITE = 0x31, - CMD_REG_READ = 0xb0, - CMD_REG_WRITE = 0xb1, - CMD_STREAMING_CTRL = 0x12, - CMD_LED_AND_IR_CTRL = 0x16, - CMD_GET_IR_CODE = 0x41, - CMD_GET_HW_INFO = 0x19, - CMD_SMARTCARD = 0x34, - CMD_CI = 0x37, -}; - -struct anysee_state { - u8 hw; /* PCB ID */ - u8 seq; - u8 fe_id:1; /* frondend ID */ - u8 has_ci:1; - struct dvb_ca_en50221 ci; - unsigned long ci_cam_ready; /* jiffies */ -}; - -#define ANYSEE_HW_507T 2 /* E30 */ -#define ANYSEE_HW_507CD 6 /* E30 Plus */ -#define ANYSEE_HW_507DC 10 /* E30 C Plus */ -#define ANYSEE_HW_507SI 11 /* E30 S2 Plus */ -#define ANYSEE_HW_507FA 15 /* E30 Combo Plus / E30 C Plus */ -#define ANYSEE_HW_508TC 18 /* E7 TC */ -#define ANYSEE_HW_508S2 19 /* E7 S2 */ -#define ANYSEE_HW_508T2C 20 /* E7 T2C */ -#define ANYSEE_HW_508PTC 21 /* E7 PTC Plus */ -#define ANYSEE_HW_508PS2 22 /* E7 PS2 Plus */ - -#define REG_IOA 0x80 /* Port A (bit addressable) */ -#define REG_IOB 0x90 /* Port B (bit addressable) */ -#define REG_IOC 0xa0 /* Port C (bit addressable) */ -#define REG_IOD 0xb0 /* Port D (bit addressable) */ -#define REG_IOE 0xb1 /* Port E (NOT bit addressable) */ -#define REG_OEA 0xb2 /* Port A Output Enable */ -#define REG_OEB 0xb3 /* Port B Output Enable */ -#define REG_OEC 0xb4 /* Port C Output Enable */ -#define REG_OED 0xb5 /* Port D Output Enable */ -#define REG_OEE 0xb6 /* Port E Output Enable */ - -#endif - -/*************************************************************************** - * USB API description (reverse engineered) - *************************************************************************** - -Transaction flow: -================= -BULK[00001] >>> REQUEST PACKET 64 bytes -BULK[00081] <<< REPLY PACKET #1 64 bytes (PREVIOUS TRANSACTION REPLY) -BULK[00081] <<< REPLY PACKET #2 64 bytes (CURRENT TRANSACTION REPLY) - -General reply packet(s) are always used if not own reply defined. - -============================================================================ -| 00-63 | GENERAL REPLY PACKET #1 (PREVIOUS REPLY) -============================================================================ -| 00 | reply data (if any) from previous transaction -| | Just same reply packet as returned during previous transaction. -| | Needed only if reply is missed in previous transaction. -| | Just skip normally. ----------------------------------------------------------------------------- -| 01-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | GENERAL REPLY PACKET #2 (CURRENT REPLY) -============================================================================ -| 00 | reply data (if any) ----------------------------------------------------------------------------- -| 01-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | I2C WRITE REQUEST PACKET -============================================================================ -| 00 | 0x31 I2C write command ----------------------------------------------------------------------------- -| 01 | i2c address ----------------------------------------------------------------------------- -| 02 | data length -| | 0x02 (for typical I2C reg / val pair) ----------------------------------------------------------------------------- -| 03 | 0x01 ----------------------------------------------------------------------------- -| 04- | data ----------------------------------------------------------------------------- -| -59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | I2C READ REQUEST PACKET -============================================================================ -| 00 | 0x33 I2C read command ----------------------------------------------------------------------------- -| 01 | i2c address + 1 ----------------------------------------------------------------------------- -| 02 | register ----------------------------------------------------------------------------- -| 03 | 0x00 ----------------------------------------------------------------------------- -| 04 | 0x00 ----------------------------------------------------------------------------- -| 05 | data length ----------------------------------------------------------------------------- -| 06-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | USB CONTROLLER REGISTER WRITE REQUEST PACKET -============================================================================ -| 00 | 0xb1 register write command ----------------------------------------------------------------------------- -| 01-02 | register ----------------------------------------------------------------------------- -| 03 | 0x01 ----------------------------------------------------------------------------- -| 04 | value ----------------------------------------------------------------------------- -| 05-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | USB CONTROLLER REGISTER READ REQUEST PACKET -============================================================================ -| 00 | 0xb0 register read command ----------------------------------------------------------------------------- -| 01-02 | register ----------------------------------------------------------------------------- -| 03 | 0x01 ----------------------------------------------------------------------------- -| 04-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | LED CONTROL REQUEST PACKET -============================================================================ -| 00 | 0x16 LED and IR control command ----------------------------------------------------------------------------- -| 01 | 0x01 (LED) ----------------------------------------------------------------------------- -| 03 | 0x00 blink -| | 0x01 lights continuously ----------------------------------------------------------------------------- -| 04 | blink interval -| | 0x00 fastest (looks like LED lights continuously) -| | 0xff slowest ----------------------------------------------------------------------------- -| 05-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | IR CONTROL REQUEST PACKET -============================================================================ -| 00 | 0x16 LED and IR control command ----------------------------------------------------------------------------- -| 01 | 0x02 (IR) ----------------------------------------------------------------------------- -| 03 | 0x00 IR disabled -| | 0x01 IR enabled ----------------------------------------------------------------------------- -| 04-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | STREAMING CONTROL REQUEST PACKET -============================================================================ -| 00 | 0x12 streaming control command ----------------------------------------------------------------------------- -| 01 | 0x00 streaming disabled -| | 0x01 streaming enabled ----------------------------------------------------------------------------- -| 02 | 0x00 ----------------------------------------------------------------------------- -| 03-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | REMOTE CONTROL REQUEST PACKET -============================================================================ -| 00 | 0x41 remote control command ----------------------------------------------------------------------------- -| 01-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | REMOTE CONTROL REPLY PACKET -============================================================================ -| 00 | 0x00 code not received -| | 0x01 code received ----------------------------------------------------------------------------- -| 01 | remote control code ----------------------------------------------------------------------------- -| 02-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | GET HARDWARE INFO REQUEST PACKET -============================================================================ -| 00 | 0x19 get hardware info command ----------------------------------------------------------------------------- -| 01-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | GET HARDWARE INFO REPLY PACKET -============================================================================ -| 00 | hardware id ----------------------------------------------------------------------------- -| 01-02 | firmware version ----------------------------------------------------------------------------- -| 03-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | SMART CARD READER PACKET -============================================================================ -| 00 | 0x34 smart card reader command ----------------------------------------------------------------------------- -| xx | ----------------------------------------------------------------------------- -| xx-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -*/ diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c deleted file mode 100644 index 05f2a8628142..000000000000 --- a/drivers/media/dvb/dvb-usb/au6610.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0. - * - * Copyright (C) 2006 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "au6610.h" -#include "zl10353.h" -#include "qt1010.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - int ret; - u16 index; - u8 *usb_buf; - - /* - * allocate enough for all known requests, - * read returns 5 and write 6 bytes - */ - usb_buf = kmalloc(6, GFP_KERNEL); - if (!usb_buf) - return -ENOMEM; - - switch (wlen) { - case 1: - index = wbuf[0] << 8; - break; - case 2: - index = wbuf[0] << 8; - index += wbuf[1]; - break; - default: - pr_err("%s: wlen = %d, aborting\n", KBUILD_MODNAME, wlen); - ret = -EINVAL; - goto error; - } - - ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation, - USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index, - usb_buf, 6, AU6610_USB_TIMEOUT); - if (ret < 0) - goto error; - - switch (operation) { - case AU6610_REQ_I2C_READ: - case AU6610_REQ_USB_READ: - /* requested value is always 5th byte in buffer */ - rbuf[0] = usb_buf[4]; - } -error: - kfree(usb_buf); - return ret; -} - -static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - u8 request; - u8 wo = (rbuf == NULL || rlen == 0); /* write-only */ - - if (wo) { - request = AU6610_REQ_I2C_WRITE; - } else { /* rw */ - request = AU6610_REQ_I2C_READ; - } - - return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen); -} - - -/* I2C */ -static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i; - - if (num > 2) - return -EINVAL; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - /* write/read request */ - if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { - if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf, - msg[i].len, msg[i+1].buf, - msg[i+1].len) < 0) - break; - i++; - } else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf, - msg[i].len, NULL, 0) < 0) - break; - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - - -static u32 au6610_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm au6610_i2c_algo = { - .master_xfer = au6610_i2c_xfer, - .functionality = au6610_i2c_func, -}; - -/* Callbacks for DVB USB */ -static struct zl10353_config au6610_zl10353_config = { - .demod_address = 0x0f, - .no_tuner = 1, - .parallel_ts = 1, -}; - -static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap) -{ - adap->fe[0] = dvb_attach(zl10353_attach, &au6610_zl10353_config, - &adap_to_d(adap)->i2c_adap); - if (adap->fe[0] == NULL) - return -ENODEV; - - return 0; -} - -static struct qt1010_config au6610_qt1010_config = { - .i2c_address = 0x62 -}; - -static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap) -{ - return dvb_attach(qt1010_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &au6610_qt1010_config) == NULL ? -ENODEV : 0; -} - -static int au6610_init(struct dvb_usb_device *d) -{ - /* TODO: this functionality belongs likely to the streaming control */ - /* bInterfaceNumber 0, bAlternateSetting 5 */ - return usb_set_interface(d->udev, 0, 5); -} - -static struct dvb_usb_device_properties au6610_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - - .i2c_algo = &au6610_i2c_algo, - .frontend_attach = au6610_zl10353_frontend_attach, - .tuner_attach = au6610_qt1010_tuner_attach, - .init = au6610_init, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_ISOC(0x82, 5, 40, 942, 1), - }, - }, -}; - -static const struct usb_device_id au6610_id_table[] = { - { DVB_USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110, - &au6610_props, "Sigmatek DVB-110", NULL) }, - { } -}; -MODULE_DEVICE_TABLE(usb, au6610_id_table); - -static struct usb_driver au6610_driver = { - .name = KBUILD_MODNAME, - .id_table = au6610_id_table, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(au6610_driver); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0"); -MODULE_VERSION("0.1"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/au6610.h b/drivers/media/dvb/dvb-usb/au6610.h deleted file mode 100644 index ea337bfc00b1..000000000000 --- a/drivers/media/dvb/dvb-usb/au6610.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0. - * - * Copyright (C) 2006 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef AU6610_H -#define AU6610_H -#include "dvb_usb.h" - -#define AU6610_REQ_I2C_WRITE 0x14 -#define AU6610_REQ_I2C_READ 0x13 -#define AU6610_REQ_USB_WRITE 0x16 -#define AU6610_REQ_USB_READ 0x15 - -#define AU6610_USB_TIMEOUT 1000 - -#endif diff --git a/drivers/media/dvb/dvb-usb/ce6230.c b/drivers/media/dvb/dvb-usb/ce6230.c deleted file mode 100644 index 84ff4a96ca4e..000000000000 --- a/drivers/media/dvb/dvb-usb/ce6230.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Intel CE6230 DVB USB driver - * - * Copyright (C) 2009 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "ce6230.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) -{ - int ret; - unsigned int pipe; - u8 request; - u8 requesttype; - u16 value; - u16 index; - u8 *buf; - - request = req->cmd; - value = req->value; - index = req->index; - - switch (req->cmd) { - case I2C_READ: - case DEMOD_READ: - case REG_READ: - requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); - break; - case I2C_WRITE: - case DEMOD_WRITE: - case REG_WRITE: - requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); - break; - default: - pr_debug("%s: unknown command=%02x\n", __func__, req->cmd); - ret = -EINVAL; - goto error; - } - - buf = kmalloc(req->data_len, GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - goto error; - } - - if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) { - /* write */ - memcpy(buf, req->data, req->data_len); - pipe = usb_sndctrlpipe(d->udev, 0); - } else { - /* read */ - pipe = usb_rcvctrlpipe(d->udev, 0); - } - - msleep(1); /* avoid I2C errors */ - - ret = usb_control_msg(d->udev, pipe, request, requesttype, value, index, - buf, req->data_len, CE6230_USB_TIMEOUT); - - ce6230_debug_dump(request, requesttype, value, index, buf, - req->data_len); - - if (ret < 0) - pr_err("%s: usb_control_msg() failed=%d\n", KBUILD_MODNAME, - ret); - else - ret = 0; - - /* read request, copy returned data to return buf */ - if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) - memcpy(req->data, buf, req->data_len); - - kfree(buf); -error: - return ret; -} - -/* I2C */ -static struct zl10353_config ce6230_zl10353_config; - -static int ce6230_i2c_master_xfer(struct i2c_adapter *adap, - struct i2c_msg msg[], int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int ret = 0, i = 0; - struct usb_req req; - - if (num > 2) - return -EOPNOTSUPP; - - memset(&req, 0, sizeof(req)); - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - while (i < num) { - if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { - if (msg[i].addr == - ce6230_zl10353_config.demod_address) { - req.cmd = DEMOD_READ; - req.value = msg[i].addr >> 1; - req.index = msg[i].buf[0]; - req.data_len = msg[i+1].len; - req.data = &msg[i+1].buf[0]; - ret = ce6230_ctrl_msg(d, &req); - } else { - pr_err("%s: I2C read not implemented\n", - KBUILD_MODNAME); - ret = -EOPNOTSUPP; - } - i += 2; - } else { - if (msg[i].addr == - ce6230_zl10353_config.demod_address) { - req.cmd = DEMOD_WRITE; - req.value = msg[i].addr >> 1; - req.index = msg[i].buf[0]; - req.data_len = msg[i].len-1; - req.data = &msg[i].buf[1]; - ret = ce6230_ctrl_msg(d, &req); - } else { - req.cmd = I2C_WRITE; - req.value = 0x2000 + (msg[i].addr >> 1); - req.index = 0x0000; - req.data_len = msg[i].len; - req.data = &msg[i].buf[0]; - ret = ce6230_ctrl_msg(d, &req); - } - i += 1; - } - if (ret) - break; - } - - mutex_unlock(&d->i2c_mutex); - return ret ? ret : i; -} - -static u32 ce6230_i2c_functionality(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm ce6230_i2c_algorithm = { - .master_xfer = ce6230_i2c_master_xfer, - .functionality = ce6230_i2c_functionality, -}; - -/* Callbacks for DVB USB */ -static struct zl10353_config ce6230_zl10353_config = { - .demod_address = 0x1e, - .adc_clock = 450000, - .if2 = 45700, - .no_tuner = 1, - .parallel_ts = 1, - .clock_ctl_1 = 0x34, - .pll_0 = 0x0e, -}; - -static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap) -{ - pr_debug("%s:\n", __func__); - - adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config, - &adap_to_d(adap)->i2c_adap); - if (adap->fe[0] == NULL) - return -ENODEV; - - return 0; -} - -static struct mxl5005s_config ce6230_mxl5003s_config = { - .i2c_address = 0xc6, - .if_freq = IF_FREQ_4570000HZ, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_DEFAULT, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .AgcMasterByte = 0x00, -}; - -static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) -{ - int ret; - - pr_debug("%s:\n", __func__); - - ret = dvb_attach(mxl5005s_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0; - return ret; -} - -static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - int ret; - - pr_debug("%s: onoff=%d\n", __func__, onoff); - - /* InterfaceNumber 1 / AlternateSetting 0 idle - InterfaceNumber 1 / AlternateSetting 1 streaming */ - ret = usb_set_interface(d->udev, 1, onoff); - if (ret) - pr_err("%s: usb_set_interface() failed=%d\n", KBUILD_MODNAME, - ret); - - return ret; -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties ce6230_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .bInterfaceNumber = 1, - - .i2c_algo = &ce6230_i2c_algorithm, - .power_ctrl = ce6230_power_ctrl, - .frontend_attach = ce6230_zl10353_frontend_attach, - .tuner_attach = ce6230_mxl5003s_tuner_attach, - - .num_adapters = 1, - .adapter = { - { - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = (16 * 512), - } - } - }, - } - }, -}; - -static const struct usb_device_id ce6230_id_table[] = { - { DVB_USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500, - &ce6230_props, "Intel CE9500 reference design", NULL) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310, - &ce6230_props, "AVerMedia A310 USB 2.0 DVB-T tuner", NULL) }, - { } -}; -MODULE_DEVICE_TABLE(usb, ce6230_id_table); - -static struct usb_driver ce6230_usb_driver = { - .name = KBUILD_MODNAME, - .id_table = ce6230_id_table, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(ce6230_usb_driver); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Intel CE6230 driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/ce6230.h b/drivers/media/dvb/dvb-usb/ce6230.h deleted file mode 100644 index 42d754494a3a..000000000000 --- a/drivers/media/dvb/dvb-usb/ce6230.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Intel CE6230 DVB USB driver - * - * Copyright (C) 2009 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef CE6230_H -#define CE6230_H - -#include "dvb_usb.h" -#include "zl10353.h" -#include "mxl5005s.h" - -#define ce6230_debug_dump(r, t, v, i, b, l) { \ - char *direction; \ - if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ - direction = ">>>"; \ - else \ - direction = "<<<"; \ - pr_debug("%s: %02x %02x %02x %02x %02x %02x %02x %02x %s [%d bytes]\n", \ - __func__, t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, \ - l & 0xff, l >> 8, direction, l); \ -} - -#define CE6230_USB_TIMEOUT 1000 - -struct usb_req { - u8 cmd; /* [1] */ - u16 value; /* [2|3] */ - u16 index; /* [4|5] */ - u16 data_len; /* [6|7] */ - u8 *data; -}; - -enum ce6230_cmd { - CONFIG_READ = 0xd0, /* rd 0 (unclear) */ - UNKNOWN_WRITE = 0xc7, /* wr 7 (unclear) */ - I2C_READ = 0xd9, /* rd 9 (unclear) */ - I2C_WRITE = 0xca, /* wr a */ - DEMOD_READ = 0xdb, /* rd b */ - DEMOD_WRITE = 0xcc, /* wr c */ - REG_READ = 0xde, /* rd e */ - REG_WRITE = 0xcf, /* wr f */ -}; - -#endif diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h deleted file mode 100644 index 773817b5fe06..000000000000 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ /dev/null @@ -1,392 +0,0 @@ -/* - * DVB USB framework - * - * Copyright (C) 2004-6 Patrick Boettcher - * Copyright (C) 2012 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef DVB_USB_H -#define DVB_USB_H - -#include -#include -#include - -#include "dvb_frontend.h" -#include "dvb_demux.h" -#include "dvb_net.h" -#include "dmxdev.h" -#include "dvb-usb-ids.h" - -/* - * device file: /dev/dvb/adapter[0-1]/frontend[0-2] - * - * |-- device - * | |-- adapter0 - * | | |-- frontend0 - * | | |-- frontend1 - * | | `-- frontend2 - * | `-- adapter1 - * | |-- frontend0 - * | |-- frontend1 - * | `-- frontend2 - * - * - * Commonly used variable names: - * d = pointer to device (struct dvb_usb_device *) - * adap = pointer to adapter (struct dvb_usb_adapter *) - * fe = pointer to frontend (struct dvb_frontend *) - * - * Use macros defined in that file to resolve needed pointers. - */ - -/* helper macros for every DVB USB driver use */ -#define adap_to_d(adap) (container_of(adap, struct dvb_usb_device, \ - adapter[adap->id])) -#define adap_to_priv(adap) (adap_to_d(adap)->priv) -#define fe_to_adap(fe) ((struct dvb_usb_adapter *) ((fe)->dvb->priv)) -#define fe_to_d(fe) (adap_to_d(fe_to_adap(fe))) -#define fe_to_priv(fe) (fe_to_d(fe)->priv) -#define d_to_priv(d) (d->priv) - -#define DVB_USB_STREAM_BULK(endpoint_, count_, size_) { \ - .type = USB_BULK, \ - .count = count_, \ - .endpoint = endpoint_, \ - .u = { \ - .bulk = { \ - .buffersize = size_, \ - } \ - } \ -} - -#define DVB_USB_STREAM_ISOC(endpoint_, count_, frames_, size_, interval_) { \ - .type = USB_ISOC, \ - .count = count_, \ - .endpoint = endpoint_, \ - .u = { \ - .isoc = { \ - .framesperurb = frames_, \ - .framesize = size_,\ - .interval = interval_, \ - } \ - } \ -} - -#define DVB_USB_DEVICE(vend, prod, props_, name_, rc) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ - .idVendor = (vend), \ - .idProduct = (prod), \ - .driver_info = (kernel_ulong_t) &((const struct dvb_usb_driver_info) { \ - .props = (props_), \ - .name = (name_), \ - .rc_map = (rc), \ - }) - -struct dvb_usb_device; -struct dvb_usb_adapter; - -/** - * structure for carrying all needed data from the device driver to the general - * dvb usb routines - * @name: device name - * @rc_map: name of rc codes table - * @props: structure containing all device properties - */ -struct dvb_usb_driver_info { - const char *name; - const char *rc_map; - const struct dvb_usb_device_properties *props; -}; - -/** - * structure for remote controller configuration - * @map_name: name of rc codes table - * @allowed_protos: protocol(s) supported by the driver - * @change_protocol: callback to change protocol - * @query: called to query an event from the device - * @interval: time in ms between two queries - * @driver_type: used to point if a device supports raw mode - * @bulk_mode: device supports bulk mode for rc (disable polling mode) - */ -struct dvb_usb_rc { - const char *map_name; - u64 allowed_protos; - int (*change_protocol)(struct rc_dev *dev, u64 rc_type); - int (*query) (struct dvb_usb_device *d); - unsigned int interval; - const enum rc_driver_type driver_type; - bool bulk_mode; -}; - -/** - * usb streaming configration for adapter - * @type: urb type - * @count: count of used urbs - * @endpoint: stream usb endpoint number - */ -struct usb_data_stream_properties { -#define USB_BULK 1 -#define USB_ISOC 2 - u8 type; - u8 count; - u8 endpoint; - - union { - struct { - unsigned int buffersize; /* per URB */ - } bulk; - struct { - int framesperurb; - int framesize; - int interval; - } isoc; - } u; -}; - -/** - * properties of dvb usb device adapter - * @caps: adapter capabilities - * @pid_filter_count: pid count of adapter pid-filter - * @pid_filter_ctrl: called to enable/disable pid-filter - * @pid_filter: called to set/unset pid for filtering - * @stream: adapter usb stream configuration - */ -#define MAX_NO_OF_FE_PER_ADAP 3 -struct dvb_usb_adapter_properties { -#define DVB_USB_ADAP_HAS_PID_FILTER 0x01 -#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 -#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 - u8 caps; - - u8 pid_filter_count; - int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); - int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); - - struct usb_data_stream_properties stream; -}; - -/** - * struct dvb_usb_device_properties - properties of a dvb-usb-device - * @driver_name: name of the owning driver module - * @owner: owner of the dvb_adapter - * @adapter_nr: values from the DVB_DEFINE_MOD_OPT_ADAPTER_NR() macro - * @bInterfaceNumber: usb interface number driver binds - * @size_of_priv: bytes allocated for the driver private data - * @generic_bulk_ctrl_endpoint: bulk control endpoint number for sent - * @generic_bulk_ctrl_endpoint_response: bulk control endpoint number for - * receive - * @generic_bulk_ctrl_delay: delay between bulk control sent and receive message - * @identify_state: called to determine the firmware state (cold or warm) and - * return possible firmware file name to be loaded - * @firmware: name of the firmware file to be loaded - * @download_firmware: called to download the firmware - * @i2c_algo: i2c_algorithm if the device has i2c-adapter - * @num_adapters: dvb usb device adapter count - * @get_adapter_count: called to resolve adapter count - * @adapter: array of all adapter properties of device - * @power_ctrl: called to enable/disable power of the device - * @read_config: called to resolve device configuration - * @read_mac_address: called to resolve adapter mac-address - * @frontend_attach: called to attach the possible frontends - * @tuner_attach: called to attach the possible tuners - * @frontend_ctrl: called to power on/off active frontend - * @streaming_ctrl: called to start/stop the usb streaming of adapter - * @fe_ioctl_override: frontend ioctl override. avoid using that is possible - * @init: called after adapters are created in order to finalize device - * configuration - * @exit: called when driver is unloaded - * @get_rc_config: called to resolve used remote controller configuration - * @get_stream_config: called to resolve input and output stream configuration - * of the adapter just before streaming is started. input stream is transport - * stream from the demodulator and output stream is usb stream to host. - */ -#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 -struct dvb_usb_device_properties { - const char *driver_name; - struct module *owner; - short *adapter_nr; - - u8 bInterfaceNumber; - unsigned int size_of_priv; - u8 generic_bulk_ctrl_endpoint; - u8 generic_bulk_ctrl_endpoint_response; - unsigned int generic_bulk_ctrl_delay; - -#define WARM 0 -#define COLD 1 - int (*identify_state) (struct dvb_usb_device *, const char **); - const char *firmware; -#define RECONNECTS_USB 1 - int (*download_firmware) (struct dvb_usb_device *, - const struct firmware *); - - struct i2c_algorithm *i2c_algo; - - unsigned int num_adapters; - int (*get_adapter_count) (struct dvb_usb_device *); - struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; - int (*power_ctrl) (struct dvb_usb_device *, int); - int (*read_config) (struct dvb_usb_device *d); - int (*read_mac_address) (struct dvb_usb_adapter *, u8 []); - int (*frontend_attach) (struct dvb_usb_adapter *); - int (*tuner_attach) (struct dvb_usb_adapter *); - int (*frontend_ctrl) (struct dvb_frontend *, int); - int (*streaming_ctrl) (struct dvb_frontend *, int); - int (*fe_ioctl_override) (struct dvb_frontend *, - unsigned int, void *, unsigned int); - int (*init) (struct dvb_usb_device *); - void (*exit) (struct dvb_usb_device *); - int (*get_rc_config) (struct dvb_usb_device *, struct dvb_usb_rc *); -#define DVB_USB_FE_TS_TYPE_188 0 -#define DVB_USB_FE_TS_TYPE_204 1 -#define DVB_USB_FE_TS_TYPE_RAW 2 - int (*get_stream_config) (struct dvb_frontend *, u8 *, - struct usb_data_stream_properties *); -}; - -/** - * generic object of an usb stream - * @buf_num: number of buffer allocated - * @buf_size: size of each buffer in buf_list - * @buf_list: array containing all allocate buffers for streaming - * @dma_addr: list of dma_addr_t for each buffer in buf_list - * - * @urbs_initialized: number of URBs initialized - * @urbs_submitted: number of URBs submitted - */ -#define MAX_NO_URBS_FOR_DATA_STREAM 10 -struct usb_data_stream { - struct usb_device *udev; - struct usb_data_stream_properties props; - -#define USB_STATE_INIT 0x00 -#define USB_STATE_URB_BUF 0x01 - u8 state; - - void (*complete) (struct usb_data_stream *, u8 *, size_t); - - struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM]; - int buf_num; - unsigned long buf_size; - u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM]; - dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM]; - - int urbs_initialized; - int urbs_submitted; - - void *user_priv; -}; - -/** - * dvb adapter object on dvb usb device - * @props: pointer to adapter properties - * @stream: adapter the usb data stream - * @id: index of this adapter (starting with 0) - * @ts_type: transport stream, input stream, type - * @pid_filtering: is hardware pid_filtering used or not - * @feed_count: current feed count - * @max_feed_count: maimum feed count device can handle - * @dvb_adap: adapter dvb_adapter - * @dmxdev: adapter dmxdev - * @demux: adapter software demuxer - * @dvb_net: adapter dvb_net interfaces - * @sync_mutex: mutex used to sync control and streaming of the adapter - * @fe: adapter frontends - * @fe_init: rerouted frontend-init function - * @fe_sleep: rerouted frontend-sleep function - */ -struct dvb_usb_adapter { - const struct dvb_usb_adapter_properties *props; - struct usb_data_stream stream; - u8 id; - u8 ts_type; - bool pid_filtering; - u8 feed_count; - u8 max_feed_count; - s8 active_fe; - - /* dvb */ - struct dvb_adapter dvb_adap; - struct dmxdev dmxdev; - struct dvb_demux demux; - struct dvb_net dvb_net; - struct mutex sync_mutex; - - struct dvb_frontend *fe[MAX_NO_OF_FE_PER_ADAP]; - int (*fe_init[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); - int (*fe_sleep[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); -}; - -/** - * dvb usb device object - * @props: device properties - * @name: device name - * @rc_map: name of rc codes table - * @udev: pointer to the device's struct usb_device - * @intf: pointer to the device's usb interface - * @rc: remote controller configuration - * @probe_work: work to defer .probe() - * @powered: indicated whether the device is power or not - * @usb_mutex: mutex for usb control messages - * @i2c_mutex: mutex for i2c-transfers - * @i2c_adap: device's i2c-adapter - * @rc_dev: rc device for the remote control - * @rc_query_work: work for polling remote - * @priv: private data of the actual driver (allocate by dvb usb, size defined - * in size_of_priv of dvb_usb_properties). - */ -struct dvb_usb_device { - const struct dvb_usb_device_properties *props; - const char *name; - const char *rc_map; - - struct usb_device *udev; - struct usb_interface *intf; - struct dvb_usb_rc rc; - struct work_struct probe_work; - pid_t work_pid; - int powered; - - /* locking */ - struct mutex usb_mutex; - - /* i2c */ - struct mutex i2c_mutex; - struct i2c_adapter i2c_adap; - - struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; - - /* remote control */ - struct rc_dev *rc_dev; - char rc_phys[64]; - struct delayed_work rc_query_work; - - void *priv; -}; - -extern int dvb_usbv2_probe(struct usb_interface *, - const struct usb_device_id *); -extern void dvb_usbv2_disconnect(struct usb_interface *); -extern int dvb_usbv2_suspend(struct usb_interface *, pm_message_t); -extern int dvb_usbv2_resume(struct usb_interface *); - -/* the generic read/write method for device control */ -extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16); -extern int dvb_usbv2_generic_write(struct dvb_usb_device *, u8 *, u16); - -#endif diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb/dvb_usb_common.h deleted file mode 100644 index 45f07090d431..000000000000 --- a/drivers/media/dvb/dvb-usb/dvb_usb_common.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * DVB USB framework - * - * Copyright (C) 2004-6 Patrick Boettcher - * Copyright (C) 2012 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef DVB_USB_COMMON_H -#define DVB_USB_COMMON_H - -#include "dvb_usb.h" - -/* commonly used methods */ -extern int usb_urb_initv2(struct usb_data_stream *stream, - const struct usb_data_stream_properties *props); -extern int usb_urb_exitv2(struct usb_data_stream *stream); -extern int usb_urb_submitv2(struct usb_data_stream *stream, - struct usb_data_stream_properties *props); -extern int usb_urb_killv2(struct usb_data_stream *stream); - -#endif diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_core.c b/drivers/media/dvb/dvb-usb/dvb_usb_core.c deleted file mode 100644 index 3224621e1f32..000000000000 --- a/drivers/media/dvb/dvb-usb/dvb_usb_core.c +++ /dev/null @@ -1,999 +0,0 @@ -/* - * DVB USB framework - * - * Copyright (C) 2004-6 Patrick Boettcher - * Copyright (C) 2012 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "dvb_usb_common.h" - -int dvb_usbv2_disable_rc_polling; -module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644); -MODULE_PARM_DESC(disable_rc_polling, - "disable remote control polling (default: 0)"); -static int dvb_usb_force_pid_filter_usage; -module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, - int, 0444); -MODULE_PARM_DESC(force_pid_filter_usage, "force all DVB USB devices to use a " \ - "PID filter, if any (default: 0)"); - -static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *name) -{ - int ret; - const struct firmware *fw; - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - if (!d->props->download_firmware) { - ret = -EINVAL; - goto err; - } - - ret = request_firmware(&fw, name, &d->udev->dev); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: Did not find the firmware file "\ - "'%s'. Please see linux/Documentation/dvb/ " \ - "for more details on firmware-problems. " \ - "Status %d\n", KBUILD_MODNAME, name, ret); - goto err; - } - - dev_info(&d->udev->dev, "%s: downloading firmware from file '%s'\n", - KBUILD_MODNAME, name); - - ret = d->props->download_firmware(d, fw); - release_firmware(fw); - if (ret < 0) - goto err; - - return ret; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usbv2_i2c_init(struct dvb_usb_device *d) -{ - int ret; - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - if (!d->props->i2c_algo) - return 0; - - strlcpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name)); - d->i2c_adap.algo = d->props->i2c_algo; - d->i2c_adap.dev.parent = &d->udev->dev; - i2c_set_adapdata(&d->i2c_adap, d); - - ret = i2c_add_adapter(&d->i2c_adap); - if (ret < 0) { - d->i2c_adap.algo = NULL; - dev_err(&d->udev->dev, "%s: i2c_add_adapter() failed=%d\n", - KBUILD_MODNAME, ret); - goto err; - } - - return 0; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usbv2_i2c_exit(struct dvb_usb_device *d) -{ - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - if (d->i2c_adap.algo) - i2c_del_adapter(&d->i2c_adap); - - return 0; -} - -static void dvb_usb_read_remote_control(struct work_struct *work) -{ - struct dvb_usb_device *d = container_of(work, - struct dvb_usb_device, rc_query_work.work); - int ret; - - /* - * When the parameter has been set to 1 via sysfs while the - * driver was running, or when bulk mode is enabled after IR init. - */ - if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode) - return; - - ret = d->rc.query(d); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: rc.query() failed=%d\n", - KBUILD_MODNAME, ret); - return; /* stop polling */ - } - - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(d->rc.interval)); -} - -static int dvb_usbv2_remote_init(struct dvb_usb_device *d) -{ - int ret; - struct rc_dev *dev; - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config) - return 0; - - d->rc.map_name = d->rc_map; - ret = d->props->get_rc_config(d, &d->rc); - if (ret < 0) - goto err; - - /* disable rc when there is no keymap defined */ - if (!d->rc.map_name) - return 0; - - dev = rc_allocate_device(); - if (!dev) { - ret = -ENOMEM; - goto err; - } - - dev->dev.parent = &d->udev->dev; - dev->input_name = d->name; - usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); - strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); - dev->input_phys = d->rc_phys; - usb_to_input_id(d->udev, &dev->input_id); - /* TODO: likely RC-core should took const char * */ - dev->driver_name = (char *) d->props->driver_name; - dev->map_name = d->rc.map_name; - dev->driver_type = d->rc.driver_type; - dev->allowed_protos = d->rc.allowed_protos; - dev->change_protocol = d->rc.change_protocol; - dev->priv = d; - - ret = rc_register_device(dev); - if (ret < 0) { - rc_free_device(dev); - goto err; - } - - d->rc_dev = dev; - - /* start polling if needed */ - if (d->rc.query && !d->rc.bulk_mode) { - /* initialize a work queue for handling polling */ - INIT_DELAYED_WORK(&d->rc_query_work, - dvb_usb_read_remote_control); - dev_info(&d->udev->dev, "%s: schedule remote query interval " \ - "to %d msecs\n", KBUILD_MODNAME, - d->rc.interval); - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(d->rc.interval)); - } - - return 0; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usbv2_remote_exit(struct dvb_usb_device *d) -{ - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - if (d->rc_dev) { - cancel_delayed_work_sync(&d->rc_query_work); - rc_unregister_device(d->rc_dev); - d->rc_dev = NULL; - } - - return 0; -} - -static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buf, - size_t len) -{ - struct dvb_usb_adapter *adap = stream->user_priv; - dvb_dmx_swfilter(&adap->demux, buf, len); -} - -static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buf, - size_t len) -{ - struct dvb_usb_adapter *adap = stream->user_priv; - dvb_dmx_swfilter_204(&adap->demux, buf, len); -} - -static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, u8 *buf, - size_t len) -{ - struct dvb_usb_adapter *adap = stream->user_priv; - dvb_dmx_swfilter_raw(&adap->demux, buf, len); -} - -int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) -{ - dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, - adap->id); - - adap->stream.udev = adap_to_d(adap)->udev; - adap->stream.user_priv = adap; - adap->stream.complete = dvb_usb_data_complete; - - return usb_urb_initv2(&adap->stream, &adap->props->stream); -} - -int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap) -{ - dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, - adap->id); - - return usb_urb_exitv2(&adap->stream); -} - -static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, - int count) -{ - struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; - struct dvb_usb_device *d = adap_to_d(adap); - int ret; - dev_dbg(&d->udev->dev, "%s: adap=%d active_fe=%d feed_type=%d " \ - "setting pid [%s]: %04x (%04d) at index %d '%s'\n", - __func__, adap->id, adap->active_fe, dvbdmxfeed->type, - adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, - dvbdmxfeed->pid, dvbdmxfeed->index, - (count == 1) ? "on" : "off"); - - if (adap->active_fe == -1) - return -EINVAL; - - adap->feed_count += count; - - /* stop feeding if it is last pid */ - if (adap->feed_count == 0) { - dev_dbg(&d->udev->dev, "%s: stop feeding\n", __func__); - usb_urb_killv2(&adap->stream); - - if (d->props->streaming_ctrl) { - ret = d->props->streaming_ctrl( - adap->fe[adap->active_fe], 0); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: streaming_ctrl() " \ - "failed=%d\n", KBUILD_MODNAME, - ret); - goto err_mutex_unlock; - } - } - mutex_unlock(&adap->sync_mutex); - } - - /* activate the pid on the device pid filter */ - if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->pid_filtering && - adap->props->pid_filter) - ret = adap->props->pid_filter(adap, dvbdmxfeed->index, - dvbdmxfeed->pid, (count == 1) ? 1 : 0); - if (ret < 0) - dev_err(&d->udev->dev, "%s: pid_filter() " \ - "failed=%d\n", KBUILD_MODNAME, - ret); - - /* start feeding if it is first pid */ - if (adap->feed_count == 1 && count == 1) { - struct usb_data_stream_properties stream_props; - mutex_lock(&adap->sync_mutex); - dev_dbg(&d->udev->dev, "%s: start feeding\n", __func__); - - /* resolve input and output streaming paramters */ - if (d->props->get_stream_config) { - memcpy(&stream_props, &adap->props->stream, - sizeof(struct usb_data_stream_properties)); - ret = d->props->get_stream_config( - adap->fe[adap->active_fe], - &adap->ts_type, &stream_props); - if (ret < 0) - goto err_mutex_unlock; - } else { - stream_props = adap->props->stream; - } - - switch (adap->ts_type) { - case DVB_USB_FE_TS_TYPE_204: - adap->stream.complete = dvb_usb_data_complete_204; - break; - case DVB_USB_FE_TS_TYPE_RAW: - adap->stream.complete = dvb_usb_data_complete_raw; - break; - case DVB_USB_FE_TS_TYPE_188: - default: - adap->stream.complete = dvb_usb_data_complete; - break; - } - - usb_urb_submitv2(&adap->stream, &stream_props); - - if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->props->caps & - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && - adap->props->pid_filter_ctrl) { - ret = adap->props->pid_filter_ctrl(adap, - adap->pid_filtering); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: " \ - "pid_filter_ctrl() failed=%d\n", - KBUILD_MODNAME, ret); - goto err_mutex_unlock; - } - } - - if (d->props->streaming_ctrl) { - ret = d->props->streaming_ctrl( - adap->fe[adap->active_fe], 1); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: streaming_ctrl() " \ - "failed=%d\n", KBUILD_MODNAME, - ret); - goto err_mutex_unlock; - } - } - } - - return 0; -err_mutex_unlock: - mutex_unlock(&adap->sync_mutex); - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - return dvb_usb_ctrl_feed(dvbdmxfeed, 1); -} - -static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - return dvb_usb_ctrl_feed(dvbdmxfeed, -1); -} - -int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) -{ - int ret; - struct dvb_usb_device *d = adap_to_d(adap); - dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id); - - ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner, - &d->udev->dev, d->props->adapter_nr); - if (ret < 0) { - dev_dbg(&d->udev->dev, "%s: dvb_register_adapter() failed=%d\n", - __func__, ret); - goto err_dvb_register_adapter; - } - - adap->dvb_adap.priv = adap; - - if (d->props->read_mac_address) { - ret = d->props->read_mac_address(adap, - adap->dvb_adap.proposed_mac); - if (ret < 0) - goto err_dvb_dmx_init; - - dev_info(&d->udev->dev, "%s: MAC address: %pM\n", - KBUILD_MODNAME, adap->dvb_adap.proposed_mac); - } - - adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; - adap->demux.priv = adap; - adap->demux.filternum = 0; - adap->demux.filternum = adap->max_feed_count; - adap->demux.feednum = adap->demux.filternum; - adap->demux.start_feed = dvb_usb_start_feed; - adap->demux.stop_feed = dvb_usb_stop_feed; - adap->demux.write_to_decoder = NULL; - ret = dvb_dmx_init(&adap->demux); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: dvb_dmx_init() failed=%d\n", - KBUILD_MODNAME, ret); - goto err_dvb_dmx_init; - } - - adap->dmxdev.filternum = adap->demux.filternum; - adap->dmxdev.demux = &adap->demux.dmx; - adap->dmxdev.capabilities = 0; - ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: dvb_dmxdev_init() failed=%d\n", - KBUILD_MODNAME, ret); - goto err_dvb_dmxdev_init; - } - - ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: dvb_net_init() failed=%d\n", - KBUILD_MODNAME, ret); - goto err_dvb_net_init; - } - - mutex_init(&adap->sync_mutex); - - return 0; -err_dvb_net_init: - dvb_dmxdev_release(&adap->dmxdev); -err_dvb_dmxdev_init: - dvb_dmx_release(&adap->demux); -err_dvb_dmx_init: - dvb_unregister_adapter(&adap->dvb_adap); -err_dvb_register_adapter: - adap->dvb_adap.priv = NULL; - return ret; -} - -int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap) -{ - dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, - adap->id); - - if (adap->dvb_adap.priv) { - dvb_net_release(&adap->dvb_net); - adap->demux.dmx.close(&adap->demux.dmx); - dvb_dmxdev_release(&adap->dmxdev); - dvb_dmx_release(&adap->demux); - dvb_unregister_adapter(&adap->dvb_adap); - } - - return 0; -} - -int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - int ret; - - if (onoff) - d->powered++; - else - d->powered--; - - if (d->powered == 0 || (onoff && d->powered == 1)) { - /* when switching from 1 to 0 or from 0 to 1 */ - dev_dbg(&d->udev->dev, "%s: power=%d\n", __func__, onoff); - if (d->props->power_ctrl) { - ret = d->props->power_ctrl(d, onoff); - if (ret < 0) - goto err; - } - } - - return 0; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usb_fe_init(struct dvb_frontend *fe) -{ - int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dvb_usb_device *d = adap_to_d(adap); - mutex_lock(&adap->sync_mutex); - dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id, - fe->id); - - ret = dvb_usbv2_device_power_ctrl(d, 1); - if (ret < 0) - goto err; - - if (d->props->frontend_ctrl) { - ret = d->props->frontend_ctrl(fe, 1); - if (ret < 0) - goto err; - } - - if (adap->fe_init[fe->id]) { - ret = adap->fe_init[fe->id](fe); - if (ret < 0) - goto err; - } - - adap->active_fe = fe->id; - mutex_unlock(&adap->sync_mutex); - - return 0; -err: - mutex_unlock(&adap->sync_mutex); - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usb_fe_sleep(struct dvb_frontend *fe) -{ - int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dvb_usb_device *d = adap_to_d(adap); - mutex_lock(&adap->sync_mutex); - dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id, - fe->id); - - if (adap->fe_sleep[fe->id]) { - ret = adap->fe_sleep[fe->id](fe); - if (ret < 0) - goto err; - } - - if (d->props->frontend_ctrl) { - ret = d->props->frontend_ctrl(fe, 0); - if (ret < 0) - goto err; - } - - ret = dvb_usbv2_device_power_ctrl(d, 0); - if (ret < 0) - goto err; - - adap->active_fe = -1; - mutex_unlock(&adap->sync_mutex); - - return 0; -err: - mutex_unlock(&adap->sync_mutex); - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) -{ - int ret, i, count_registered = 0; - struct dvb_usb_device *d = adap_to_d(adap); - dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id); - - memset(adap->fe, 0, sizeof(adap->fe)); - adap->active_fe = -1; - - if (d->props->frontend_attach) { - ret = d->props->frontend_attach(adap); - if (ret < 0) { - dev_dbg(&d->udev->dev, "%s: frontend_attach() " \ - "failed=%d\n", __func__, ret); - goto err_dvb_frontend_detach; - } - } else { - dev_dbg(&d->udev->dev, "%s: frontend_attach() do not exists\n", - __func__); - ret = 0; - goto err; - } - - for (i = 0; i < MAX_NO_OF_FE_PER_ADAP && adap->fe[i]; i++) { - adap->fe[i]->id = i; - /* re-assign sleep and wakeup functions */ - adap->fe_init[i] = adap->fe[i]->ops.init; - adap->fe[i]->ops.init = dvb_usb_fe_init; - adap->fe_sleep[i] = adap->fe[i]->ops.sleep; - adap->fe[i]->ops.sleep = dvb_usb_fe_sleep; - - ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: frontend%d registration " \ - "failed\n", KBUILD_MODNAME, i); - goto err_dvb_unregister_frontend; - } - - count_registered++; - } - - if (d->props->tuner_attach) { - ret = d->props->tuner_attach(adap); - if (ret < 0) { - dev_dbg(&d->udev->dev, "%s: tuner_attach() failed=%d\n", - __func__, ret); - goto err_dvb_unregister_frontend; - } - } - - return 0; - -err_dvb_unregister_frontend: - for (i = count_registered - 1; i >= 0; i--) - dvb_unregister_frontend(adap->fe[i]); - -err_dvb_frontend_detach: - for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { - if (adap->fe[i]) - dvb_frontend_detach(adap->fe[i]); - } - -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap) -{ - int i; - dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, - adap->id); - - for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { - if (adap->fe[i]) { - dvb_unregister_frontend(adap->fe[i]); - dvb_frontend_detach(adap->fe[i]); - } - } - - return 0; -} - -static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) -{ - struct dvb_usb_adapter *adap; - int ret, i, adapter_count; - - /* resolve adapter count */ - adapter_count = d->props->num_adapters; - if (d->props->get_adapter_count) { - ret = d->props->get_adapter_count(d); - if (ret < 0) - goto err; - - adapter_count = ret; - } - - for (i = 0; i < adapter_count; i++) { - adap = &d->adapter[i]; - adap->id = i; - adap->props = &d->props->adapter[i]; - - /* speed - when running at FULL speed we need a HW PID filter */ - if (d->udev->speed == USB_SPEED_FULL && - !(adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) { - dev_err(&d->udev->dev, "%s: this USB2.0 device " \ - "cannot be run on a USB1.1 port (it " \ - "lacks a hardware PID filter)\n", - KBUILD_MODNAME); - ret = -ENODEV; - goto err; - } else if ((d->udev->speed == USB_SPEED_FULL && - adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) || - (adap->props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { - dev_info(&d->udev->dev, "%s: will use the device's " \ - "hardware PID filter " \ - "(table count: %d)\n", KBUILD_MODNAME, - adap->props->pid_filter_count); - adap->pid_filtering = 1; - adap->max_feed_count = adap->props->pid_filter_count; - } else { - dev_info(&d->udev->dev, "%s: will pass the complete " \ - "MPEG2 transport stream to the " \ - "software demuxer\n", KBUILD_MODNAME); - adap->pid_filtering = 0; - adap->max_feed_count = 255; - } - - if (!adap->pid_filtering && dvb_usb_force_pid_filter_usage && - adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) { - dev_info(&d->udev->dev, "%s: PID filter enabled by " \ - "module option\n", KBUILD_MODNAME); - adap->pid_filtering = 1; - adap->max_feed_count = adap->props->pid_filter_count; - } - - ret = dvb_usbv2_adapter_stream_init(adap); - if (ret) - goto err; - - ret = dvb_usbv2_adapter_dvb_init(adap); - if (ret) - goto err; - - ret = dvb_usbv2_adapter_frontend_init(adap); - if (ret) - goto err; - - /* use exclusive FE lock if there is multiple shared FEs */ - if (adap->fe[1]) - adap->dvb_adap.mfe_shared = 1; - - adap->dvb_adap.fe_ioctl_override = d->props->fe_ioctl_override; - } - - return 0; -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) -{ - int i; - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { - if (d->adapter[i].props) { - dvb_usbv2_adapter_frontend_exit(&d->adapter[i]); - dvb_usbv2_adapter_dvb_exit(&d->adapter[i]); - dvb_usbv2_adapter_stream_exit(&d->adapter[i]); - } - } - - return 0; -} - -/* general initialization functions */ -static int dvb_usbv2_exit(struct dvb_usb_device *d) -{ - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - dvb_usbv2_remote_exit(d); - dvb_usbv2_adapter_exit(d); - dvb_usbv2_i2c_exit(d); - kfree(d->priv); - kfree(d); - - return 0; -} - -static int dvb_usbv2_init(struct dvb_usb_device *d) -{ - int ret; - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - dvb_usbv2_device_power_ctrl(d, 1); - - if (d->props->read_config) { - ret = d->props->read_config(d); - if (ret < 0) - goto err; - } - - ret = dvb_usbv2_i2c_init(d); - if (ret < 0) - goto err; - - ret = dvb_usbv2_adapter_init(d); - if (ret < 0) - goto err; - - if (d->props->init) { - ret = d->props->init(d); - if (ret < 0) - goto err; - } - - ret = dvb_usbv2_remote_init(d); - if (ret < 0) - goto err; - - dvb_usbv2_device_power_ctrl(d, 0); - - return 0; -err: - dvb_usbv2_device_power_ctrl(d, 0); - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -/* - * udev, which is used for the firmware downloading, requires we cannot - * block during module_init(). module_init() calls USB probe() which - * is this routine. Due to that we delay actual operation using workqueue - * and return always success here. - */ -static void dvb_usbv2_init_work(struct work_struct *work) -{ - int ret; - struct dvb_usb_device *d = - container_of(work, struct dvb_usb_device, probe_work); - - d->work_pid = current->pid; - dev_dbg(&d->udev->dev, "%s: work_pid=%d\n", __func__, d->work_pid); - - if (d->props->size_of_priv) { - d->priv = kzalloc(d->props->size_of_priv, GFP_KERNEL); - if (!d->priv) { - dev_err(&d->udev->dev, "%s: kzalloc() failed\n", - KBUILD_MODNAME); - ret = -ENOMEM; - goto err_usb_driver_release_interface; - } - } - - if (d->props->identify_state) { - const char *name = NULL; - ret = d->props->identify_state(d, &name); - if (ret == 0) { - ; - } else if (ret == COLD) { - dev_info(&d->udev->dev, "%s: found a '%s' in cold " \ - "state\n", KBUILD_MODNAME, d->name); - - if (!name) - name = d->props->firmware; - - ret = dvb_usbv2_download_firmware(d, name); - if (ret == 0) { - /* device is warm, continue initialization */ - ; - } else if (ret == RECONNECTS_USB) { - /* - * USB core will call disconnect() and then - * probe() as device reconnects itself from the - * USB bus. disconnect() will release all driver - * resources and probe() is called for 'new' - * device. As 'new' device is warm we should - * never go here again. - */ - return; - } else { - /* - * Unexpected error. We must unregister driver - * manually from the device, because device is - * already register by returning from probe() - * with success. usb_driver_release_interface() - * finally calls disconnect() in order to free - * resources. - */ - goto err_usb_driver_release_interface; - } - } else { - goto err_usb_driver_release_interface; - } - } - - dev_info(&d->udev->dev, "%s: found a '%s' in warm state\n", - KBUILD_MODNAME, d->name); - - ret = dvb_usbv2_init(d); - if (ret < 0) - goto err_usb_driver_release_interface; - - dev_info(&d->udev->dev, "%s: '%s' successfully initialized and " \ - "connected\n", KBUILD_MODNAME, d->name); - - return; -err_usb_driver_release_interface: - dev_info(&d->udev->dev, "%s: '%s' error while loading driver (%d)\n", - KBUILD_MODNAME, d->name, ret); - usb_driver_release_interface(to_usb_driver(d->intf->dev.driver), - d->intf); - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return; -} - -int dvb_usbv2_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int ret; - struct dvb_usb_device *d; - struct usb_device *udev = interface_to_usbdev(intf); - struct dvb_usb_driver_info *driver_info = - (struct dvb_usb_driver_info *) id->driver_info; - - dev_dbg(&udev->dev, "%s: bInterfaceNumber=%d\n", __func__, - intf->cur_altsetting->desc.bInterfaceNumber); - - if (!id->driver_info) { - dev_err(&udev->dev, "%s: driver_info failed\n", KBUILD_MODNAME); - ret = -ENODEV; - goto err; - } - - d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); - if (!d) { - dev_err(&udev->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); - ret = -ENOMEM; - goto err; - } - - d->name = driver_info->name; - d->rc_map = driver_info->rc_map; - d->udev = udev; - d->intf = intf; - d->props = driver_info->props; - - if (d->intf->cur_altsetting->desc.bInterfaceNumber != - d->props->bInterfaceNumber) { - ret = -ENODEV; - goto err_kfree; - } - - mutex_init(&d->usb_mutex); - mutex_init(&d->i2c_mutex); - INIT_WORK(&d->probe_work, dvb_usbv2_init_work); - usb_set_intfdata(intf, d); - ret = schedule_work(&d->probe_work); - if (ret < 0) { - dev_err(&d->udev->dev, "%s: schedule_work() failed\n", - KBUILD_MODNAME); - goto err_kfree; - } - - return 0; -err_kfree: - kfree(d); -err: - dev_dbg(&udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} -EXPORT_SYMBOL(dvb_usbv2_probe); - -void dvb_usbv2_disconnect(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - const char *name = d->name; - struct device dev = d->udev->dev; - dev_dbg(&d->udev->dev, "%s: pid=%d work_pid=%d\n", __func__, - current->pid, d->work_pid); - - /* ensure initialization work is finished until release resources */ - if (d->work_pid != current->pid) - cancel_work_sync(&d->probe_work); - - if (d->props->exit) - d->props->exit(d); - - dvb_usbv2_exit(d); - - dev_info(&dev, "%s: '%s' successfully deinitialized and disconnected\n", - KBUILD_MODNAME, name); -} -EXPORT_SYMBOL(dvb_usbv2_disconnect); - -int dvb_usbv2_suspend(struct usb_interface *intf, pm_message_t msg) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - int i; - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - /* stop remote controller poll */ - if (d->rc.query && !d->rc.bulk_mode) - cancel_delayed_work_sync(&d->rc_query_work); - - /* stop streaming */ - for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { - if (d->adapter[i].dvb_adap.priv && - d->adapter[i].active_fe != -1) - usb_urb_killv2(&d->adapter[i].stream); - } - - return 0; -} -EXPORT_SYMBOL(dvb_usbv2_suspend); - -int dvb_usbv2_resume(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - int i; - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - /* start streaming */ - for (i = 0; i < MAX_NO_OF_ADAPTER_PER_DEVICE; i++) { - if (d->adapter[i].dvb_adap.priv && - d->adapter[i].active_fe != -1) - usb_urb_submitv2(&d->adapter[i].stream, NULL); - } - - /* start remote controller poll */ - if (d->rc.query && !d->rc.bulk_mode) - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(d->rc.interval)); - - return 0; -} -EXPORT_SYMBOL(dvb_usbv2_resume); - -MODULE_VERSION("2.0"); -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("DVB USB common"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c deleted file mode 100644 index 61c3fe9a599e..000000000000 --- a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c +++ /dev/null @@ -1,125 +0,0 @@ -/* dvb_usb_firmware.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for downloading the firmware to Cypress FX 1 - * and 2 based devices. - * - */ - -#include "dvb_usb.h" -#include "dvb_usb_firmware.h" - -struct usb_cypress_controller { - u8 id; - const char *name; /* name of the usb controller */ - u16 cs_reg; /* needs to be restarted, - * when the firmware has been downloaded */ -}; - -static const struct usb_cypress_controller cypress[] = { - { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cs_reg = 0x7f92 }, - { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cs_reg = 0x7f92 }, - { .id = CYPRESS_FX2, .name = "Cypress FX2", .cs_reg = 0xe600 }, -}; - -/* - * load a firmware packet to the device - */ -static int usb_cypress_writemem(struct usb_device *udev, u16 addr, u8 *data, - u8 len) -{ - return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000); -} - -int usbv2_cypress_load_firmware(struct usb_device *udev, - const struct firmware *fw, int type) -{ - struct hexline hx; - u8 reset; - int ret, pos = 0; - - /* stop the CPU */ - reset = 1; - ret = usb_cypress_writemem(udev, cypress[type].cs_reg, &reset, 1); - if (ret != 1) - pr_err("%s: could not stop the USB controller CPU", - KBUILD_MODNAME); - - while ((ret = dvb_usbv2_get_hexline(fw, &hx, &pos)) > 0) { - pr_debug("%s: writing to address %04x (buffer: %02x %02x)\n", - __func__, hx.addr, hx.len, hx.chk); - - ret = usb_cypress_writemem(udev, hx.addr, hx.data, hx.len); - if (ret != hx.len) { - pr_err("%s: error while transferring firmware " \ - "(transferred size=%d, block size=%d)", - KBUILD_MODNAME, ret, hx.len); - ret = -EINVAL; - break; - } - } - if (ret < 0) { - pr_err("%s: firmware download failed at %d with %d", - KBUILD_MODNAME, pos, ret); - return ret; - } - - if (ret == 0) { - /* restart the CPU */ - reset = 0; - if (ret || usb_cypress_writemem( - udev, cypress[type].cs_reg, &reset, 1) != 1) { - pr_err("%s: could not restart the USB controller CPU", - KBUILD_MODNAME); - ret = -EINVAL; - } - } else - ret = -EIO; - - return ret; -} -EXPORT_SYMBOL(usbv2_cypress_load_firmware); - -int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx, - int *pos) -{ - u8 *b = (u8 *) &fw->data[*pos]; - int data_offs = 4; - - if (*pos >= fw->size) - return 0; - - memset(hx, 0, sizeof(struct hexline)); - - hx->len = b[0]; - - if ((*pos + hx->len + 4) >= fw->size) - return -EINVAL; - - hx->addr = b[1] | (b[2] << 8); - hx->type = b[3]; - - if (hx->type == 0x04) { - /* b[4] and b[5] are the Extended linear address record data - * field */ - hx->addr |= (b[4] << 24) | (b[5] << 16); - /* - hx->len -= 2; - data_offs += 2; - */ - } - memcpy(hx->data, &b[data_offs], hx->len); - hx->chk = b[hx->len + data_offs]; - - *pos += hx->len + 5; - - return *pos; -} -EXPORT_SYMBOL(dvb_usbv2_get_hexline); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Cypress firmware download"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.h b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.h deleted file mode 100644 index 358d9d0b1899..000000000000 --- a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.h +++ /dev/null @@ -1,31 +0,0 @@ -/* dvb_usb_firmware.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for downloading the firmware to Cypress FX 1 - * and 2 based devices. - * - */ - -#ifndef DVB_USB_FIRMWARE_H -#define DVB_USB_FIRMWARE_H - -#define CYPRESS_AN2135 0 -#define CYPRESS_AN2235 1 -#define CYPRESS_FX2 2 - -/* commonly used firmware download types and function */ -struct hexline { - u8 len; - u32 addr; - u8 type; - u8 data[255]; - u8 chk; -}; -extern int usbv2_cypress_load_firmware(struct usb_device *, - const struct firmware *, int); -extern int dvb_usbv2_get_hexline(const struct firmware *, - struct hexline *, int *); - -#endif diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c deleted file mode 100644 index 5f5bdd0c4c9d..000000000000 --- a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * DVB USB framework - * - * Copyright (C) 2004-6 Patrick Boettcher - * Copyright (C) 2012 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "dvb_usb_common.h" - -#undef DVB_USB_XFER_DEBUG -int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, - u16 rlen) -{ - int ret, actual_length; - - if (!d || !wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint || - !d->props->generic_bulk_ctrl_endpoint_response) { - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, -EINVAL); - return -EINVAL; - } - - ret = mutex_lock_interruptible(&d->usb_mutex); - if (ret < 0) - return ret; - -#ifdef DVB_USB_XFER_DEBUG - print_hex_dump(KERN_DEBUG, KBUILD_MODNAME ": >>> ", DUMP_PREFIX_NONE, - 32, 1, wbuf, wlen, 0); -#endif - ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev, - d->props->generic_bulk_ctrl_endpoint), wbuf, wlen, - &actual_length, 2000); - if (ret < 0) - dev_err(&d->udev->dev, "%s: usb_bulk_msg() failed=%d\n", - KBUILD_MODNAME, ret); - else - ret = actual_length != wlen ? -EIO : 0; - - /* an answer is expected, and no error before */ - if (!ret && rbuf && rlen) { - if (d->props->generic_bulk_ctrl_delay) - usleep_range(d->props->generic_bulk_ctrl_delay, - d->props->generic_bulk_ctrl_delay - + 20000); - - ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, - d->props->generic_bulk_ctrl_endpoint_response), - rbuf, rlen, &actual_length, 2000); - if (ret) - dev_err(&d->udev->dev, "%s: 2nd usb_bulk_msg() " \ - "failed=%d\n", KBUILD_MODNAME, ret); - -#ifdef DVB_USB_XFER_DEBUG - print_hex_dump(KERN_DEBUG, KBUILD_MODNAME ": <<< ", - DUMP_PREFIX_NONE, 32, 1, rbuf, actual_length, - 0); -#endif - } - - mutex_unlock(&d->usb_mutex); - return ret; -} -EXPORT_SYMBOL(dvb_usbv2_generic_rw); - -int dvb_usbv2_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) -{ - return dvb_usbv2_generic_rw(d, buf, len, NULL, 0); -} -EXPORT_SYMBOL(dvb_usbv2_generic_write); diff --git a/drivers/media/dvb/dvb-usb/ec168.c b/drivers/media/dvb/dvb-usb/ec168.c deleted file mode 100644 index ab77622c383d..000000000000 --- a/drivers/media/dvb/dvb-usb/ec168.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - * E3C EC168 DVB USB driver - * - * Copyright (C) 2009 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "ec168.h" -#include "ec100.h" -#include "mxl5005s.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req) -{ - int ret; - unsigned int pipe; - u8 request, requesttype; - u8 *buf; - - switch (req->cmd) { - case DOWNLOAD_FIRMWARE: - case GPIO: - case WRITE_I2C: - case STREAMING_CTRL: - requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); - request = req->cmd; - break; - case READ_I2C: - requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); - request = req->cmd; - break; - case GET_CONFIG: - requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); - request = CONFIG; - break; - case SET_CONFIG: - requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); - request = CONFIG; - break; - case WRITE_DEMOD: - requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); - request = DEMOD_RW; - break; - case READ_DEMOD: - requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); - request = DEMOD_RW; - break; - default: - pr_err("%s: unknown command=%02x\n", KBUILD_MODNAME, req->cmd); - ret = -EINVAL; - goto error; - } - - buf = kmalloc(req->size, GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - goto error; - } - - if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) { - /* write */ - memcpy(buf, req->data, req->size); - pipe = usb_sndctrlpipe(d->udev, 0); - } else { - /* read */ - pipe = usb_rcvctrlpipe(d->udev, 0); - } - - msleep(1); /* avoid I2C errors */ - - ret = usb_control_msg(d->udev, pipe, request, requesttype, req->value, - req->index, buf, req->size, EC168_USB_TIMEOUT); - - ec168_debug_dump(request, requesttype, req->value, req->index, buf, - req->size); - - if (ret < 0) - goto err_dealloc; - else - ret = 0; - - /* read request, copy returned data to return buf */ - if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) - memcpy(req->data, buf, req->size); - - kfree(buf); - return ret; - -err_dealloc: - kfree(buf); -error: - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -/* I2C */ -static struct ec100_config ec168_ec100_config; - -static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct ec168_req req; - int i = 0; - int ret; - - if (num > 2) - return -EINVAL; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - while (i < num) { - if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { - if (msg[i].addr == ec168_ec100_config.demod_address) { - req.cmd = READ_DEMOD; - req.value = 0; - req.index = 0xff00 + msg[i].buf[0]; /* reg */ - req.size = msg[i+1].len; /* bytes to read */ - req.data = &msg[i+1].buf[0]; - ret = ec168_ctrl_msg(d, &req); - i += 2; - } else { - pr_err("%s: I2C read not implemented\n", - KBUILD_MODNAME); - ret = -EOPNOTSUPP; - i += 2; - } - } else { - if (msg[i].addr == ec168_ec100_config.demod_address) { - req.cmd = WRITE_DEMOD; - req.value = msg[i].buf[1]; /* val */ - req.index = 0xff00 + msg[i].buf[0]; /* reg */ - req.size = 0; - req.data = NULL; - ret = ec168_ctrl_msg(d, &req); - i += 1; - } else { - req.cmd = WRITE_I2C; - req.value = msg[i].buf[0]; /* val */ - req.index = 0x0100 + msg[i].addr; /* I2C addr */ - req.size = msg[i].len-1; - req.data = &msg[i].buf[1]; - ret = ec168_ctrl_msg(d, &req); - i += 1; - } - } - if (ret) - goto error; - - } - ret = i; - -error: - mutex_unlock(&d->i2c_mutex); - return i; -} - -static u32 ec168_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm ec168_i2c_algo = { - .master_xfer = ec168_i2c_xfer, - .functionality = ec168_i2c_func, -}; - -/* Callbacks for DVB USB */ -static int ec168_identify_state(struct dvb_usb_device *d, const char **name) -{ - int ret; - u8 reply; - struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply}; - pr_debug("%s:\n", __func__); - - ret = ec168_ctrl_msg(d, &req); - if (ret) - goto error; - - pr_debug("%s: reply=%02x\n", __func__, reply); - - if (reply == 0x01) - ret = WARM; - else - ret = COLD; - - return ret; -error: - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -static int ec168_download_firmware(struct dvb_usb_device *d, - const struct firmware *fw) -{ - int ret, len, remaining; - struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL}; - pr_debug("%s:\n", __func__); - - #define LEN_MAX 2048 /* max packet size */ - for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { - len = remaining; - if (len > LEN_MAX) - len = LEN_MAX; - - req.size = len; - req.data = (u8 *) &fw->data[fw->size - remaining]; - req.index = fw->size - remaining; - - ret = ec168_ctrl_msg(d, &req); - if (ret) { - pr_err("%s: firmware download failed=%d\n", - KBUILD_MODNAME, ret); - goto error; - } - } - - req.size = 0; - - /* set "warm"? */ - req.cmd = SET_CONFIG; - req.value = 0; - req.index = 0x0001; - ret = ec168_ctrl_msg(d, &req); - if (ret) - goto error; - - /* really needed - no idea what does */ - req.cmd = GPIO; - req.value = 0; - req.index = 0x0206; - ret = ec168_ctrl_msg(d, &req); - if (ret) - goto error; - - /* activate tuner I2C? */ - req.cmd = WRITE_I2C; - req.value = 0; - req.index = 0x00c6; - ret = ec168_ctrl_msg(d, &req); - if (ret) - goto error; - - return ret; -error: - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -static struct ec100_config ec168_ec100_config = { - .demod_address = 0xff, /* not real address, demod is integrated */ -}; - -static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap) -{ - pr_debug("%s:\n", __func__); - adap->fe[0] = dvb_attach(ec100_attach, &ec168_ec100_config, - &adap_to_d(adap)->i2c_adap); - if (adap->fe[0] == NULL) - return -ENODEV; - - return 0; -} - -static struct mxl5005s_config ec168_mxl5003s_config = { - .i2c_address = 0xc6, - .if_freq = IF_FREQ_4570000HZ, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_OFF, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .AgcMasterByte = 0x00, -}; - -static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) -{ - pr_debug("%s:\n", __func__); - return dvb_attach(mxl5005s_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, - &ec168_mxl5003s_config) == NULL ? -ENODEV : 0; -} - -static int ec168_streaming_ctrl(struct dvb_frontend *fe, int onoff) -{ - struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL}; - pr_debug("%s: onoff=%d\n", __func__, onoff); - if (onoff) - req.index = 0x0102; - return ec168_ctrl_msg(fe_to_d(fe), &req); -} - -/* DVB USB Driver stuff */ -/* bInterfaceNumber 0 is HID - * bInterfaceNumber 1 is DVB-T */ -static struct dvb_usb_device_properties ec168_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .bInterfaceNumber = 1, - - .identify_state = ec168_identify_state, - .firmware = "dvb-usb-ec168.fw", - .download_firmware = ec168_download_firmware, - - .i2c_algo = &ec168_i2c_algo, - .frontend_attach = ec168_ec100_frontend_attach, - .tuner_attach = ec168_mxl5003s_tuner_attach, - .streaming_ctrl = ec168_streaming_ctrl, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_BULK(0x82, 6, 32 * 512), - } - }, -}; - -static const struct dvb_usb_driver_info ec168_driver_info = { - .name = "E3C EC168 reference design", - .props = &ec168_props, -}; - -static const struct usb_device_id ec168_id[] = { - { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168), - .driver_info = (kernel_ulong_t) &ec168_driver_info }, - { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2), - .driver_info = (kernel_ulong_t) &ec168_driver_info }, - { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3), - .driver_info = (kernel_ulong_t) &ec168_driver_info }, - { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4), - .driver_info = (kernel_ulong_t) &ec168_driver_info }, - { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5), - .driver_info = (kernel_ulong_t) &ec168_driver_info }, - {} -}; -MODULE_DEVICE_TABLE(usb, ec168_id); - -static struct usb_driver ec168_driver = { - .name = KBUILD_MODNAME, - .id_table = ec168_id, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(ec168_driver); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("E3C EC168 driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/ec168.h b/drivers/media/dvb/dvb-usb/ec168.h deleted file mode 100644 index 9181236f6ebc..000000000000 --- a/drivers/media/dvb/dvb-usb/ec168.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * E3C EC168 DVB USB driver - * - * Copyright (C) 2009 Antti Palosaari - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef EC168_H -#define EC168_H - -#include "dvb_usb.h" - -#define ec168_debug_dump(r, t, v, i, b, l) { \ - char *direction; \ - if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ - direction = ">>>"; \ - else \ - direction = "<<<"; \ - pr_debug("%s: %02x %02x %02x %02x %02x %02x %02x %02x %s\n", \ - __func__, t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, \ - l & 0xff, l >> 8, direction); \ -} - -#define EC168_USB_TIMEOUT 1000 - -struct ec168_req { - u8 cmd; /* [1] */ - u16 value; /* [2|3] */ - u16 index; /* [4|5] */ - u16 size; /* [6|7] */ - u8 *data; -}; - -enum ec168_cmd { - DOWNLOAD_FIRMWARE = 0x00, - CONFIG = 0x01, - DEMOD_RW = 0x03, - GPIO = 0x04, - STREAMING_CTRL = 0x10, - READ_I2C = 0x20, - WRITE_I2C = 0x21, - HID_DOWNLOAD = 0x30, - GET_CONFIG, - SET_CONFIG, - READ_DEMOD, - WRITE_DEMOD, -}; - -#endif diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c deleted file mode 100644 index cf29f43e3598..000000000000 --- a/drivers/media/dvb/dvb-usb/gl861.c +++ /dev/null @@ -1,175 +0,0 @@ -/* DVB USB compliant linux driver for GL861 USB2.0 devices. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "gl861.h" - -#include "zl10353.h" -#include "qt1010.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - u16 index; - u16 value = addr << (8 + 1); - int wo = (rbuf == NULL || rlen == 0); /* write-only */ - u8 req, type; - - if (wo) { - req = GL861_REQ_I2C_WRITE; - type = GL861_WRITE; - } else { /* rw */ - req = GL861_REQ_I2C_READ; - type = GL861_READ; - } - - switch (wlen) { - case 1: - index = wbuf[0]; - break; - case 2: - index = wbuf[0]; - value = value + wbuf[1]; - break; - default: - pr_err("%s: wlen=%d, aborting\n", KBUILD_MODNAME, wlen); - return -EINVAL; - } - - msleep(1); /* avoid I2C errors */ - - return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type, - value, index, rbuf, rlen, 2000); -} - -/* I2C */ -static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i; - - if (num > 2) - return -EINVAL; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - /* write/read request */ - if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { - if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf, - msg[i].len, msg[i+1].buf, msg[i+1].len) < 0) - break; - i++; - } else - if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf, - msg[i].len, NULL, 0) < 0) - break; - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - -static u32 gl861_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm gl861_i2c_algo = { - .master_xfer = gl861_i2c_xfer, - .functionality = gl861_i2c_func, -}; - -/* Callbacks for DVB USB */ -static struct zl10353_config gl861_zl10353_config = { - .demod_address = 0x0f, - .no_tuner = 1, - .parallel_ts = 1, -}; - -static int gl861_frontend_attach(struct dvb_usb_adapter *adap) -{ - - adap->fe[0] = dvb_attach(zl10353_attach, &gl861_zl10353_config, - &adap_to_d(adap)->i2c_adap); - if (adap->fe[0] == NULL) - return -EIO; - - return 0; -} - -static struct qt1010_config gl861_qt1010_config = { - .i2c_address = 0x62 -}; - -static int gl861_tuner_attach(struct dvb_usb_adapter *adap) -{ - return dvb_attach(qt1010_attach, - adap->fe[0], &adap_to_d(adap)->i2c_adap, - &gl861_qt1010_config) == NULL ? -ENODEV : 0; -} - -static int gl861_init(struct dvb_usb_device *d) -{ - /* - * There is 2 interfaces. Interface 0 is for TV and interface 1 is - * for HID remote controller. Interface 0 has 2 alternate settings. - * For some reason we need to set interface explicitly, defaulted - * as alternate setting 1? - */ - return usb_set_interface(d->udev, 0, 0); -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties gl861_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - - .i2c_algo = &gl861_i2c_algo, - .frontend_attach = gl861_frontend_attach, - .tuner_attach = gl861_tuner_attach, - .init = gl861_init, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_BULK(0x81, 7, 512), - } - } -}; - -static const struct usb_device_id gl861_id_table[] = { - { DVB_USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801, - &gl861_props, "MSI Mega Sky 55801 DVB-T USB2.0", NULL) }, - { DVB_USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU, - &gl861_props, "A-LINK DTU DVB-T USB2.0", NULL) }, - { } -}; -MODULE_DEVICE_TABLE(usb, gl861_id_table); - -static struct usb_driver gl861_usb_driver = { - .name = KBUILD_MODNAME, - .id_table = gl861_id_table, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(gl861_usb_driver); - -MODULE_AUTHOR("Carl Lundqvist "); -MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861"); -MODULE_VERSION("0.1"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/gl861.h b/drivers/media/dvb/dvb-usb/gl861.h deleted file mode 100644 index b0b80d87bb7e..000000000000 --- a/drivers/media/dvb/dvb-usb/gl861.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _DVB_USB_GL861_H_ -#define _DVB_USB_GL861_H_ - -#include "dvb_usb.h" - -#define GL861_WRITE 0x40 -#define GL861_READ 0xc0 - -#define GL861_REQ_I2C_WRITE 0x01 -#define GL861_REQ_I2C_READ 0x02 - -#endif diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c deleted file mode 100644 index d83df4bb72d3..000000000000 --- a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c +++ /dev/null @@ -1,612 +0,0 @@ -/* - * mxl111sf-demod.c - driver for the MaxLinear MXL111SF DVB-T demodulator - * - * Copyright (C) 2010 Michael Krufky - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "mxl111sf-demod.h" -#include "mxl111sf-reg.h" - -/* debug */ -static int mxl111sf_demod_debug; -module_param_named(debug, mxl111sf_demod_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); - -#define mxl_dbg(fmt, arg...) \ - if (mxl111sf_demod_debug) \ - mxl_printk(KERN_DEBUG, fmt, ##arg) - -/* ------------------------------------------------------------------------ */ - -struct mxl111sf_demod_state { - struct mxl111sf_state *mxl_state; - - struct mxl111sf_demod_config *cfg; - - struct dvb_frontend fe; -}; - -/* ------------------------------------------------------------------------ */ - -static int mxl111sf_demod_read_reg(struct mxl111sf_demod_state *state, - u8 addr, u8 *data) -{ - return (state->cfg->read_reg) ? - state->cfg->read_reg(state->mxl_state, addr, data) : - -EINVAL; -} - -static int mxl111sf_demod_write_reg(struct mxl111sf_demod_state *state, - u8 addr, u8 data) -{ - return (state->cfg->write_reg) ? - state->cfg->write_reg(state->mxl_state, addr, data) : - -EINVAL; -} - -static -int mxl111sf_demod_program_regs(struct mxl111sf_demod_state *state, - struct mxl111sf_reg_ctrl_info *ctrl_reg_info) -{ - return (state->cfg->program_regs) ? - state->cfg->program_regs(state->mxl_state, ctrl_reg_info) : - -EINVAL; -} - -/* ------------------------------------------------------------------------ */ -/* TPS */ - -static -int mxl1x1sf_demod_get_tps_code_rate(struct mxl111sf_demod_state *state, - fe_code_rate_t *code_rate) -{ - u8 val; - int ret = mxl111sf_demod_read_reg(state, V6_CODE_RATE_TPS_REG, &val); - /* bit<2:0> - 000:1/2, 001:2/3, 010:3/4, 011:5/6, 100:7/8 */ - if (mxl_fail(ret)) - goto fail; - - switch (val & V6_CODE_RATE_TPS_MASK) { - case 0: - *code_rate = FEC_1_2; - break; - case 1: - *code_rate = FEC_2_3; - break; - case 2: - *code_rate = FEC_3_4; - break; - case 3: - *code_rate = FEC_5_6; - break; - case 4: - *code_rate = FEC_7_8; - break; - } -fail: - return ret; -} - -static -int mxl1x1sf_demod_get_tps_modulation(struct mxl111sf_demod_state *state, - fe_modulation_t *modulation) -{ - u8 val; - int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val); - /* Constellation, 00 : QPSK, 01 : 16QAM, 10:64QAM */ - if (mxl_fail(ret)) - goto fail; - - switch ((val & V6_PARAM_CONSTELLATION_MASK) >> 4) { - case 0: - *modulation = QPSK; - break; - case 1: - *modulation = QAM_16; - break; - case 2: - *modulation = QAM_64; - break; - } -fail: - return ret; -} - -static -int mxl1x1sf_demod_get_tps_guard_fft_mode(struct mxl111sf_demod_state *state, - fe_transmit_mode_t *fft_mode) -{ - u8 val; - int ret = mxl111sf_demod_read_reg(state, V6_MODE_TPS_REG, &val); - /* FFT Mode, 00:2K, 01:8K, 10:4K */ - if (mxl_fail(ret)) - goto fail; - - switch ((val & V6_PARAM_FFT_MODE_MASK) >> 2) { - case 0: - *fft_mode = TRANSMISSION_MODE_2K; - break; - case 1: - *fft_mode = TRANSMISSION_MODE_8K; - break; - case 2: - *fft_mode = TRANSMISSION_MODE_4K; - break; - } -fail: - return ret; -} - -static -int mxl1x1sf_demod_get_tps_guard_interval(struct mxl111sf_demod_state *state, - fe_guard_interval_t *guard) -{ - u8 val; - int ret = mxl111sf_demod_read_reg(state, V6_CP_TPS_REG, &val); - /* 00:1/32, 01:1/16, 10:1/8, 11:1/4 */ - if (mxl_fail(ret)) - goto fail; - - switch ((val & V6_PARAM_GI_MASK) >> 4) { - case 0: - *guard = GUARD_INTERVAL_1_32; - break; - case 1: - *guard = GUARD_INTERVAL_1_16; - break; - case 2: - *guard = GUARD_INTERVAL_1_8; - break; - case 3: - *guard = GUARD_INTERVAL_1_4; - break; - } -fail: - return ret; -} - -static -int mxl1x1sf_demod_get_tps_hierarchy(struct mxl111sf_demod_state *state, - fe_hierarchy_t *hierarchy) -{ - u8 val; - int ret = mxl111sf_demod_read_reg(state, V6_TPS_HIERACHY_REG, &val); - /* bit<6:4> - 000:Non hierarchy, 001:1, 010:2, 011:4 */ - if (mxl_fail(ret)) - goto fail; - - switch ((val & V6_TPS_HIERARCHY_INFO_MASK) >> 6) { - case 0: - *hierarchy = HIERARCHY_NONE; - break; - case 1: - *hierarchy = HIERARCHY_1; - break; - case 2: - *hierarchy = HIERARCHY_2; - break; - case 3: - *hierarchy = HIERARCHY_4; - break; - } -fail: - return ret; -} - -/* ------------------------------------------------------------------------ */ -/* LOCKS */ - -static -int mxl1x1sf_demod_get_sync_lock_status(struct mxl111sf_demod_state *state, - int *sync_lock) -{ - u8 val = 0; - int ret = mxl111sf_demod_read_reg(state, V6_SYNC_LOCK_REG, &val); - if (mxl_fail(ret)) - goto fail; - *sync_lock = (val & SYNC_LOCK_MASK) >> 4; -fail: - return ret; -} - -static -int mxl1x1sf_demod_get_rs_lock_status(struct mxl111sf_demod_state *state, - int *rs_lock) -{ - u8 val = 0; - int ret = mxl111sf_demod_read_reg(state, V6_RS_LOCK_DET_REG, &val); - if (mxl_fail(ret)) - goto fail; - *rs_lock = (val & RS_LOCK_DET_MASK) >> 3; -fail: - return ret; -} - -static -int mxl1x1sf_demod_get_tps_lock_status(struct mxl111sf_demod_state *state, - int *tps_lock) -{ - u8 val = 0; - int ret = mxl111sf_demod_read_reg(state, V6_TPS_LOCK_REG, &val); - if (mxl_fail(ret)) - goto fail; - *tps_lock = (val & V6_PARAM_TPS_LOCK_MASK) >> 6; -fail: - return ret; -} - -static -int mxl1x1sf_demod_get_fec_lock_status(struct mxl111sf_demod_state *state, - int *fec_lock) -{ - u8 val = 0; - int ret = mxl111sf_demod_read_reg(state, V6_IRQ_STATUS_REG, &val); - if (mxl_fail(ret)) - goto fail; - *fec_lock = (val & IRQ_MASK_FEC_LOCK) >> 4; -fail: - return ret; -} - -#if 0 -static -int mxl1x1sf_demod_get_cp_lock_status(struct mxl111sf_demod_state *state, - int *cp_lock) -{ - u8 val = 0; - int ret = mxl111sf_demod_read_reg(state, V6_CP_LOCK_DET_REG, &val); - if (mxl_fail(ret)) - goto fail; - *cp_lock = (val & V6_CP_LOCK_DET_MASK) >> 2; -fail: - return ret; -} -#endif - -static int mxl1x1sf_demod_reset_irq_status(struct mxl111sf_demod_state *state) -{ - return mxl111sf_demod_write_reg(state, 0x0e, 0xff); -} - -/* ------------------------------------------------------------------------ */ - -static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe) -{ - struct mxl111sf_demod_state *state = fe->demodulator_priv; - int ret = 0; - - struct mxl111sf_reg_ctrl_info phy_pll_patch[] = { - {0x00, 0xff, 0x01}, /* change page to 1 */ - {0x40, 0xff, 0x05}, - {0x40, 0xff, 0x01}, - {0x41, 0xff, 0xca}, - {0x41, 0xff, 0xc0}, - {0x00, 0xff, 0x00}, /* change page to 0 */ - {0, 0, 0} - }; - - mxl_dbg("()"); - - if (fe->ops.tuner_ops.set_params) { - ret = fe->ops.tuner_ops.set_params(fe); - if (mxl_fail(ret)) - goto fail; - msleep(50); - } - ret = mxl111sf_demod_program_regs(state, phy_pll_patch); - mxl_fail(ret); - msleep(50); - ret = mxl1x1sf_demod_reset_irq_status(state); - mxl_fail(ret); - msleep(100); -fail: - return ret; -} - -/* ------------------------------------------------------------------------ */ - -#if 0 -/* resets TS Packet error count */ -/* After setting 7th bit of V5_PER_COUNT_RESET_REG, it should be reset to 0. */ -static -int mxl1x1sf_demod_reset_packet_error_count(struct mxl111sf_demod_state *state) -{ - struct mxl111sf_reg_ctrl_info reset_per_count[] = { - {0x20, 0x01, 0x01}, - {0x20, 0x01, 0x00}, - {0, 0, 0} - }; - return mxl111sf_demod_program_regs(state, reset_per_count); -} -#endif - -/* returns TS Packet error count */ -/* PER Count = FEC_PER_COUNT * (2 ** (FEC_PER_SCALE * 4)) */ -static int mxl111sf_demod_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct mxl111sf_demod_state *state = fe->demodulator_priv; - u32 fec_per_count, fec_per_scale; - u8 val; - int ret; - - *ucblocks = 0; - - /* FEC_PER_COUNT Register */ - ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_COUNT_REG, &val); - if (mxl_fail(ret)) - goto fail; - - fec_per_count = val; - - /* FEC_PER_SCALE Register */ - ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_SCALE_REG, &val); - if (mxl_fail(ret)) - goto fail; - - val &= V6_FEC_PER_SCALE_MASK; - val *= 4; - - fec_per_scale = 1 << val; - - fec_per_count *= fec_per_scale; - - *ucblocks = fec_per_count; -fail: - return ret; -} - -#ifdef MXL111SF_DEMOD_ENABLE_CALCULATIONS -/* FIXME: leaving this enabled breaks the build on some architectures, - * and we shouldn't have any floating point math in the kernel, anyway. - * - * These macros need to be re-written, but it's harmless to simply - * return zero for now. */ -#define CALCULATE_BER(avg_errors, count) \ - ((u32)(avg_errors * 4)/(count*64*188*8)) -#define CALCULATE_SNR(data) \ - ((u32)((10 * (u32)data / 64) - 2.5)) -#else -#define CALCULATE_BER(avg_errors, count) 0 -#define CALCULATE_SNR(data) 0 -#endif - -static int mxl111sf_demod_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct mxl111sf_demod_state *state = fe->demodulator_priv; - u8 val1, val2, val3; - int ret; - - *ber = 0; - - ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_LSB_REG, &val1); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_MSB_REG, &val2); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_demod_read_reg(state, V6_N_ACCUMULATE_REG, &val3); - if (mxl_fail(ret)) - goto fail; - - *ber = CALCULATE_BER((val1 | (val2 << 8)), val3); -fail: - return ret; -} - -static int mxl111sf_demod_calc_snr(struct mxl111sf_demod_state *state, - u16 *snr) -{ - u8 val1, val2; - int ret; - - *snr = 0; - - ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_LSB_REG, &val1); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_MSB_REG, &val2); - if (mxl_fail(ret)) - goto fail; - - *snr = CALCULATE_SNR(val1 | ((val2 & 0x03) << 8)); -fail: - return ret; -} - -static int mxl111sf_demod_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct mxl111sf_demod_state *state = fe->demodulator_priv; - - int ret = mxl111sf_demod_calc_snr(state, snr); - if (mxl_fail(ret)) - goto fail; - - *snr /= 10; /* 0.1 dB */ -fail: - return ret; -} - -static int mxl111sf_demod_read_status(struct dvb_frontend *fe, - fe_status_t *status) -{ - struct mxl111sf_demod_state *state = fe->demodulator_priv; - int ret, locked, cr_lock, sync_lock, fec_lock; - - *status = 0; - - ret = mxl1x1sf_demod_get_rs_lock_status(state, &locked); - if (mxl_fail(ret)) - goto fail; - ret = mxl1x1sf_demod_get_tps_lock_status(state, &cr_lock); - if (mxl_fail(ret)) - goto fail; - ret = mxl1x1sf_demod_get_sync_lock_status(state, &sync_lock); - if (mxl_fail(ret)) - goto fail; - ret = mxl1x1sf_demod_get_fec_lock_status(state, &fec_lock); - if (mxl_fail(ret)) - goto fail; - - if (locked) - *status |= FE_HAS_SIGNAL; - if (cr_lock) - *status |= FE_HAS_CARRIER; - if (sync_lock) - *status |= FE_HAS_SYNC; - if (fec_lock) /* false positives? */ - *status |= FE_HAS_VITERBI; - - if ((locked) && (cr_lock) && (sync_lock)) - *status |= FE_HAS_LOCK; -fail: - return ret; -} - -static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe, - u16 *signal_strength) -{ - struct mxl111sf_demod_state *state = fe->demodulator_priv; - fe_modulation_t modulation; - u16 snr; - - mxl111sf_demod_calc_snr(state, &snr); - mxl1x1sf_demod_get_tps_modulation(state, &modulation); - - switch (modulation) { - case QPSK: - *signal_strength = (snr >= 1300) ? - min(65535, snr * 44) : snr * 38; - break; - case QAM_16: - *signal_strength = (snr >= 1500) ? - min(65535, snr * 38) : snr * 33; - break; - case QAM_64: - *signal_strength = (snr >= 2000) ? - min(65535, snr * 29) : snr * 25; - break; - default: - *signal_strength = 0; - return -EINVAL; - } - - return 0; -} - -static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct mxl111sf_demod_state *state = fe->demodulator_priv; - - mxl_dbg("()"); -#if 0 - p->inversion = /* FIXME */ ? INVERSION_ON : INVERSION_OFF; -#endif - if (fe->ops.tuner_ops.get_bandwidth) - fe->ops.tuner_ops.get_bandwidth(fe, &p->bandwidth_hz); - if (fe->ops.tuner_ops.get_frequency) - fe->ops.tuner_ops.get_frequency(fe, &p->frequency); - mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_HP); - mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_LP); - mxl1x1sf_demod_get_tps_modulation(state, &p->modulation); - mxl1x1sf_demod_get_tps_guard_fft_mode(state, - &p->transmission_mode); - mxl1x1sf_demod_get_tps_guard_interval(state, - &p->guard_interval); - mxl1x1sf_demod_get_tps_hierarchy(state, - &p->hierarchy); - - return 0; -} - -static -int mxl111sf_demod_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 1000; - return 0; -} - -static void mxl111sf_demod_release(struct dvb_frontend *fe) -{ - struct mxl111sf_demod_state *state = fe->demodulator_priv; - mxl_dbg("()"); - kfree(state); - fe->demodulator_priv = NULL; -} - -static struct dvb_frontend_ops mxl111sf_demod_ops = { - .delsys = { SYS_DVBT }, - .info = { - .name = "MaxLinear MxL111SF DVB-T demodulator", - .frequency_min = 177000000, - .frequency_max = 858000000, - .frequency_stepsize = 166666, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_QAM_AUTO | - FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER - }, - .release = mxl111sf_demod_release, -#if 0 - .init = mxl111sf_init, - .i2c_gate_ctrl = mxl111sf_i2c_gate_ctrl, -#endif - .set_frontend = mxl111sf_demod_set_frontend, - .get_frontend = mxl111sf_demod_get_frontend, - .get_tune_settings = mxl111sf_demod_get_tune_settings, - .read_status = mxl111sf_demod_read_status, - .read_signal_strength = mxl111sf_demod_read_signal_strength, - .read_ber = mxl111sf_demod_read_ber, - .read_snr = mxl111sf_demod_read_snr, - .read_ucblocks = mxl111sf_demod_read_ucblocks, -}; - -struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, - struct mxl111sf_demod_config *cfg) -{ - struct mxl111sf_demod_state *state = NULL; - - mxl_dbg("()"); - - state = kzalloc(sizeof(struct mxl111sf_demod_state), GFP_KERNEL); - if (state == NULL) - return NULL; - - state->mxl_state = mxl_state; - state->cfg = cfg; - - memcpy(&state->fe.ops, &mxl111sf_demod_ops, - sizeof(struct dvb_frontend_ops)); - - state->fe.demodulator_priv = state; - return &state->fe; -} -EXPORT_SYMBOL_GPL(mxl111sf_demod_attach); - -MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver"); -MODULE_AUTHOR("Michael Krufky "); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.1"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.h b/drivers/media/dvb/dvb-usb/mxl111sf-demod.h deleted file mode 100644 index 432706ae5274..000000000000 --- a/drivers/media/dvb/dvb-usb/mxl111sf-demod.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * mxl111sf-demod.h - driver for the MaxLinear MXL111SF DVB-T demodulator - * - * Copyright (C) 2010 Michael Krufky - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __MXL111SF_DEMOD_H__ -#define __MXL111SF_DEMOD_H__ - -#include "dvb_frontend.h" -#include "mxl111sf.h" - -struct mxl111sf_demod_config { - int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data); - int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data); - int (*program_regs)(struct mxl111sf_state *state, - struct mxl111sf_reg_ctrl_info *ctrl_reg_info); -}; - -#if defined(CONFIG_DVB_USB_MXL111SF) || \ - (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE)) -extern -struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, - struct mxl111sf_demod_config *cfg); -#else -static inline -struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, - struct mxl111sf_demod_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_USB_MXL111SF */ - -#endif /* __MXL111SF_DEMOD_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.c b/drivers/media/dvb/dvb-usb/mxl111sf-gpio.c deleted file mode 100644 index e4121cb8f5ef..000000000000 --- a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.c +++ /dev/null @@ -1,763 +0,0 @@ -/* - * mxl111sf-gpio.c - driver for the MaxLinear MXL111SF - * - * Copyright (C) 2010 Michael Krufky - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "mxl111sf-gpio.h" -#include "mxl111sf-i2c.h" -#include "mxl111sf.h" - -/* ------------------------------------------------------------------------- */ - -#define MXL_GPIO_MUX_REG_0 0x84 -#define MXL_GPIO_MUX_REG_1 0x89 -#define MXL_GPIO_MUX_REG_2 0x82 - -#define MXL_GPIO_DIR_INPUT 0 -#define MXL_GPIO_DIR_OUTPUT 1 - - -static int mxl111sf_set_gpo_state(struct mxl111sf_state *state, u8 pin, u8 val) -{ - int ret; - u8 tmp; - - mxl_debug_adv("(%d, %d)", pin, val); - - if ((pin > 0) && (pin < 8)) { - ret = mxl111sf_read_reg(state, 0x19, &tmp); - if (mxl_fail(ret)) - goto fail; - tmp &= ~(1 << (pin - 1)); - tmp |= (val << (pin - 1)); - ret = mxl111sf_write_reg(state, 0x19, tmp); - if (mxl_fail(ret)) - goto fail; - } else if (pin <= 10) { - if (pin == 0) - pin += 7; - ret = mxl111sf_read_reg(state, 0x30, &tmp); - if (mxl_fail(ret)) - goto fail; - tmp &= ~(1 << (pin - 3)); - tmp |= (val << (pin - 3)); - ret = mxl111sf_write_reg(state, 0x30, tmp); - if (mxl_fail(ret)) - goto fail; - } else - ret = -EINVAL; -fail: - return ret; -} - -static int mxl111sf_get_gpi_state(struct mxl111sf_state *state, u8 pin, u8 *val) -{ - int ret; - u8 tmp; - - mxl_debug("(0x%02x)", pin); - - *val = 0; - - switch (pin) { - case 0: - case 1: - case 2: - case 3: - ret = mxl111sf_read_reg(state, 0x23, &tmp); - if (mxl_fail(ret)) - goto fail; - *val = (tmp >> (pin + 4)) & 0x01; - break; - case 4: - case 5: - case 6: - case 7: - ret = mxl111sf_read_reg(state, 0x2f, &tmp); - if (mxl_fail(ret)) - goto fail; - *val = (tmp >> pin) & 0x01; - break; - case 8: - case 9: - case 10: - ret = mxl111sf_read_reg(state, 0x22, &tmp); - if (mxl_fail(ret)) - goto fail; - *val = (tmp >> (pin - 3)) & 0x01; - break; - default: - return -EINVAL; /* invalid pin */ - } -fail: - return ret; -} - -struct mxl_gpio_cfg { - u8 pin; - u8 dir; - u8 val; -}; - -static int mxl111sf_config_gpio_pins(struct mxl111sf_state *state, - struct mxl_gpio_cfg *gpio_cfg) -{ - int ret; - u8 tmp; - - mxl_debug_adv("(%d, %d)", gpio_cfg->pin, gpio_cfg->dir); - - switch (gpio_cfg->pin) { - case 0: - case 1: - case 2: - case 3: - ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_0, &tmp); - if (mxl_fail(ret)) - goto fail; - tmp &= ~(1 << (gpio_cfg->pin + 4)); - tmp |= (gpio_cfg->dir << (gpio_cfg->pin + 4)); - ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_0, tmp); - if (mxl_fail(ret)) - goto fail; - break; - case 4: - case 5: - case 6: - case 7: - ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_1, &tmp); - if (mxl_fail(ret)) - goto fail; - tmp &= ~(1 << gpio_cfg->pin); - tmp |= (gpio_cfg->dir << gpio_cfg->pin); - ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_1, tmp); - if (mxl_fail(ret)) - goto fail; - break; - case 8: - case 9: - case 10: - ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_2, &tmp); - if (mxl_fail(ret)) - goto fail; - tmp &= ~(1 << (gpio_cfg->pin - 3)); - tmp |= (gpio_cfg->dir << (gpio_cfg->pin - 3)); - ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_2, tmp); - if (mxl_fail(ret)) - goto fail; - break; - default: - return -EINVAL; /* invalid pin */ - } - - ret = (MXL_GPIO_DIR_OUTPUT == gpio_cfg->dir) ? - mxl111sf_set_gpo_state(state, - gpio_cfg->pin, gpio_cfg->val) : - mxl111sf_get_gpi_state(state, - gpio_cfg->pin, &gpio_cfg->val); - mxl_fail(ret); -fail: - return ret; -} - -static int mxl111sf_hw_do_set_gpio(struct mxl111sf_state *state, - int gpio, int direction, int val) -{ - struct mxl_gpio_cfg gpio_config = { - .pin = gpio, - .dir = direction, - .val = val, - }; - - mxl_debug("(%d, %d, %d)", gpio, direction, val); - - return mxl111sf_config_gpio_pins(state, &gpio_config); -} - -/* ------------------------------------------------------------------------- */ - -#define PIN_MUX_MPEG_MODE_MASK 0x40 /* 0x17 <6> */ -#define PIN_MUX_MPEG_PAR_EN_MASK 0x01 /* 0x18 <0> */ -#define PIN_MUX_MPEG_SER_EN_MASK 0x02 /* 0x18 <1> */ -#define PIN_MUX_MPG_IN_MUX_MASK 0x80 /* 0x3D <7> */ -#define PIN_MUX_BT656_ENABLE_MASK 0x04 /* 0x12 <2> */ -#define PIN_MUX_I2S_ENABLE_MASK 0x40 /* 0x15 <6> */ -#define PIN_MUX_SPI_MODE_MASK 0x10 /* 0x3D <4> */ -#define PIN_MUX_MCLK_EN_CTRL_MASK 0x10 /* 0x82 <4> */ -#define PIN_MUX_MPSYN_EN_CTRL_MASK 0x20 /* 0x82 <5> */ -#define PIN_MUX_MDVAL_EN_CTRL_MASK 0x40 /* 0x82 <6> */ -#define PIN_MUX_MPERR_EN_CTRL_MASK 0x80 /* 0x82 <7> */ -#define PIN_MUX_MDAT_EN_0_MASK 0x10 /* 0x84 <4> */ -#define PIN_MUX_MDAT_EN_1_MASK 0x20 /* 0x84 <5> */ -#define PIN_MUX_MDAT_EN_2_MASK 0x40 /* 0x84 <6> */ -#define PIN_MUX_MDAT_EN_3_MASK 0x80 /* 0x84 <7> */ -#define PIN_MUX_MDAT_EN_4_MASK 0x10 /* 0x89 <4> */ -#define PIN_MUX_MDAT_EN_5_MASK 0x20 /* 0x89 <5> */ -#define PIN_MUX_MDAT_EN_6_MASK 0x40 /* 0x89 <6> */ -#define PIN_MUX_MDAT_EN_7_MASK 0x80 /* 0x89 <7> */ - -int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state, - enum mxl111sf_mux_config pin_mux_config) -{ - u8 r12, r15, r17, r18, r3D, r82, r84, r89; - int ret; - - mxl_debug("(%d)", pin_mux_config); - - ret = mxl111sf_read_reg(state, 0x17, &r17); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_read_reg(state, 0x18, &r18); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_read_reg(state, 0x12, &r12); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_read_reg(state, 0x15, &r15); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_read_reg(state, 0x82, &r82); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_read_reg(state, 0x84, &r84); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_read_reg(state, 0x89, &r89); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_read_reg(state, 0x3D, &r3D); - if (mxl_fail(ret)) - goto fail; - - switch (pin_mux_config) { - case PIN_MUX_TS_OUT_PARALLEL: - /* mpeg_mode = 1 */ - r17 |= PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 1 */ - r18 |= PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 0 */ - r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 0 */ - r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 0 */ - r15 &= ~PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 0 */ - r3D &= ~PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 1 */ - r82 |= PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 1 */ - r82 |= PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 1 */ - r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 1 */ - r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0xF */ - r84 |= 0xF0; - /* mdat_en_ctrl[7:4] = 0xF */ - r89 |= 0xF0; - break; - case PIN_MUX_TS_OUT_SERIAL: - /* mpeg_mode = 1 */ - r17 |= PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 0 */ - r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 1 */ - r18 |= PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 0 */ - r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 0 */ - r15 &= ~PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 0 */ - r3D &= ~PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 1 */ - r82 |= PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 1 */ - r82 |= PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 1 */ - r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 1 */ - r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0xF */ - r84 |= 0xF0; - /* mdat_en_ctrl[7:4] = 0xF */ - r89 |= 0xF0; - break; - case PIN_MUX_GPIO_MODE: - /* mpeg_mode = 0 */ - r17 &= ~PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 0 */ - r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 0 */ - r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 0 */ - r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 0 */ - r15 &= ~PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 0 */ - r3D &= ~PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0x0 */ - r84 &= 0x0F; - /* mdat_en_ctrl[7:4] = 0x0 */ - r89 &= 0x0F; - break; - case PIN_MUX_TS_SERIAL_IN_MODE_0: - /* mpeg_mode = 0 */ - r17 &= ~PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 0 */ - r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 1 */ - r18 |= PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 0 */ - r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 0 */ - r15 &= ~PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 0 */ - r3D &= ~PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0x0 */ - r84 &= 0x0F; - /* mdat_en_ctrl[7:4] = 0x0 */ - r89 &= 0x0F; - break; - case PIN_MUX_TS_SERIAL_IN_MODE_1: - /* mpeg_mode = 0 */ - r17 &= ~PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 0 */ - r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 1 */ - r18 |= PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 1 */ - r3D |= PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 0 */ - r15 &= ~PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 0 */ - r3D &= ~PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0x0 */ - r84 &= 0x0F; - /* mdat_en_ctrl[7:4] = 0x0 */ - r89 &= 0x0F; - break; - case PIN_MUX_TS_SPI_IN_MODE_1: - /* mpeg_mode = 0 */ - r17 &= ~PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 0 */ - r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 1 */ - r18 |= PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 1 */ - r3D |= PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 1 */ - r15 |= PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 1 */ - r3D |= PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0x0 */ - r84 &= 0x0F; - /* mdat_en_ctrl[7:4] = 0x0 */ - r89 &= 0x0F; - break; - case PIN_MUX_TS_SPI_IN_MODE_0: - /* mpeg_mode = 0 */ - r17 &= ~PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 0 */ - r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 1 */ - r18 |= PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 0 */ - r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 1 */ - r15 |= PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 1 */ - r3D |= PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0x0 */ - r84 &= 0x0F; - /* mdat_en_ctrl[7:4] = 0x0 */ - r89 &= 0x0F; - break; - case PIN_MUX_TS_PARALLEL_IN: - /* mpeg_mode = 0 */ - r17 &= ~PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 1 */ - r18 |= PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 0 */ - r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 0 */ - r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 0 */ - r15 &= ~PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 0 */ - r3D &= ~PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0x0 */ - r84 &= 0x0F; - /* mdat_en_ctrl[7:4] = 0x0 */ - r89 &= 0x0F; - break; - case PIN_MUX_BT656_I2S_MODE: - /* mpeg_mode = 0 */ - r17 &= ~PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 0 */ - r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 0 */ - r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 0 */ - r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 1 */ - r12 |= PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 1 */ - r15 |= PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 0 */ - r3D &= ~PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0x0 */ - r84 &= 0x0F; - /* mdat_en_ctrl[7:4] = 0x0 */ - r89 &= 0x0F; - break; - case PIN_MUX_DEFAULT: - default: - /* mpeg_mode = 1 */ - r17 |= PIN_MUX_MPEG_MODE_MASK; - /* mpeg_par_en = 0 */ - r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; - /* mpeg_ser_en = 0 */ - r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; - /* mpg_in_mux = 0 */ - r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; - /* bt656_enable = 0 */ - r12 &= ~PIN_MUX_BT656_ENABLE_MASK; - /* i2s_enable = 0 */ - r15 &= ~PIN_MUX_I2S_ENABLE_MASK; - /* spi_mode = 0 */ - r3D &= ~PIN_MUX_SPI_MODE_MASK; - /* mclk_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; - /* mperr_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; - /* mdval_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; - /* mpsyn_en_ctrl = 0 */ - r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; - /* mdat_en_ctrl[3:0] = 0x0 */ - r84 &= 0x0F; - /* mdat_en_ctrl[7:4] = 0x0 */ - r89 &= 0x0F; - break; - } - - ret = mxl111sf_write_reg(state, 0x17, r17); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_write_reg(state, 0x18, r18); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_write_reg(state, 0x12, r12); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_write_reg(state, 0x15, r15); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_write_reg(state, 0x82, r82); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_write_reg(state, 0x84, r84); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_write_reg(state, 0x89, r89); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_write_reg(state, 0x3D, r3D); - if (mxl_fail(ret)) - goto fail; -fail: - return ret; -} - -/* ------------------------------------------------------------------------- */ - -static int mxl111sf_hw_set_gpio(struct mxl111sf_state *state, int gpio, int val) -{ - return mxl111sf_hw_do_set_gpio(state, gpio, MXL_GPIO_DIR_OUTPUT, val); -} - -static int mxl111sf_hw_gpio_initialize(struct mxl111sf_state *state) -{ - u8 gpioval = 0x07; /* write protect enabled, signal LEDs off */ - int i, ret; - - mxl_debug("()"); - - for (i = 3; i < 8; i++) { - ret = mxl111sf_hw_set_gpio(state, i, (gpioval >> i) & 0x01); - if (mxl_fail(ret)) - break; - } - - return ret; -} - -#define PCA9534_I2C_ADDR (0x40 >> 1) -static int pca9534_set_gpio(struct mxl111sf_state *state, int gpio, int val) -{ - u8 w[2] = { 1, 0 }; - u8 r = 0; - struct i2c_msg msg[] = { - { .addr = PCA9534_I2C_ADDR, - .flags = 0, .buf = w, .len = 1 }, - { .addr = PCA9534_I2C_ADDR, - .flags = I2C_M_RD, .buf = &r, .len = 1 }, - }; - - mxl_debug("(%d, %d)", gpio, val); - - /* read current GPIO levels from flip-flop */ - i2c_transfer(&state->d->i2c_adap, msg, 2); - - /* prepare write buffer with current GPIO levels */ - msg[0].len = 2; -#if 0 - w[0] = 1; -#endif - w[1] = r; - - /* clear the desired GPIO */ - w[1] &= ~(1 << gpio); - - /* set the desired GPIO value */ - w[1] |= ((val ? 1 : 0) << gpio); - - /* write new GPIO levels to flip-flop */ - i2c_transfer(&state->d->i2c_adap, &msg[0], 1); - - return 0; -} - -static int pca9534_init_port_expander(struct mxl111sf_state *state) -{ - u8 w[2] = { 1, 0x07 }; /* write protect enabled, signal LEDs off */ - - struct i2c_msg msg = { - .addr = PCA9534_I2C_ADDR, - .flags = 0, .buf = w, .len = 2 - }; - - mxl_debug("()"); - - i2c_transfer(&state->d->i2c_adap, &msg, 1); - - /* configure all pins as outputs */ - w[0] = 3; - w[1] = 0; - - i2c_transfer(&state->d->i2c_adap, &msg, 1); - - return 0; -} - -int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val) -{ - mxl_debug("(%d, %d)", gpio, val); - - switch (state->gpio_port_expander) { - default: - mxl_printk(KERN_ERR, - "gpio_port_expander undefined, assuming PCA9534"); - /* fall-thru */ - case mxl111sf_PCA9534: - return pca9534_set_gpio(state, gpio, val); - case mxl111sf_gpio_hw: - return mxl111sf_hw_set_gpio(state, gpio, val); - } -} - -static int mxl111sf_probe_port_expander(struct mxl111sf_state *state) -{ - int ret; - u8 w = 1; - u8 r = 0; - struct i2c_msg msg[] = { - { .flags = 0, .buf = &w, .len = 1 }, - { .flags = I2C_M_RD, .buf = &r, .len = 1 }, - }; - - mxl_debug("()"); - - msg[0].addr = 0x70 >> 1; - msg[1].addr = 0x70 >> 1; - - /* read current GPIO levels from flip-flop */ - ret = i2c_transfer(&state->d->i2c_adap, msg, 2); - if (ret == 2) { - state->port_expander_addr = msg[0].addr; - state->gpio_port_expander = mxl111sf_PCA9534; - mxl_debug("found port expander at 0x%02x", - state->port_expander_addr); - return 0; - } - - msg[0].addr = 0x40 >> 1; - msg[1].addr = 0x40 >> 1; - - ret = i2c_transfer(&state->d->i2c_adap, msg, 2); - if (ret == 2) { - state->port_expander_addr = msg[0].addr; - state->gpio_port_expander = mxl111sf_PCA9534; - mxl_debug("found port expander at 0x%02x", - state->port_expander_addr); - return 0; - } - state->port_expander_addr = 0xff; - state->gpio_port_expander = mxl111sf_gpio_hw; - mxl_debug("using hardware gpio"); - return 0; -} - -int mxl111sf_init_port_expander(struct mxl111sf_state *state) -{ - mxl_debug("()"); - - if (0x00 == state->port_expander_addr) - mxl111sf_probe_port_expander(state); - - switch (state->gpio_port_expander) { - default: - mxl_printk(KERN_ERR, - "gpio_port_expander undefined, assuming PCA9534"); - /* fall-thru */ - case mxl111sf_PCA9534: - return pca9534_init_port_expander(state); - case mxl111sf_gpio_hw: - return mxl111sf_hw_gpio_initialize(state); - } -} - -/* ------------------------------------------------------------------------ */ - -int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode) -{ -/* GPO: - * 3 - ATSC/MH# | 1 = ATSC transport, 0 = MH transport | default 0 - * 4 - ATSC_RST## | 1 = ATSC enable, 0 = ATSC Reset | default 0 - * 5 - ATSC_EN | 1 = ATSC power enable, 0 = ATSC power off | default 0 - * 6 - MH_RESET# | 1 = MH enable, 0 = MH Reset | default 0 - * 7 - MH_EN | 1 = MH power enable, 0 = MH power off | default 0 - */ - mxl_debug("(%d)", mode); - - switch (mode) { - case MXL111SF_GPIO_MOD_MH: - mxl111sf_set_gpio(state, 4, 0); - mxl111sf_set_gpio(state, 5, 0); - msleep(50); - mxl111sf_set_gpio(state, 7, 1); - msleep(50); - mxl111sf_set_gpio(state, 6, 1); - msleep(50); - - mxl111sf_set_gpio(state, 3, 0); - break; - case MXL111SF_GPIO_MOD_ATSC: - mxl111sf_set_gpio(state, 6, 0); - mxl111sf_set_gpio(state, 7, 0); - msleep(50); - mxl111sf_set_gpio(state, 5, 1); - msleep(50); - mxl111sf_set_gpio(state, 4, 1); - msleep(50); - mxl111sf_set_gpio(state, 3, 1); - break; - default: /* DVBT / STANDBY */ - mxl111sf_init_port_expander(state); - break; - } - return 0; -} - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.h b/drivers/media/dvb/dvb-usb/mxl111sf-gpio.h deleted file mode 100644 index 0220f54299a5..000000000000 --- a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * mxl111sf-gpio.h - driver for the MaxLinear MXL111SF - * - * Copyright (C) 2010 Michael Krufky - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _DVB_USB_MXL111SF_GPIO_H_ -#define _DVB_USB_MXL111SF_GPIO_H_ - -#include "mxl111sf.h" - -int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val); -int mxl111sf_init_port_expander(struct mxl111sf_state *state); - -#define MXL111SF_GPIO_MOD_DVBT 0 -#define MXL111SF_GPIO_MOD_MH 1 -#define MXL111SF_GPIO_MOD_ATSC 2 -int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode); - -enum mxl111sf_mux_config { - PIN_MUX_DEFAULT = 0, - PIN_MUX_TS_OUT_PARALLEL, - PIN_MUX_TS_OUT_SERIAL, - PIN_MUX_GPIO_MODE, - PIN_MUX_TS_SERIAL_IN_MODE_0, - PIN_MUX_TS_SERIAL_IN_MODE_1, - PIN_MUX_TS_SPI_IN_MODE_0, - PIN_MUX_TS_SPI_IN_MODE_1, - PIN_MUX_TS_PARALLEL_IN, - PIN_MUX_BT656_I2S_MODE, -}; - -int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state, - enum mxl111sf_mux_config pin_mux_config); - -#endif /* _DVB_USB_MXL111SF_GPIO_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c b/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c deleted file mode 100644 index 34434557ef65..000000000000 --- a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c +++ /dev/null @@ -1,850 +0,0 @@ -/* - * mxl111sf-i2c.c - driver for the MaxLinear MXL111SF - * - * Copyright (C) 2010 Michael Krufky - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "mxl111sf-i2c.h" -#include "mxl111sf.h" - -/* SW-I2C ----------------------------------------------------------------- */ - -#define SW_I2C_ADDR 0x1a -#define SW_I2C_EN 0x02 -#define SW_SCL_OUT 0x04 -#define SW_SDA_OUT 0x08 -#define SW_SDA_IN 0x04 - -#define SW_I2C_BUSY_ADDR 0x2f -#define SW_I2C_BUSY 0x02 - -static int mxl111sf_i2c_bitbang_sendbyte(struct mxl111sf_state *state, - u8 byte) -{ - int i, ret; - u8 data = 0; - - mxl_i2c("(0x%02x)", byte); - - ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data); - if (mxl_fail(ret)) - goto fail; - - for (i = 0; i < 8; i++) { - - data = (byte & (0x80 >> i)) ? SW_SDA_OUT : 0; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | data); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | data | SW_SCL_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | data); - if (mxl_fail(ret)) - goto fail; - } - - /* last bit was 0 so we need to release SDA */ - if (!(byte & 1)) { - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - } - - /* CLK high for ACK readback */ - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data); - if (mxl_fail(ret)) - goto fail; - - /* drop the CLK after getting ACK, SDA will go high right away */ - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - - if (data & SW_SDA_IN) - ret = -EIO; -fail: - return ret; -} - -static int mxl111sf_i2c_bitbang_recvbyte(struct mxl111sf_state *state, - u8 *pbyte) -{ - int i, ret; - u8 byte = 0; - u8 data = 0; - - mxl_i2c("()"); - - *pbyte = 0; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - - for (i = 0; i < 8; i++) { - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | - SW_SCL_OUT | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data); - if (mxl_fail(ret)) - goto fail; - - if (data & SW_SDA_IN) - byte |= (0x80 >> i); - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - } - *pbyte = byte; -fail: - return ret; -} - -static int mxl111sf_i2c_start(struct mxl111sf_state *state) -{ - int ret; - - mxl_i2c("()"); - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SCL_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN); /* start */ - mxl_fail(ret); -fail: - return ret; -} - -static int mxl111sf_i2c_stop(struct mxl111sf_state *state) -{ - int ret; - - mxl_i2c("()"); - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN); /* stop */ - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SCL_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_SCL_OUT | SW_SDA_OUT); - mxl_fail(ret); -fail: - return ret; -} - -static int mxl111sf_i2c_ack(struct mxl111sf_state *state) -{ - int ret; - u8 b = 0; - - mxl_i2c("()"); - - ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &b); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN); - if (mxl_fail(ret)) - goto fail; - - /* pull SDA low */ - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SCL_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SDA_OUT); - mxl_fail(ret); -fail: - return ret; -} - -static int mxl111sf_i2c_nack(struct mxl111sf_state *state) -{ - int ret; - - mxl_i2c("()"); - - /* SDA high to signal last byte read from slave */ - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, SW_I2C_ADDR, - 0x10 | SW_I2C_EN | SW_SDA_OUT); - mxl_fail(ret); -fail: - return ret; -} - -/* ------------------------------------------------------------------------ */ - -static int mxl111sf_i2c_sw_xfer_msg(struct mxl111sf_state *state, - struct i2c_msg *msg) -{ - int i, ret; - - mxl_i2c("()"); - - if (msg->flags & I2C_M_RD) { - - ret = mxl111sf_i2c_start(state); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_i2c_bitbang_sendbyte(state, - (msg->addr << 1) | 0x01); - if (mxl_fail(ret)) { - mxl111sf_i2c_stop(state); - goto fail; - } - - for (i = 0; i < msg->len; i++) { - ret = mxl111sf_i2c_bitbang_recvbyte(state, - &msg->buf[i]); - if (mxl_fail(ret)) { - mxl111sf_i2c_stop(state); - goto fail; - } - - if (i < msg->len - 1) - mxl111sf_i2c_ack(state); - } - - mxl111sf_i2c_nack(state); - - ret = mxl111sf_i2c_stop(state); - if (mxl_fail(ret)) - goto fail; - - } else { - - ret = mxl111sf_i2c_start(state); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_i2c_bitbang_sendbyte(state, - (msg->addr << 1) & 0xfe); - if (mxl_fail(ret)) { - mxl111sf_i2c_stop(state); - goto fail; - } - - for (i = 0; i < msg->len; i++) { - ret = mxl111sf_i2c_bitbang_sendbyte(state, - msg->buf[i]); - if (mxl_fail(ret)) { - mxl111sf_i2c_stop(state); - goto fail; - } - } - - /* FIXME: we only want to do this on the last transaction */ - mxl111sf_i2c_stop(state); - } -fail: - return ret; -} - -/* HW-I2C ----------------------------------------------------------------- */ - -#define USB_WRITE_I2C_CMD 0x99 -#define USB_READ_I2C_CMD 0xdd -#define USB_END_I2C_CMD 0xfe - -#define USB_WRITE_I2C_CMD_LEN 26 -#define USB_READ_I2C_CMD_LEN 24 - -#define I2C_MUX_REG 0x30 -#define I2C_CONTROL_REG 0x00 -#define I2C_SLAVE_ADDR_REG 0x08 -#define I2C_DATA_REG 0x0c -#define I2C_INT_STATUS_REG 0x10 - -static int mxl111sf_i2c_send_data(struct mxl111sf_state *state, - u8 index, u8 *wdata) -{ - int ret = mxl111sf_ctrl_msg(state->d, wdata[0], - &wdata[1], 25, NULL, 0); - mxl_fail(ret); - - return ret; -} - -static int mxl111sf_i2c_get_data(struct mxl111sf_state *state, - u8 index, u8 *wdata, u8 *rdata) -{ - int ret = mxl111sf_ctrl_msg(state->d, wdata[0], - &wdata[1], 25, rdata, 24); - mxl_fail(ret); - - return ret; -} - -static u8 mxl111sf_i2c_check_status(struct mxl111sf_state *state) -{ - u8 status = 0; - u8 buf[26]; - - mxl_i2c_adv("()"); - - buf[0] = USB_READ_I2C_CMD; - buf[1] = 0x00; - - buf[2] = I2C_INT_STATUS_REG; - buf[3] = 0x00; - buf[4] = 0x00; - - buf[5] = USB_END_I2C_CMD; - - mxl111sf_i2c_get_data(state, 0, buf, buf); - - if (buf[1] & 0x04) - status = 1; - - return status; -} - -static u8 mxl111sf_i2c_check_fifo(struct mxl111sf_state *state) -{ - u8 status = 0; - u8 buf[26]; - - mxl_i2c("()"); - - buf[0] = USB_READ_I2C_CMD; - buf[1] = 0x00; - - buf[2] = I2C_MUX_REG; - buf[3] = 0x00; - buf[4] = 0x00; - - buf[5] = I2C_INT_STATUS_REG; - buf[6] = 0x00; - buf[7] = 0x00; - buf[8] = USB_END_I2C_CMD; - - mxl111sf_i2c_get_data(state, 0, buf, buf); - - if (0x08 == (buf[1] & 0x08)) - status = 1; - - if ((buf[5] & 0x02) == 0x02) - mxl_i2c("(buf[5] & 0x02) == 0x02"); /* FIXME */ - - return status; -} - -static int mxl111sf_i2c_readagain(struct mxl111sf_state *state, - u8 count, u8 *rbuf) -{ - u8 i2c_w_data[26]; - u8 i2c_r_data[24]; - u8 i = 0; - u8 fifo_status = 0; - int status = 0; - - mxl_i2c("read %d bytes", count); - - while ((fifo_status == 0) && (i++ < 5)) - fifo_status = mxl111sf_i2c_check_fifo(state); - - i2c_w_data[0] = 0xDD; - i2c_w_data[1] = 0x00; - - for (i = 2; i < 26; i++) - i2c_w_data[i] = 0xFE; - - for (i = 0; i < count; i++) { - i2c_w_data[2+(i*3)] = 0x0C; - i2c_w_data[3+(i*3)] = 0x00; - i2c_w_data[4+(i*3)] = 0x00; - } - - mxl111sf_i2c_get_data(state, 0, i2c_w_data, i2c_r_data); - - /* Check for I2C NACK status */ - if (mxl111sf_i2c_check_status(state) == 1) { - mxl_i2c("error!"); - } else { - for (i = 0; i < count; i++) { - rbuf[i] = i2c_r_data[(i*3)+1]; - mxl_i2c("%02x\t %02x", - i2c_r_data[(i*3)+1], - i2c_r_data[(i*3)+2]); - } - - status = 1; - } - - return status; -} - -#define HWI2C400 1 -static int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state, - struct i2c_msg *msg) -{ - int i, k, ret = 0; - u16 index = 0; - u8 buf[26]; - u8 i2c_r_data[24]; - u16 block_len; - u16 left_over_len; - u8 rd_status[8]; - u8 ret_status; - u8 readbuff[26]; - - mxl_i2c("addr: 0x%02x, read buff len: %d, write buff len: %d", - msg->addr, (msg->flags & I2C_M_RD) ? msg->len : 0, - (!(msg->flags & I2C_M_RD)) ? msg->len : 0); - - for (index = 0; index < 26; index++) - buf[index] = USB_END_I2C_CMD; - - /* command to indicate data payload is destined for I2C interface */ - buf[0] = USB_WRITE_I2C_CMD; - buf[1] = 0x00; - - /* enable I2C interface */ - buf[2] = I2C_MUX_REG; - buf[3] = 0x80; - buf[4] = 0x00; - - /* enable I2C interface */ - buf[5] = I2C_MUX_REG; - buf[6] = 0x81; - buf[7] = 0x00; - - /* set Timeout register on I2C interface */ - buf[8] = 0x14; - buf[9] = 0xff; - buf[10] = 0x00; -#if 0 - /* enable Interrupts on I2C interface */ - buf[8] = 0x24; - buf[9] = 0xF7; - buf[10] = 0x00; -#endif - buf[11] = 0x24; - buf[12] = 0xF7; - buf[13] = 0x00; - - ret = mxl111sf_i2c_send_data(state, 0, buf); - - /* write data on I2C bus */ - if (!(msg->flags & I2C_M_RD) && (msg->len > 0)) { - mxl_i2c("%d\t%02x", msg->len, msg->buf[0]); - - /* control register on I2C interface to initialize I2C bus */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0x5E; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - - /* I2C Slave device Address */ - buf[5] = I2C_SLAVE_ADDR_REG; - buf[6] = (msg->addr); - buf[7] = 0x00; - buf[8] = USB_END_I2C_CMD; - ret = mxl111sf_i2c_send_data(state, 0, buf); - - /* check for slave device status */ - if (mxl111sf_i2c_check_status(state) == 1) { - mxl_i2c("NACK writing slave address %02x", - msg->addr); - /* if NACK, stop I2C bus and exit */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0x4E; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - ret = -EIO; - goto exit; - } - - /* I2C interface can do I2C operations in block of 8 bytes of - I2C data. calculation to figure out number of blocks of i2c - data required to program */ - block_len = (msg->len / 8); - left_over_len = (msg->len % 8); - index = 0; - - mxl_i2c("block_len %d, left_over_len %d", - block_len, left_over_len); - - for (index = 0; index < block_len; index++) { - for (i = 0; i < 8; i++) { - /* write data on I2C interface */ - buf[2+(i*3)] = I2C_DATA_REG; - buf[3+(i*3)] = msg->buf[(index*8)+i]; - buf[4+(i*3)] = 0x00; - } - - ret = mxl111sf_i2c_send_data(state, 0, buf); - - /* check for I2C NACK status */ - if (mxl111sf_i2c_check_status(state) == 1) { - mxl_i2c("NACK writing slave address %02x", - msg->addr); - - /* if NACK, stop I2C bus and exit */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0x4E; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - ret = -EIO; - goto exit; - } - - } - - if (left_over_len) { - for (k = 0; k < 26; k++) - buf[k] = USB_END_I2C_CMD; - - buf[0] = 0x99; - buf[1] = 0x00; - - for (i = 0; i < left_over_len; i++) { - buf[2+(i*3)] = I2C_DATA_REG; - buf[3+(i*3)] = msg->buf[(index*8)+i]; - mxl_i2c("index = %d %d data %d", - index, i, msg->buf[(index*8)+i]); - buf[4+(i*3)] = 0x00; - } - ret = mxl111sf_i2c_send_data(state, 0, buf); - - /* check for I2C NACK status */ - if (mxl111sf_i2c_check_status(state) == 1) { - mxl_i2c("NACK writing slave address %02x", - msg->addr); - - /* if NACK, stop I2C bus and exit */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0x4E; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - ret = -EIO; - goto exit; - } - - } - - /* issue I2C STOP after write */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0x4E; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - - } - - /* read data from I2C bus */ - if ((msg->flags & I2C_M_RD) && (msg->len > 0)) { - mxl_i2c("read buf len %d", msg->len); - - /* command to indicate data payload is - destined for I2C interface */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0xDF; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - - /* I2C xfer length */ - buf[5] = 0x14; - buf[6] = (msg->len & 0xFF); - buf[7] = 0; - - /* I2C slave device Address */ - buf[8] = I2C_SLAVE_ADDR_REG; - buf[9] = msg->addr; - buf[10] = 0x00; - buf[11] = USB_END_I2C_CMD; - ret = mxl111sf_i2c_send_data(state, 0, buf); - - /* check for I2C NACK status */ - if (mxl111sf_i2c_check_status(state) == 1) { - mxl_i2c("NACK reading slave address %02x", - msg->addr); - - /* if NACK, stop I2C bus and exit */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0xC7; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - ret = -EIO; - goto exit; - } - - /* I2C interface can do I2C operations in block of 8 bytes of - I2C data. calculation to figure out number of blocks of - i2c data required to program */ - block_len = ((msg->len) / 8); - left_over_len = ((msg->len) % 8); - index = 0; - - mxl_i2c("block_len %d, left_over_len %d", - block_len, left_over_len); - - /* command to read data from I2C interface */ - buf[0] = USB_READ_I2C_CMD; - buf[1] = 0x00; - - for (index = 0; index < block_len; index++) { - /* setup I2C read request packet on I2C interface */ - for (i = 0; i < 8; i++) { - buf[2+(i*3)] = I2C_DATA_REG; - buf[3+(i*3)] = 0x00; - buf[4+(i*3)] = 0x00; - } - - ret = mxl111sf_i2c_get_data(state, 0, buf, i2c_r_data); - - /* check for I2C NACK status */ - if (mxl111sf_i2c_check_status(state) == 1) { - mxl_i2c("NACK reading slave address %02x", - msg->addr); - - /* if NACK, stop I2C bus and exit */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0xC7; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - ret = -EIO; - goto exit; - } - - /* copy data from i2c data payload to read buffer */ - for (i = 0; i < 8; i++) { - rd_status[i] = i2c_r_data[(i*3)+2]; - - if (rd_status[i] == 0x04) { - if (i < 7) { - mxl_i2c("i2c fifo empty!" - " @ %d", i); - msg->buf[(index*8)+i] = - i2c_r_data[(i*3)+1]; - /* read again */ - ret_status = - mxl111sf_i2c_readagain( - state, 8-(i+1), - readbuff); - if (ret_status == 1) { - for (k = 0; - k < 8-(i+1); - k++) { - - msg->buf[(index*8)+(k+i+1)] = - readbuff[k]; - mxl_i2c("read data: %02x\t %02x", - msg->buf[(index*8)+(k+i)], - (index*8)+(k+i)); - mxl_i2c("read data: %02x\t %02x", - msg->buf[(index*8)+(k+i+1)], - readbuff[k]); - - } - goto stop_copy; - } else { - mxl_i2c("readagain " - "ERROR!"); - } - } else { - msg->buf[(index*8)+i] = - i2c_r_data[(i*3)+1]; - } - } else { - msg->buf[(index*8)+i] = - i2c_r_data[(i*3)+1]; - } - } -stop_copy: - ; - - } - - if (left_over_len) { - for (k = 0; k < 26; k++) - buf[k] = USB_END_I2C_CMD; - - buf[0] = 0xDD; - buf[1] = 0x00; - - for (i = 0; i < left_over_len; i++) { - buf[2+(i*3)] = I2C_DATA_REG; - buf[3+(i*3)] = 0x00; - buf[4+(i*3)] = 0x00; - } - ret = mxl111sf_i2c_get_data(state, 0, buf, - i2c_r_data); - - /* check for I2C NACK status */ - if (mxl111sf_i2c_check_status(state) == 1) { - mxl_i2c("NACK reading slave address %02x", - msg->addr); - - /* if NACK, stop I2C bus and exit */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0xC7; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - ret = -EIO; - goto exit; - } - - for (i = 0; i < left_over_len; i++) { - msg->buf[(block_len*8)+i] = - i2c_r_data[(i*3)+1]; - mxl_i2c("read data: %02x\t %02x", - i2c_r_data[(i*3)+1], - i2c_r_data[(i*3)+2]); - } - } - - /* indicate I2C interface to issue NACK - after next I2C read op */ - buf[0] = USB_WRITE_I2C_CMD; - buf[1] = 0x00; - - /* control register */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0x17; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - - buf[5] = USB_END_I2C_CMD; - ret = mxl111sf_i2c_send_data(state, 0, buf); - - /* control register */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0xC7; - buf[4] = (HWI2C400) ? 0x03 : 0x0D; - - } -exit: - /* STOP and disable I2C MUX */ - buf[0] = USB_WRITE_I2C_CMD; - buf[1] = 0x00; - - /* de-initilize I2C BUS */ - buf[5] = USB_END_I2C_CMD; - mxl111sf_i2c_send_data(state, 0, buf); - - /* Control Register */ - buf[2] = I2C_CONTROL_REG; - buf[3] = 0xDF; - buf[4] = 0x03; - - /* disable I2C interface */ - buf[5] = I2C_MUX_REG; - buf[6] = 0x00; - buf[7] = 0x00; - - /* de-initilize I2C BUS */ - buf[8] = USB_END_I2C_CMD; - mxl111sf_i2c_send_data(state, 0, buf); - - /* disable I2C interface */ - buf[2] = I2C_MUX_REG; - buf[3] = 0x81; - buf[4] = 0x00; - - /* disable I2C interface */ - buf[5] = I2C_MUX_REG; - buf[6] = 0x00; - buf[7] = 0x00; - - /* disable I2C interface */ - buf[8] = I2C_MUX_REG; - buf[9] = 0x00; - buf[10] = 0x00; - - buf[11] = USB_END_I2C_CMD; - mxl111sf_i2c_send_data(state, 0, buf); - - return ret; -} - -/* ------------------------------------------------------------------------ */ - -int mxl111sf_i2c_xfer(struct i2c_adapter *adap, - struct i2c_msg msg[], int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct mxl111sf_state *state = d->priv; - int hwi2c = (state->chip_rev > MXL111SF_V6); - int i, ret; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - ret = (hwi2c) ? - mxl111sf_i2c_hw_xfer_msg(state, &msg[i]) : - mxl111sf_i2c_sw_xfer_msg(state, &msg[i]); - if (mxl_fail(ret)) { - mxl_debug_adv("failed with error %d on i2c " - "transaction %d of %d, %sing %d bytes " - "to/from 0x%02x", ret, i+1, num, - (msg[i].flags & I2C_M_RD) ? - "read" : "writ", - msg[i].len, msg[i].addr); - - break; - } - } - - mutex_unlock(&d->i2c_mutex); - - return i == num ? num : -EREMOTEIO; -} - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.h b/drivers/media/dvb/dvb-usb/mxl111sf-i2c.h deleted file mode 100644 index a57a45ffb9e4..000000000000 --- a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * mxl111sf-i2c.h - driver for the MaxLinear MXL111SF - * - * Copyright (C) 2010 Michael Krufky - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _DVB_USB_MXL111SF_I2C_H_ -#define _DVB_USB_MXL111SF_I2C_H_ - -#include - -int mxl111sf_i2c_xfer(struct i2c_adapter *adap, - struct i2c_msg msg[], int num); - -#endif /* _DVB_USB_MXL111SF_I2C_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-phy.c b/drivers/media/dvb/dvb-usb/mxl111sf-phy.c deleted file mode 100644 index b741b3a7a325..000000000000 --- a/drivers/media/dvb/dvb-usb/mxl111sf-phy.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * mxl111sf-phy.c - driver for the MaxLinear MXL111SF - * - * Copyright (C) 2010 Michael Krufky - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "mxl111sf-phy.h" -#include "mxl111sf-reg.h" - -int mxl111sf_init_tuner_demod(struct mxl111sf_state *state) -{ - struct mxl111sf_reg_ctrl_info mxl_111_overwrite_default[] = { - {0x07, 0xff, 0x0c}, - {0x58, 0xff, 0x9d}, - {0x09, 0xff, 0x00}, - {0x06, 0xff, 0x06}, - {0xc8, 0xff, 0x40}, /* ED_LE_WIN_OLD = 0 */ - {0x8d, 0x01, 0x01}, /* NEGATE_Q */ - {0x32, 0xff, 0xac}, /* DIG_RFREFSELECT = 12 */ - {0x42, 0xff, 0x43}, /* DIG_REG_AMP = 4 */ - {0x74, 0xff, 0xc4}, /* SSPUR_FS_PRIO = 4 */ - {0x71, 0xff, 0xe6}, /* SPUR_ROT_PRIO_VAL = 1 */ - {0x83, 0xff, 0x64}, /* INF_FILT1_THD_SC = 100 */ - {0x85, 0xff, 0x64}, /* INF_FILT2_THD_SC = 100 */ - {0x88, 0xff, 0xf0}, /* INF_THD = 240 */ - {0x6f, 0xf0, 0xb0}, /* DFE_DLY = 11 */ - {0x00, 0xff, 0x01}, /* Change to page 1 */ - {0x81, 0xff, 0x11}, /* DSM_FERR_BYPASS = 1 */ - {0xf4, 0xff, 0x07}, /* DIG_FREQ_CORR = 1 */ - {0xd4, 0x1f, 0x0f}, /* SPUR_TEST_NOISE_TH = 15 */ - {0xd6, 0xff, 0x0c}, /* SPUR_TEST_NOISE_PAPR = 12 */ - {0x00, 0xff, 0x00}, /* Change to page 0 */ - {0, 0, 0} - }; - - mxl_debug("()"); - - return mxl111sf_ctrl_program_regs(state, mxl_111_overwrite_default); -} - -int mxl1x1sf_soft_reset(struct mxl111sf_state *state) -{ - int ret; - mxl_debug("()"); - - ret = mxl111sf_write_reg(state, 0xff, 0x00); /* AIC */ - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_write_reg(state, 0x02, 0x01); /* get out of reset */ - mxl_fail(ret); -fail: - return ret; -} - -int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode) -{ - int ret; - - mxl_debug("(%s)", MXL_SOC_MODE == mode ? - "MXL_SOC_MODE" : "MXL_TUNER_MODE"); - - /* set device mode */ - ret = mxl111sf_write_reg(state, 0x03, - MXL_SOC_MODE == mode ? 0x01 : 0x00); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg_mask(state, - 0x7d, 0x40, MXL_SOC_MODE == mode ? - 0x00 : /* enable impulse noise filter, - INF_BYP = 0 */ - 0x40); /* disable impulse noise filter, - INF_BYP = 1 */ - if (mxl_fail(ret)) - goto fail; - - state->device_mode = mode; -fail: - return ret; -} - -/* power up tuner */ -int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff) -{ - mxl_debug("(%d)", onoff); - - return mxl111sf_write_reg(state, 0x01, onoff ? 0x01 : 0x00); -} - -int mxl111sf_disable_656_port(struct mxl111sf_state *state) -{ - mxl_debug("()"); - - return mxl111sf_write_reg_mask(state, 0x12, 0x04, 0x00); -} - -int mxl111sf_enable_usb_output(struct mxl111sf_state *state) -{ - mxl_debug("()"); - - return mxl111sf_write_reg_mask(state, 0x17, 0x40, 0x00); -} - -/* initialize TSIF as input port of MxL1X1SF for MPEG2 data transfer */ -int mxl111sf_config_mpeg_in(struct mxl111sf_state *state, - unsigned int parallel_serial, - unsigned int msb_lsb_1st, - unsigned int clock_phase, - unsigned int mpeg_valid_pol, - unsigned int mpeg_sync_pol) -{ - int ret; - u8 mode, tmp; - - mxl_debug("(%u,%u,%u,%u,%u)", parallel_serial, msb_lsb_1st, - clock_phase, mpeg_valid_pol, mpeg_sync_pol); - - /* Enable PIN MUX */ - ret = mxl111sf_write_reg(state, V6_PIN_MUX_MODE_REG, V6_ENABLE_PIN_MUX); - mxl_fail(ret); - - /* Configure MPEG Clock phase */ - mxl111sf_read_reg(state, V6_MPEG_IN_CLK_INV_REG, &mode); - - if (clock_phase == TSIF_NORMAL) - mode &= ~V6_INVERTED_CLK_PHASE; - else - mode |= V6_INVERTED_CLK_PHASE; - - ret = mxl111sf_write_reg(state, V6_MPEG_IN_CLK_INV_REG, mode); - mxl_fail(ret); - - /* Configure data input mode, MPEG Valid polarity, MPEG Sync polarity - * Get current configuration */ - ret = mxl111sf_read_reg(state, V6_MPEG_IN_CTRL_REG, &mode); - mxl_fail(ret); - - /* Data Input mode */ - if (parallel_serial == TSIF_INPUT_PARALLEL) { - /* Disable serial mode */ - mode &= ~V6_MPEG_IN_DATA_SERIAL; - - /* Enable Parallel mode */ - mode |= V6_MPEG_IN_DATA_PARALLEL; - } else { - /* Disable Parallel mode */ - mode &= ~V6_MPEG_IN_DATA_PARALLEL; - - /* Enable Serial Mode */ - mode |= V6_MPEG_IN_DATA_SERIAL; - - /* If serial interface is chosen, configure - MSB or LSB order in transmission */ - ret = mxl111sf_read_reg(state, - V6_MPEG_INOUT_BIT_ORDER_CTRL_REG, - &tmp); - mxl_fail(ret); - - if (msb_lsb_1st == MPEG_SER_MSB_FIRST_ENABLED) - tmp |= V6_MPEG_SER_MSB_FIRST; - else - tmp &= ~V6_MPEG_SER_MSB_FIRST; - - ret = mxl111sf_write_reg(state, - V6_MPEG_INOUT_BIT_ORDER_CTRL_REG, - tmp); - mxl_fail(ret); - } - - /* MPEG Sync polarity */ - if (mpeg_sync_pol == TSIF_NORMAL) - mode &= ~V6_INVERTED_MPEG_SYNC; - else - mode |= V6_INVERTED_MPEG_SYNC; - - /* MPEG Valid polarity */ - if (mpeg_valid_pol == 0) - mode &= ~V6_INVERTED_MPEG_VALID; - else - mode |= V6_INVERTED_MPEG_VALID; - - ret = mxl111sf_write_reg(state, V6_MPEG_IN_CTRL_REG, mode); - mxl_fail(ret); - - return ret; -} - -int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size) -{ - static struct mxl111sf_reg_ctrl_info init_i2s[] = { - {0x1b, 0xff, 0x1e}, /* pin mux mode, Choose 656/I2S input */ - {0x15, 0x60, 0x60}, /* Enable I2S */ - {0x17, 0xe0, 0x20}, /* Input, MPEG MODE USB, - Inverted 656 Clock, I2S_SOFT_RESET, - 0 : Normal operation, 1 : Reset State */ -#if 0 - {0x12, 0x01, 0x00}, /* AUDIO_IRQ_CLR (Overflow Indicator) */ -#endif - {0x00, 0xff, 0x02}, /* Change to Control Page */ - {0x26, 0x0d, 0x0d}, /* I2S_MODE & BT656_SRC_SEL for FPGA only */ - {0x00, 0xff, 0x00}, - {0, 0, 0} - }; - int ret; - - mxl_debug("(0x%02x)", sample_size); - - ret = mxl111sf_ctrl_program_regs(state, init_i2s); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, V6_I2S_NUM_SAMPLES_REG, sample_size); - mxl_fail(ret); -fail: - return ret; -} - -int mxl111sf_disable_i2s_port(struct mxl111sf_state *state) -{ - static struct mxl111sf_reg_ctrl_info disable_i2s[] = { - {0x15, 0x40, 0x00}, - {0, 0, 0} - }; - - mxl_debug("()"); - - return mxl111sf_ctrl_program_regs(state, disable_i2s); -} - -int mxl111sf_config_i2s(struct mxl111sf_state *state, - u8 msb_start_pos, u8 data_width) -{ - int ret; - u8 tmp; - - mxl_debug("(0x%02x, 0x%02x)", msb_start_pos, data_width); - - ret = mxl111sf_read_reg(state, V6_I2S_STREAM_START_BIT_REG, &tmp); - if (mxl_fail(ret)) - goto fail; - - tmp &= 0xe0; - tmp |= msb_start_pos; - ret = mxl111sf_write_reg(state, V6_I2S_STREAM_START_BIT_REG, tmp); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_read_reg(state, V6_I2S_STREAM_END_BIT_REG, &tmp); - if (mxl_fail(ret)) - goto fail; - - tmp &= 0xe0; - tmp |= data_width; - ret = mxl111sf_write_reg(state, V6_I2S_STREAM_END_BIT_REG, tmp); - mxl_fail(ret); -fail: - return ret; -} - -int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff) -{ - u8 val; - int ret; - - mxl_debug("(%d)", onoff); - - ret = mxl111sf_write_reg(state, 0x00, 0x02); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_read_reg(state, V8_SPI_MODE_REG, &val); - if (mxl_fail(ret)) - goto fail; - - if (onoff) - val |= 0x04; - else - val &= ~0x04; - - ret = mxl111sf_write_reg(state, V8_SPI_MODE_REG, val); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_write_reg(state, 0x00, 0x00); - mxl_fail(ret); -fail: - return ret; -} - -int mxl111sf_idac_config(struct mxl111sf_state *state, - u8 control_mode, u8 current_setting, - u8 current_value, u8 hysteresis_value) -{ - int ret; - u8 val; - /* current value will be set for both automatic & manual IDAC control */ - val = current_value; - - if (control_mode == IDAC_MANUAL_CONTROL) { - /* enable manual control of IDAC */ - val |= IDAC_MANUAL_CONTROL_BIT_MASK; - - if (current_setting == IDAC_CURRENT_SINKING_ENABLE) - /* enable current sinking in manual mode */ - val |= IDAC_CURRENT_SINKING_BIT_MASK; - else - /* disable current sinking in manual mode */ - val &= ~IDAC_CURRENT_SINKING_BIT_MASK; - } else { - /* disable manual control of IDAC */ - val &= ~IDAC_MANUAL_CONTROL_BIT_MASK; - - /* set hysteresis value reg: 0x0B<5:0> */ - ret = mxl111sf_write_reg(state, V6_IDAC_HYSTERESIS_REG, - (hysteresis_value & 0x3F)); - mxl_fail(ret); - } - - ret = mxl111sf_write_reg(state, V6_IDAC_SETTINGS_REG, val); - mxl_fail(ret); - - return ret; -} - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-phy.h b/drivers/media/dvb/dvb-usb/mxl111sf-phy.h deleted file mode 100644 index f0756071d347..000000000000 --- a/drivers/media/dvb/dvb-usb/mxl111sf-phy.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * mxl111sf-phy.h - driver for the MaxLinear MXL111SF - * - * Copyright (C) 2010 Michael Krufky - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _DVB_USB_MXL111SF_PHY_H_ -#define _DVB_USB_MXL111SF_PHY_H_ - -#include "mxl111sf.h" - -int mxl1x1sf_soft_reset(struct mxl111sf_state *state); -int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode); -int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff); -int mxl111sf_disable_656_port(struct mxl111sf_state *state); -int mxl111sf_init_tuner_demod(struct mxl111sf_state *state); -int mxl111sf_enable_usb_output(struct mxl111sf_state *state); -int mxl111sf_config_mpeg_in(struct mxl111sf_state *state, - unsigned int parallel_serial, - unsigned int msb_lsb_1st, - unsigned int clock_phase, - unsigned int mpeg_valid_pol, - unsigned int mpeg_sync_pol); -int mxl111sf_config_i2s(struct mxl111sf_state *state, - u8 msb_start_pos, u8 data_width); -int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size); -int mxl111sf_disable_i2s_port(struct mxl111sf_state *state); -int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff); -int mxl111sf_idac_config(struct mxl111sf_state *state, - u8 control_mode, u8 current_setting, - u8 current_value, u8 hysteresis_value); - -#endif /* _DVB_USB_MXL111SF_PHY_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-reg.h b/drivers/media/dvb/dvb-usb/mxl111sf-reg.h deleted file mode 100644 index 17831b0fb9db..000000000000 --- a/drivers/media/dvb/dvb-usb/mxl111sf-reg.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * mxl111sf-reg.h - driver for the MaxLinear MXL111SF - * - * Copyright (C) 2010 Michael Krufky - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _DVB_USB_MXL111SF_REG_H_ -#define _DVB_USB_MXL111SF_REG_H_ - -#define CHIP_ID_REG 0xFC -#define TOP_CHIP_REV_ID_REG 0xFA - -#define V6_SNR_RB_LSB_REG 0x27 -#define V6_SNR_RB_MSB_REG 0x28 - -#define V6_N_ACCUMULATE_REG 0x11 -#define V6_RS_AVG_ERRORS_LSB_REG 0x2C -#define V6_RS_AVG_ERRORS_MSB_REG 0x2D - -#define V6_IRQ_STATUS_REG 0x24 -#define IRQ_MASK_FEC_LOCK 0x10 - -#define V6_SYNC_LOCK_REG 0x28 -#define SYNC_LOCK_MASK 0x10 - -#define V6_RS_LOCK_DET_REG 0x28 -#define RS_LOCK_DET_MASK 0x08 - -#define V6_INITACQ_NODETECT_REG 0x20 -#define V6_FORCE_NFFT_CPSIZE_REG 0x20 - -#define V6_CODE_RATE_TPS_REG 0x29 -#define V6_CODE_RATE_TPS_MASK 0x07 - - -#define V6_CP_LOCK_DET_REG 0x28 -#define V6_CP_LOCK_DET_MASK 0x04 - -#define V6_TPS_HIERACHY_REG 0x29 -#define V6_TPS_HIERARCHY_INFO_MASK 0x40 - -#define V6_MODORDER_TPS_REG 0x2A -#define V6_PARAM_CONSTELLATION_MASK 0x30 - -#define V6_MODE_TPS_REG 0x2A -#define V6_PARAM_FFT_MODE_MASK 0x0C - - -#define V6_CP_TPS_REG 0x29 -#define V6_PARAM_GI_MASK 0x30 - -#define V6_TPS_LOCK_REG 0x2A -#define V6_PARAM_TPS_LOCK_MASK 0x40 - -#define V6_FEC_PER_COUNT_REG 0x2E -#define V6_FEC_PER_SCALE_REG 0x2B -#define V6_FEC_PER_SCALE_MASK 0x03 -#define V6_FEC_PER_CLR_REG 0x20 -#define V6_FEC_PER_CLR_MASK 0x01 - -#define V6_PIN_MUX_MODE_REG 0x1B -#define V6_ENABLE_PIN_MUX 0x1E - -#define V6_I2S_NUM_SAMPLES_REG 0x16 - -#define V6_MPEG_IN_CLK_INV_REG 0x17 -#define V6_MPEG_IN_CTRL_REG 0x18 - -#define V6_INVERTED_CLK_PHASE 0x20 -#define V6_MPEG_IN_DATA_PARALLEL 0x01 -#define V6_MPEG_IN_DATA_SERIAL 0x02 - -#define V6_INVERTED_MPEG_SYNC 0x04 -#define V6_INVERTED_MPEG_VALID 0x08 - -#define TSIF_INPUT_PARALLEL 0 -#define TSIF_INPUT_SERIAL 1 -#define TSIF_NORMAL 0 - -#define V6_MPEG_INOUT_BIT_ORDER_CTRL_REG 0x19 -#define V6_MPEG_SER_MSB_FIRST 0x80 -#define MPEG_SER_MSB_FIRST_ENABLED 0x01 - -#define V6_656_I2S_BUFF_STATUS_REG 0x2F -#define V6_656_OVERFLOW_MASK_BIT 0x08 -#define V6_I2S_OVERFLOW_MASK_BIT 0x01 - -#define V6_I2S_STREAM_START_BIT_REG 0x14 -#define V6_I2S_STREAM_END_BIT_REG 0x15 -#define I2S_RIGHT_JUSTIFIED 0 -#define I2S_LEFT_JUSTIFIED 1 -#define I2S_DATA_FORMAT 2 - -#define V6_TUNER_LOOP_THRU_CONTROL_REG 0x09 -#define V6_ENABLE_LOOP_THRU 0x01 - -#define TOTAL_NUM_IF_OUTPUT_FREQ 16 - -#define TUNER_NORMAL_IF_SPECTRUM 0x0 -#define TUNER_INVERT_IF_SPECTRUM 0x10 - -#define V6_TUNER_IF_SEL_REG 0x06 -#define V6_TUNER_IF_FCW_REG 0x3C -#define V6_TUNER_IF_FCW_BYP_REG 0x3D -#define V6_RF_LOCK_STATUS_REG 0x23 - -#define NUM_DIG_TV_CHANNEL 1000 - -#define V6_DIG_CLK_FREQ_SEL_REG 0x07 -#define V6_REF_SYNTH_INT_REG 0x5C -#define V6_REF_SYNTH_REMAIN_REG 0x58 -#define V6_DIG_RFREFSELECT_REG 0x32 -#define V6_XTAL_CLK_OUT_GAIN_REG 0x31 -#define V6_TUNER_LOOP_THRU_CTRL_REG 0x09 -#define V6_DIG_XTAL_ENABLE_REG 0x06 -#define V6_DIG_XTAL_BIAS_REG 0x66 -#define V6_XTAL_CAP_REG 0x08 - -#define V6_GPO_CTRL_REG 0x18 -#define MXL_GPO_0 0x00 -#define MXL_GPO_1 0x01 -#define V6_GPO_0_MASK 0x10 -#define V6_GPO_1_MASK 0x20 - -#define V6_111SF_GPO_CTRL_REG 0x19 -#define MXL_111SF_GPO_1 0x00 -#define MXL_111SF_GPO_2 0x01 -#define MXL_111SF_GPO_3 0x02 -#define MXL_111SF_GPO_4 0x03 -#define MXL_111SF_GPO_5 0x04 -#define MXL_111SF_GPO_6 0x05 -#define MXL_111SF_GPO_7 0x06 - -#define MXL_111SF_GPO_0_MASK 0x01 -#define MXL_111SF_GPO_1_MASK 0x02 -#define MXL_111SF_GPO_2_MASK 0x04 -#define MXL_111SF_GPO_3_MASK 0x08 -#define MXL_111SF_GPO_4_MASK 0x10 -#define MXL_111SF_GPO_5_MASK 0x20 -#define MXL_111SF_GPO_6_MASK 0x40 - -#define V6_ATSC_CONFIG_REG 0x0A - -#define MXL_MODE_REG 0x03 -#define START_TUNE_REG 0x1C - -#define V6_IDAC_HYSTERESIS_REG 0x0B -#define V6_IDAC_SETTINGS_REG 0x0C -#define IDAC_MANUAL_CONTROL 1 -#define IDAC_CURRENT_SINKING_ENABLE 1 -#define IDAC_MANUAL_CONTROL_BIT_MASK 0x80 -#define IDAC_CURRENT_SINKING_BIT_MASK 0x40 - -#define V8_SPI_MODE_REG 0xE9 - -#define V6_DIG_RF_PWR_LSB_REG 0x46 -#define V6_DIG_RF_PWR_MSB_REG 0x47 - -#endif /* _DVB_USB_MXL111SF_REG_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c deleted file mode 100644 index ef4c65fcbb73..000000000000 --- a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - * mxl111sf-tuner.c - driver for the MaxLinear MXL111SF CMOS tuner - * - * Copyright (C) 2010 Michael Krufky - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "mxl111sf-tuner.h" -#include "mxl111sf-phy.h" -#include "mxl111sf-reg.h" - -/* debug */ -static int mxl111sf_tuner_debug; -module_param_named(debug, mxl111sf_tuner_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); - -#define mxl_dbg(fmt, arg...) \ - if (mxl111sf_tuner_debug) \ - mxl_printk(KERN_DEBUG, fmt, ##arg) - -#define err pr_err - -/* ------------------------------------------------------------------------ */ - -struct mxl111sf_tuner_state { - struct mxl111sf_state *mxl_state; - - struct mxl111sf_tuner_config *cfg; - - enum mxl_if_freq if_freq; - - u32 frequency; - u32 bandwidth; -}; - -static int mxl111sf_tuner_read_reg(struct mxl111sf_tuner_state *state, - u8 addr, u8 *data) -{ - return (state->cfg->read_reg) ? - state->cfg->read_reg(state->mxl_state, addr, data) : - -EINVAL; -} - -static int mxl111sf_tuner_write_reg(struct mxl111sf_tuner_state *state, - u8 addr, u8 data) -{ - return (state->cfg->write_reg) ? - state->cfg->write_reg(state->mxl_state, addr, data) : - -EINVAL; -} - -static int mxl111sf_tuner_program_regs(struct mxl111sf_tuner_state *state, - struct mxl111sf_reg_ctrl_info *ctrl_reg_info) -{ - return (state->cfg->program_regs) ? - state->cfg->program_regs(state->mxl_state, ctrl_reg_info) : - -EINVAL; -} - -static int mxl1x1sf_tuner_top_master_ctrl(struct mxl111sf_tuner_state *state, - int onoff) -{ - return (state->cfg->top_master_ctrl) ? - state->cfg->top_master_ctrl(state->mxl_state, onoff) : - -EINVAL; -} - -/* ------------------------------------------------------------------------ */ - -static struct mxl111sf_reg_ctrl_info mxl_phy_tune_rf[] = { - {0x1d, 0x7f, 0x00}, /* channel bandwidth section 1/2/3, - DIG_MODEINDEX, _A, _CSF, */ - {0x1e, 0xff, 0x00}, /* channel frequency (lo and fractional) */ - {0x1f, 0xff, 0x00}, /* channel frequency (hi for integer portion) */ - {0, 0, 0} -}; - -/* ------------------------------------------------------------------------ */ - -static struct mxl111sf_reg_ctrl_info *mxl111sf_calc_phy_tune_regs(u32 freq, - u8 bw) -{ - u8 filt_bw; - - /* set channel bandwidth */ - switch (bw) { - case 0: /* ATSC */ - filt_bw = 25; - break; - case 1: /* QAM */ - filt_bw = 69; - break; - case 6: - filt_bw = 21; - break; - case 7: - filt_bw = 42; - break; - case 8: - filt_bw = 63; - break; - default: - err("%s: invalid bandwidth setting!", __func__); - return NULL; - } - - /* calculate RF channel */ - freq /= 1000000; - - freq *= 64; -#if 0 - /* do round */ - freq += 0.5; -#endif - /* set bandwidth */ - mxl_phy_tune_rf[0].data = filt_bw; - - /* set RF */ - mxl_phy_tune_rf[1].data = (freq & 0xff); - mxl_phy_tune_rf[2].data = (freq >> 8) & 0xff; - - /* start tune */ - return mxl_phy_tune_rf; -} - -static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state) -{ - int ret; - u8 ctrl; -#if 0 - u16 iffcw; - u32 if_freq; -#endif - mxl_dbg("(IF polarity = %d, IF freq = 0x%02x)", - state->cfg->invert_spectrum, state->cfg->if_freq); - - /* set IF polarity */ - ctrl = state->cfg->invert_spectrum; - - ctrl |= state->cfg->if_freq; - - ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_SEL_REG, ctrl); - if (mxl_fail(ret)) - goto fail; - -#if 0 - if_freq /= 1000000; - - /* do round */ - if_freq += 0.5; - - if (MXL_IF_LO == state->cfg->if_freq) { - ctrl = 0x08; - iffcw = (u16)(if_freq / (108 * 4096)); - } else if (MXL_IF_HI == state->cfg->if_freq) { - ctrl = 0x08; - iffcw = (u16)(if_freq / (216 * 4096)); - } else { - ctrl = 0; - iffcw = 0; - } - - ctrl |= (iffcw >> 8); -#endif - ret = mxl111sf_tuner_read_reg(state, V6_TUNER_IF_FCW_BYP_REG, &ctrl); - if (mxl_fail(ret)) - goto fail; - - ctrl &= 0xf0; - ctrl |= 0x90; - - ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_BYP_REG, ctrl); - if (mxl_fail(ret)) - goto fail; - -#if 0 - ctrl = iffcw & 0x00ff; -#endif - ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl); - if (mxl_fail(ret)) - goto fail; - - state->if_freq = state->cfg->if_freq; -fail: - return ret; -} - -static int mxl1x1sf_tune_rf(struct dvb_frontend *fe, u32 freq, u8 bw) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - static struct mxl111sf_reg_ctrl_info *reg_ctrl_array; - int ret; - u8 mxl_mode; - - mxl_dbg("(freq = %d, bw = 0x%x)", freq, bw); - - /* stop tune */ - ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 0); - if (mxl_fail(ret)) - goto fail; - - /* check device mode */ - ret = mxl111sf_tuner_read_reg(state, MXL_MODE_REG, &mxl_mode); - if (mxl_fail(ret)) - goto fail; - - /* Fill out registers for channel tune */ - reg_ctrl_array = mxl111sf_calc_phy_tune_regs(freq, bw); - if (!reg_ctrl_array) - return -EINVAL; - - ret = mxl111sf_tuner_program_regs(state, reg_ctrl_array); - if (mxl_fail(ret)) - goto fail; - - if ((mxl_mode & MXL_DEV_MODE_MASK) == MXL_TUNER_MODE) { - /* IF tuner mode only */ - mxl1x1sf_tuner_top_master_ctrl(state, 0); - mxl1x1sf_tuner_top_master_ctrl(state, 1); - mxl1x1sf_tuner_set_if_output_freq(state); - } - - ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 1); - if (mxl_fail(ret)) - goto fail; - - if (state->cfg->ant_hunt) - state->cfg->ant_hunt(fe); -fail: - return ret; -} - -static int mxl1x1sf_tuner_get_lock_status(struct mxl111sf_tuner_state *state, - int *rf_synth_lock, - int *ref_synth_lock) -{ - int ret; - u8 data; - - *rf_synth_lock = 0; - *ref_synth_lock = 0; - - ret = mxl111sf_tuner_read_reg(state, V6_RF_LOCK_STATUS_REG, &data); - if (mxl_fail(ret)) - goto fail; - - *ref_synth_lock = ((data & 0x03) == 0x03) ? 1 : 0; - *rf_synth_lock = ((data & 0x0c) == 0x0c) ? 1 : 0; -fail: - return ret; -} - -#if 0 -static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state, - int onoff) -{ - return mxl111sf_tuner_write_reg(state, V6_TUNER_LOOP_THRU_CTRL_REG, - onoff ? 1 : 0); -} -#endif - -/* ------------------------------------------------------------------------ */ - -static int mxl111sf_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u32 delsys = c->delivery_system; - struct mxl111sf_tuner_state *state = fe->tuner_priv; - int ret; - u8 bw; - - mxl_dbg("()"); - - switch (delsys) { - case SYS_ATSC: - case SYS_ATSCMH: - bw = 0; /* ATSC */ - break; - case SYS_DVBC_ANNEX_B: - bw = 1; /* US CABLE */ - break; - case SYS_DVBT: - switch (c->bandwidth_hz) { - case 6000000: - bw = 6; - break; - case 7000000: - bw = 7; - break; - case 8000000: - bw = 8; - break; - default: - err("%s: bandwidth not set!", __func__); - return -EINVAL; - } - break; - default: - err("%s: modulation type not supported!", __func__); - return -EINVAL; - } - ret = mxl1x1sf_tune_rf(fe, c->frequency, bw); - if (mxl_fail(ret)) - goto fail; - - state->frequency = c->frequency; - state->bandwidth = c->bandwidth_hz; -fail: - return ret; -} - -/* ------------------------------------------------------------------------ */ - -#if 0 -static int mxl111sf_tuner_init(struct dvb_frontend *fe) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - int ret; - - /* wake from standby handled by usb driver */ - - return ret; -} - -static int mxl111sf_tuner_sleep(struct dvb_frontend *fe) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - int ret; - - /* enter standby mode handled by usb driver */ - - return ret; -} -#endif - -/* ------------------------------------------------------------------------ */ - -static int mxl111sf_tuner_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - int rf_locked, ref_locked, ret; - - *status = 0; - - ret = mxl1x1sf_tuner_get_lock_status(state, &rf_locked, &ref_locked); - if (mxl_fail(ret)) - goto fail; - mxl_info("%s%s", rf_locked ? "rf locked " : "", - ref_locked ? "ref locked" : ""); - - if ((rf_locked) || (ref_locked)) - *status |= TUNER_STATUS_LOCKED; -fail: - return ret; -} - -static int mxl111sf_get_rf_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - u8 val1, val2; - int ret; - - *strength = 0; - - ret = mxl111sf_tuner_write_reg(state, 0x00, 0x02); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_LSB_REG, &val1); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_MSB_REG, &val2); - if (mxl_fail(ret)) - goto fail; - - *strength = val1 | ((val2 & 0x07) << 8); -fail: - ret = mxl111sf_tuner_write_reg(state, 0x00, 0x00); - mxl_fail(ret); - - return ret; -} - -/* ------------------------------------------------------------------------ */ - -static int mxl111sf_tuner_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - *frequency = state->frequency; - return 0; -} - -static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - *bandwidth = state->bandwidth; - return 0; -} - -static int mxl111sf_tuner_get_if_frequency(struct dvb_frontend *fe, - u32 *frequency) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - - *frequency = 0; - - switch (state->if_freq) { - case MXL_IF_4_0: /* 4.0 MHz */ - *frequency = 4000000; - break; - case MXL_IF_4_5: /* 4.5 MHz */ - *frequency = 4500000; - break; - case MXL_IF_4_57: /* 4.57 MHz */ - *frequency = 4570000; - break; - case MXL_IF_5_0: /* 5.0 MHz */ - *frequency = 5000000; - break; - case MXL_IF_5_38: /* 5.38 MHz */ - *frequency = 5380000; - break; - case MXL_IF_6_0: /* 6.0 MHz */ - *frequency = 6000000; - break; - case MXL_IF_6_28: /* 6.28 MHz */ - *frequency = 6280000; - break; - case MXL_IF_7_2: /* 7.2 MHz */ - *frequency = 7200000; - break; - case MXL_IF_35_25: /* 35.25 MHz */ - *frequency = 35250000; - break; - case MXL_IF_36: /* 36 MHz */ - *frequency = 36000000; - break; - case MXL_IF_36_15: /* 36.15 MHz */ - *frequency = 36150000; - break; - case MXL_IF_44: /* 44 MHz */ - *frequency = 44000000; - break; - } - return 0; -} - -static int mxl111sf_tuner_release(struct dvb_frontend *fe) -{ - struct mxl111sf_tuner_state *state = fe->tuner_priv; - mxl_dbg("()"); - kfree(state); - fe->tuner_priv = NULL; - return 0; -} - -/* ------------------------------------------------------------------------- */ - -static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = { - .info = { - .name = "MaxLinear MxL111SF", -#if 0 - .frequency_min = , - .frequency_max = , - .frequency_step = , -#endif - }, -#if 0 - .init = mxl111sf_tuner_init, - .sleep = mxl111sf_tuner_sleep, -#endif - .set_params = mxl111sf_tuner_set_params, - .get_status = mxl111sf_tuner_get_status, - .get_rf_strength = mxl111sf_get_rf_strength, - .get_frequency = mxl111sf_tuner_get_frequency, - .get_bandwidth = mxl111sf_tuner_get_bandwidth, - .get_if_frequency = mxl111sf_tuner_get_if_frequency, - .release = mxl111sf_tuner_release, -}; - -struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, - struct mxl111sf_state *mxl_state, - struct mxl111sf_tuner_config *cfg) -{ - struct mxl111sf_tuner_state *state = NULL; - - mxl_dbg("()"); - - state = kzalloc(sizeof(struct mxl111sf_tuner_state), GFP_KERNEL); - if (state == NULL) - return NULL; - - state->mxl_state = mxl_state; - state->cfg = cfg; - - memcpy(&fe->ops.tuner_ops, &mxl111sf_tuner_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = state; - return fe; -} -EXPORT_SYMBOL_GPL(mxl111sf_tuner_attach); - -MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver"); -MODULE_AUTHOR("Michael Krufky "); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.1"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.h b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.h deleted file mode 100644 index ff333960b184..000000000000 --- a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * mxl111sf-tuner.h - driver for the MaxLinear MXL111SF CMOS tuner - * - * Copyright (C) 2010 Michael Krufky - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __MXL111SF_TUNER_H__ -#define __MXL111SF_TUNER_H__ - -#include "dvb_frontend.h" - -#include "mxl111sf.h" - -enum mxl_if_freq { -#if 0 - MXL_IF_LO = 0x00, /* other IF < 9MHz */ -#endif - MXL_IF_4_0 = 0x01, /* 4.0 MHz */ - MXL_IF_4_5 = 0x02, /* 4.5 MHz */ - MXL_IF_4_57 = 0x03, /* 4.57 MHz */ - MXL_IF_5_0 = 0x04, /* 5.0 MHz */ - MXL_IF_5_38 = 0x05, /* 5.38 MHz */ - MXL_IF_6_0 = 0x06, /* 6.0 MHz */ - MXL_IF_6_28 = 0x07, /* 6.28 MHz */ - MXL_IF_7_2 = 0x08, /* 7.2 MHz */ - MXL_IF_35_25 = 0x09, /* 35.25 MHz */ - MXL_IF_36 = 0x0a, /* 36 MHz */ - MXL_IF_36_15 = 0x0b, /* 36.15 MHz */ - MXL_IF_44 = 0x0c, /* 44 MHz */ -#if 0 - MXL_IF_HI = 0x0f, /* other IF > 35 MHz and < 45 MHz */ -#endif -}; - -struct mxl111sf_tuner_config { - enum mxl_if_freq if_freq; - unsigned int invert_spectrum:1; - - int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data); - int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data); - int (*program_regs)(struct mxl111sf_state *state, - struct mxl111sf_reg_ctrl_info *ctrl_reg_info); - int (*top_master_ctrl)(struct mxl111sf_state *state, int onoff); - int (*ant_hunt)(struct dvb_frontend *fe); -}; - -/* ------------------------------------------------------------------------ */ - -#if defined(CONFIG_DVB_USB_MXL111SF) || \ - (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE)) -extern -struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, - struct mxl111sf_state *mxl_state, - struct mxl111sf_tuner_config *cfg); -#else -static inline -struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, - struct mxl111sf_state *mxl_state - struct mxl111sf_tuner_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* __MXL111SF_TUNER_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ - diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c deleted file mode 100644 index 1fb017ecee74..000000000000 --- a/drivers/media/dvb/dvb-usb/mxl111sf.c +++ /dev/null @@ -1,1463 +0,0 @@ -/* - * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ - -#include -#include - -#include "mxl111sf.h" -#include "mxl111sf-reg.h" -#include "mxl111sf-phy.h" -#include "mxl111sf-i2c.h" -#include "mxl111sf-gpio.h" - -#include "mxl111sf-demod.h" -#include "mxl111sf-tuner.h" - -#include "lgdt3305.h" -#include "lg2160.h" - -int dvb_usb_mxl111sf_debug; -module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level " - "(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able))."); - -int dvb_usb_mxl111sf_isoc; -module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644); -MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc)."); - -int dvb_usb_mxl111sf_spi; -module_param_named(spi, dvb_usb_mxl111sf_spi, int, 0644); -MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi)."); - -#define ANT_PATH_AUTO 0 -#define ANT_PATH_EXTERNAL 1 -#define ANT_PATH_INTERNAL 2 - -int dvb_usb_mxl111sf_rfswitch = -#if 0 - ANT_PATH_AUTO; -#else - ANT_PATH_EXTERNAL; -#endif - -module_param_named(rfswitch, dvb_usb_mxl111sf_rfswitch, int, 0644); -MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int)."); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define deb_info pr_debug -#define deb_reg pr_debug -#define deb_adv pr_debug -#define err pr_err -#define info pr_info - -int mxl111sf_ctrl_msg(struct dvb_usb_device *d, - u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) -{ - int wo = (rbuf == NULL || rlen == 0); /* write-only */ - int ret; - u8 sndbuf[1+wlen]; - - deb_adv("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen); - - memset(sndbuf, 0, 1+wlen); - - sndbuf[0] = cmd; - memcpy(&sndbuf[1], wbuf, wlen); - - ret = (wo) ? dvb_usbv2_generic_write(d, sndbuf, 1+wlen) : - dvb_usbv2_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen); - mxl_fail(ret); - - return ret; -} - -/* ------------------------------------------------------------------------ */ - -#define MXL_CMD_REG_READ 0xaa -#define MXL_CMD_REG_WRITE 0x55 - -int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data) -{ - u8 buf[2]; - int ret; - - ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_READ, &addr, 1, buf, 2); - if (mxl_fail(ret)) { - mxl_debug("error reading reg: 0x%02x", addr); - goto fail; - } - - if (buf[0] == addr) - *data = buf[1]; - else { - err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x", - addr, buf[0], buf[1]); - ret = -EINVAL; - } - - deb_reg("R: (0x%02x, 0x%02x)\n", addr, *data); -fail: - return ret; -} - -int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data) -{ - u8 buf[] = { addr, data }; - int ret; - - deb_reg("W: (0x%02x, 0x%02x)\n", addr, data); - - ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0); - if (mxl_fail(ret)) - err("error writing reg: 0x%02x, val: 0x%02x", addr, data); - return ret; -} - -/* ------------------------------------------------------------------------ */ - -int mxl111sf_write_reg_mask(struct mxl111sf_state *state, - u8 addr, u8 mask, u8 data) -{ - int ret; - u8 val; - - if (mask != 0xff) { - ret = mxl111sf_read_reg(state, addr, &val); -#if 1 - /* dont know why this usually errors out on the first try */ - if (mxl_fail(ret)) - err("error writing addr: 0x%02x, mask: 0x%02x, " - "data: 0x%02x, retrying...", addr, mask, data); - - ret = mxl111sf_read_reg(state, addr, &val); -#endif - if (mxl_fail(ret)) - goto fail; - } - val &= ~mask; - val |= data; - - ret = mxl111sf_write_reg(state, addr, val); - mxl_fail(ret); -fail: - return ret; -} - -/* ------------------------------------------------------------------------ */ - -int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state, - struct mxl111sf_reg_ctrl_info *ctrl_reg_info) -{ - int i, ret = 0; - - for (i = 0; ctrl_reg_info[i].addr | - ctrl_reg_info[i].mask | - ctrl_reg_info[i].data; i++) { - - ret = mxl111sf_write_reg_mask(state, - ctrl_reg_info[i].addr, - ctrl_reg_info[i].mask, - ctrl_reg_info[i].data); - if (mxl_fail(ret)) { - err("failed on reg #%d (0x%02x)", i, - ctrl_reg_info[i].addr); - break; - } - } - return ret; -} - -/* ------------------------------------------------------------------------ */ - -static int mxl1x1sf_get_chip_info(struct mxl111sf_state *state) -{ - int ret; - u8 id, ver; - char *mxl_chip, *mxl_rev; - - if ((state->chip_id) && (state->chip_ver)) - return 0; - - ret = mxl111sf_read_reg(state, CHIP_ID_REG, &id); - if (mxl_fail(ret)) - goto fail; - state->chip_id = id; - - ret = mxl111sf_read_reg(state, TOP_CHIP_REV_ID_REG, &ver); - if (mxl_fail(ret)) - goto fail; - state->chip_ver = ver; - - switch (id) { - case 0x61: - mxl_chip = "MxL101SF"; - break; - case 0x63: - mxl_chip = "MxL111SF"; - break; - default: - mxl_chip = "UNKNOWN MxL1X1"; - break; - } - switch (ver) { - case 0x36: - state->chip_rev = MXL111SF_V6; - mxl_rev = "v6"; - break; - case 0x08: - state->chip_rev = MXL111SF_V8_100; - mxl_rev = "v8_100"; - break; - case 0x18: - state->chip_rev = MXL111SF_V8_200; - mxl_rev = "v8_200"; - break; - default: - state->chip_rev = 0; - mxl_rev = "UNKNOWN REVISION"; - break; - } - info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver); -fail: - return ret; -} - -#define get_chip_info(state) \ -({ \ - int ___ret; \ - ___ret = mxl1x1sf_get_chip_info(state); \ - if (mxl_fail(___ret)) { \ - mxl_debug("failed to get chip info" \ - " on first probe attempt"); \ - ___ret = mxl1x1sf_get_chip_info(state); \ - if (mxl_fail(___ret)) \ - err("failed to get chip info during probe"); \ - else \ - mxl_debug("probe needed a retry " \ - "in order to succeed."); \ - } \ - ___ret; \ -}) - -/* ------------------------------------------------------------------------ */ -#if 0 -static int mxl111sf_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - /* power control depends on which adapter is being woken: - * save this for init, instead, via mxl111sf_adap_fe_init */ - return 0; -} -#endif - -static int mxl111sf_adap_fe_init(struct dvb_frontend *fe) -{ - struct dvb_usb_device *d = fe_to_d(fe); - struct mxl111sf_state *state = fe_to_priv(fe); - struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id]; - int err; - - /* exit if we didnt initialize the driver yet */ - if (!state->chip_id) { - mxl_debug("driver not yet initialized, exit."); - goto fail; - } - - deb_info("%s()\n", __func__); - - mutex_lock(&state->fe_lock); - - state->alt_mode = adap_state->alt_mode; - - if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) - err("set interface failed"); - - err = mxl1x1sf_soft_reset(state); - mxl_fail(err); - err = mxl111sf_init_tuner_demod(state); - mxl_fail(err); - err = mxl1x1sf_set_device_mode(state, adap_state->device_mode); - - mxl_fail(err); - mxl111sf_enable_usb_output(state); - mxl_fail(err); - mxl1x1sf_top_master_ctrl(state, 1); - mxl_fail(err); - - if ((MXL111SF_GPIO_MOD_DVBT != adap_state->gpio_mode) && - (state->chip_rev > MXL111SF_V6)) { - mxl111sf_config_pin_mux_modes(state, - PIN_MUX_TS_SPI_IN_MODE_1); - mxl_fail(err); - } - err = mxl111sf_init_port_expander(state); - if (!mxl_fail(err)) { - state->gpio_mode = adap_state->gpio_mode; - err = mxl111sf_gpio_mode_switch(state, state->gpio_mode); - mxl_fail(err); -#if 0 - err = fe->ops.init(fe); -#endif - msleep(100); /* add short delay after enabling - * the demod before touching it */ - } - - return (adap_state->fe_init) ? adap_state->fe_init(fe) : 0; -fail: - return -ENODEV; -} - -static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe) -{ - struct mxl111sf_state *state = fe_to_priv(fe); - struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id]; - int err; - - /* exit if we didnt initialize the driver yet */ - if (!state->chip_id) { - mxl_debug("driver not yet initialized, exit."); - goto fail; - } - - deb_info("%s()\n", __func__); - - err = (adap_state->fe_sleep) ? adap_state->fe_sleep(fe) : 0; - - mutex_unlock(&state->fe_lock); - - return err; -fail: - return -ENODEV; -} - - -static int mxl111sf_ep6_streaming_ctrl(struct dvb_frontend *fe, int onoff) -{ - struct mxl111sf_state *state = fe_to_priv(fe); - struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id]; - int ret = 0; - - deb_info("%s(%d)\n", __func__, onoff); - - if (onoff) { - ret = mxl111sf_enable_usb_output(state); - mxl_fail(ret); - ret = mxl111sf_config_mpeg_in(state, 1, 1, - adap_state->ep6_clockphase, - 0, 0); - mxl_fail(ret); -#if 0 - } else { - ret = mxl111sf_disable_656_port(state); - mxl_fail(ret); -#endif - } - - return ret; -} - -static int mxl111sf_ep5_streaming_ctrl(struct dvb_frontend *fe, int onoff) -{ - struct mxl111sf_state *state = fe_to_priv(fe); - int ret = 0; - - deb_info("%s(%d)\n", __func__, onoff); - - if (onoff) { - ret = mxl111sf_enable_usb_output(state); - mxl_fail(ret); - - ret = mxl111sf_init_i2s_port(state, 200); - mxl_fail(ret); - ret = mxl111sf_config_i2s(state, 0, 15); - mxl_fail(ret); - } else { - ret = mxl111sf_disable_i2s_port(state); - mxl_fail(ret); - } - if (state->chip_rev > MXL111SF_V6) - ret = mxl111sf_config_spi(state, onoff); - mxl_fail(ret); - - return ret; -} - -static int mxl111sf_ep4_streaming_ctrl(struct dvb_frontend *fe, int onoff) -{ - struct mxl111sf_state *state = fe_to_priv(fe); - int ret = 0; - - deb_info("%s(%d)\n", __func__, onoff); - - if (onoff) { - ret = mxl111sf_enable_usb_output(state); - mxl_fail(ret); - } - - return ret; -} - -/* ------------------------------------------------------------------------ */ - -static struct lgdt3305_config hauppauge_lgdt3305_config = { - .i2c_addr = 0xb2 >> 1, - .mpeg_mode = LGDT3305_MPEG_SERIAL, - .tpclk_edge = LGDT3305_TPCLK_RISING_EDGE, - .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, - .deny_i2c_rptr = 1, - .spectral_inversion = 0, - .qam_if_khz = 6000, - .vsb_if_khz = 6000, -}; - -static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct mxl111sf_state *state = d_to_priv(d); - struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; - int ret; - - deb_adv("%s()\n", __func__); - - /* save a pointer to the dvb_usb_device in device state */ - state->d = d; - adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; - state->alt_mode = adap_state->alt_mode; - - if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) - err("set interface failed"); - - state->gpio_mode = MXL111SF_GPIO_MOD_ATSC; - adap_state->gpio_mode = state->gpio_mode; - adap_state->device_mode = MXL_TUNER_MODE; - adap_state->ep6_clockphase = 1; - - ret = mxl1x1sf_soft_reset(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_init_tuner_demod(state); - if (mxl_fail(ret)) - goto fail; - - ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_enable_usb_output(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl1x1sf_top_master_ctrl(state, 1); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_init_port_expander(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); - if (mxl_fail(ret)) - goto fail; - - adap->fe[fe_id] = dvb_attach(lgdt3305_attach, - &hauppauge_lgdt3305_config, - &d->i2c_adap); - if (adap->fe[fe_id]) { - state->num_frontends++; - adap_state->fe_init = adap->fe[fe_id]->ops.init; - adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; - adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; - adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; - return 0; - } - ret = -EIO; -fail: - return ret; -} - -static struct lg2160_config hauppauge_lg2160_config = { - .lg_chip = LG2160, - .i2c_addr = 0x1c >> 1, - .deny_i2c_rptr = 1, - .spectral_inversion = 0, - .if_khz = 6000, -}; - -static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct mxl111sf_state *state = d_to_priv(d); - struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; - int ret; - - deb_adv("%s()\n", __func__); - - /* save a pointer to the dvb_usb_device in device state */ - state->d = d; - adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; - state->alt_mode = adap_state->alt_mode; - - if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) - err("set interface failed"); - - state->gpio_mode = MXL111SF_GPIO_MOD_MH; - adap_state->gpio_mode = state->gpio_mode; - adap_state->device_mode = MXL_TUNER_MODE; - adap_state->ep6_clockphase = 1; - - ret = mxl1x1sf_soft_reset(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_init_tuner_demod(state); - if (mxl_fail(ret)) - goto fail; - - ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_enable_usb_output(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl1x1sf_top_master_ctrl(state, 1); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_init_port_expander(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); - if (mxl_fail(ret)) - goto fail; - - ret = get_chip_info(state); - if (mxl_fail(ret)) - goto fail; - - adap->fe[fe_id] = dvb_attach(lg2160_attach, - &hauppauge_lg2160_config, - &d->i2c_adap); - if (adap->fe[fe_id]) { - state->num_frontends++; - adap_state->fe_init = adap->fe[fe_id]->ops.init; - adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; - adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; - adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; - return 0; - } - ret = -EIO; -fail: - return ret; -} - -static struct lg2160_config hauppauge_lg2161_1019_config = { - .lg_chip = LG2161_1019, - .i2c_addr = 0x1c >> 1, - .deny_i2c_rptr = 1, - .spectral_inversion = 0, - .if_khz = 6000, - .output_if = 2, /* LG2161_OIF_SPI_MAS */ -}; - -static struct lg2160_config hauppauge_lg2161_1040_config = { - .lg_chip = LG2161_1040, - .i2c_addr = 0x1c >> 1, - .deny_i2c_rptr = 1, - .spectral_inversion = 0, - .if_khz = 6000, - .output_if = 4, /* LG2161_OIF_SPI_MAS */ -}; - -static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct mxl111sf_state *state = d_to_priv(d); - struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; - int ret; - - deb_adv("%s()\n", __func__); - - /* save a pointer to the dvb_usb_device in device state */ - state->d = d; - adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; - state->alt_mode = adap_state->alt_mode; - - if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) - err("set interface failed"); - - state->gpio_mode = MXL111SF_GPIO_MOD_MH; - adap_state->gpio_mode = state->gpio_mode; - adap_state->device_mode = MXL_TUNER_MODE; - adap_state->ep6_clockphase = 1; - - ret = mxl1x1sf_soft_reset(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_init_tuner_demod(state); - if (mxl_fail(ret)) - goto fail; - - ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_enable_usb_output(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl1x1sf_top_master_ctrl(state, 1); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_init_port_expander(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); - if (mxl_fail(ret)) - goto fail; - - ret = get_chip_info(state); - if (mxl_fail(ret)) - goto fail; - - adap->fe[fe_id] = dvb_attach(lg2160_attach, - (MXL111SF_V8_200 == state->chip_rev) ? - &hauppauge_lg2161_1040_config : - &hauppauge_lg2161_1019_config, - &d->i2c_adap); - if (adap->fe[fe_id]) { - state->num_frontends++; - adap_state->fe_init = adap->fe[fe_id]->ops.init; - adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; - adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; - adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; - return 0; - } - ret = -EIO; -fail: - return ret; -} - -static struct lg2160_config hauppauge_lg2161_1019_ep6_config = { - .lg_chip = LG2161_1019, - .i2c_addr = 0x1c >> 1, - .deny_i2c_rptr = 1, - .spectral_inversion = 0, - .if_khz = 6000, - .output_if = 1, /* LG2161_OIF_SERIAL_TS */ -}; - -static struct lg2160_config hauppauge_lg2161_1040_ep6_config = { - .lg_chip = LG2161_1040, - .i2c_addr = 0x1c >> 1, - .deny_i2c_rptr = 1, - .spectral_inversion = 0, - .if_khz = 6000, - .output_if = 7, /* LG2161_OIF_SERIAL_TS */ -}; - -static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct mxl111sf_state *state = d_to_priv(d); - struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; - int ret; - - deb_adv("%s()\n", __func__); - - /* save a pointer to the dvb_usb_device in device state */ - state->d = d; - adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; - state->alt_mode = adap_state->alt_mode; - - if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) - err("set interface failed"); - - state->gpio_mode = MXL111SF_GPIO_MOD_MH; - adap_state->gpio_mode = state->gpio_mode; - adap_state->device_mode = MXL_TUNER_MODE; - adap_state->ep6_clockphase = 0; - - ret = mxl1x1sf_soft_reset(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_init_tuner_demod(state); - if (mxl_fail(ret)) - goto fail; - - ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_enable_usb_output(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl1x1sf_top_master_ctrl(state, 1); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_init_port_expander(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); - if (mxl_fail(ret)) - goto fail; - - ret = get_chip_info(state); - if (mxl_fail(ret)) - goto fail; - - adap->fe[fe_id] = dvb_attach(lg2160_attach, - (MXL111SF_V8_200 == state->chip_rev) ? - &hauppauge_lg2161_1040_ep6_config : - &hauppauge_lg2161_1019_ep6_config, - &d->i2c_adap); - if (adap->fe[fe_id]) { - state->num_frontends++; - adap_state->fe_init = adap->fe[fe_id]->ops.init; - adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; - adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; - adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; - return 0; - } - ret = -EIO; -fail: - return ret; -} - -static struct mxl111sf_demod_config mxl_demod_config = { - .read_reg = mxl111sf_read_reg, - .write_reg = mxl111sf_write_reg, - .program_regs = mxl111sf_ctrl_program_regs, -}; - -static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap, u8 fe_id) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct mxl111sf_state *state = d_to_priv(d); - struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; - int ret; - - deb_adv("%s()\n", __func__); - - /* save a pointer to the dvb_usb_device in device state */ - state->d = d; - adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 1 : 2; - state->alt_mode = adap_state->alt_mode; - - if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) - err("set interface failed"); - - state->gpio_mode = MXL111SF_GPIO_MOD_DVBT; - adap_state->gpio_mode = state->gpio_mode; - adap_state->device_mode = MXL_SOC_MODE; - adap_state->ep6_clockphase = 1; - - ret = mxl1x1sf_soft_reset(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl111sf_init_tuner_demod(state); - if (mxl_fail(ret)) - goto fail; - - ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); - if (mxl_fail(ret)) - goto fail; - - ret = mxl111sf_enable_usb_output(state); - if (mxl_fail(ret)) - goto fail; - ret = mxl1x1sf_top_master_ctrl(state, 1); - if (mxl_fail(ret)) - goto fail; - - /* dont care if this fails */ - mxl111sf_init_port_expander(state); - - adap->fe[fe_id] = dvb_attach(mxl111sf_demod_attach, state, - &mxl_demod_config); - if (adap->fe[fe_id]) { - state->num_frontends++; - adap_state->fe_init = adap->fe[fe_id]->ops.init; - adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; - adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; - adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; - return 0; - } - ret = -EIO; -fail: - return ret; -} - -static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state, - int antpath) -{ - return mxl111sf_idac_config(state, 1, 1, - (antpath == ANT_PATH_INTERNAL) ? - 0x3f : 0x00, 0); -} - -#define DbgAntHunt(x, pwr0, pwr1, pwr2, pwr3) \ - err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \ - __func__, __LINE__, \ - (ANT_PATH_EXTERNAL == x) ? "EXTERNAL" : "INTERNAL", \ - pwr0, pwr1, pwr2, pwr3) - -#define ANT_HUNT_SLEEP 90 -#define ANT_EXT_TWEAK 0 - -static int mxl111sf_ant_hunt(struct dvb_frontend *fe) -{ - struct mxl111sf_state *state = fe_to_priv(fe); - int antctrl = dvb_usb_mxl111sf_rfswitch; - - u16 rxPwrA, rxPwr0, rxPwr1, rxPwr2; - - /* FIXME: must force EXTERNAL for QAM - done elsewhere */ - mxl111sf_set_ant_path(state, antctrl == ANT_PATH_AUTO ? - ANT_PATH_EXTERNAL : antctrl); - - if (antctrl == ANT_PATH_AUTO) { -#if 0 - msleep(ANT_HUNT_SLEEP); -#endif - fe->ops.tuner_ops.get_rf_strength(fe, &rxPwrA); - - mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); - msleep(ANT_HUNT_SLEEP); - fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr0); - - mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); - msleep(ANT_HUNT_SLEEP); - fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr1); - - mxl111sf_set_ant_path(state, ANT_PATH_INTERNAL); - msleep(ANT_HUNT_SLEEP); - fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr2); - - if (rxPwr1+ANT_EXT_TWEAK >= rxPwr2) { - /* return with EXTERNAL enabled */ - mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); - DbgAntHunt(ANT_PATH_EXTERNAL, rxPwrA, - rxPwr0, rxPwr1, rxPwr2); - } else { - /* return with INTERNAL enabled */ - DbgAntHunt(ANT_PATH_INTERNAL, rxPwrA, - rxPwr0, rxPwr1, rxPwr2); - } - } - return 0; -} - -static struct mxl111sf_tuner_config mxl_tuner_config = { - .if_freq = MXL_IF_6_0, /* applies to external IF output, only */ - .invert_spectrum = 0, - .read_reg = mxl111sf_read_reg, - .write_reg = mxl111sf_write_reg, - .program_regs = mxl111sf_ctrl_program_regs, - .top_master_ctrl = mxl1x1sf_top_master_ctrl, - .ant_hunt = mxl111sf_ant_hunt, -}; - -static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap) -{ - struct mxl111sf_state *state = adap_to_priv(adap); - int i; - - deb_adv("%s()\n", __func__); - - for (i = 0; i < state->num_frontends; i++) { - if (dvb_attach(mxl111sf_tuner_attach, adap->fe[i], state, - &mxl_tuner_config) == NULL) - return -EIO; - } - - return 0; -} - -static int mxl111sf_fe_ioctl_override(struct dvb_frontend *fe, - unsigned int cmd, void *parg, - unsigned int stage) -{ - int err = 0; - - switch (stage) { - case DVB_FE_IOCTL_PRE: - - switch (cmd) { - case FE_READ_SIGNAL_STRENGTH: - err = fe->ops.tuner_ops.get_rf_strength(fe, parg); - /* If no error occurs, prevent dvb-core from handling - * this IOCTL, otherwise return the error */ - if (0 == err) - err = 1; - break; - } - break; - - case DVB_FE_IOCTL_POST: - /* no post-ioctl handling required */ - break; - } - return err; -}; - -static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -struct i2c_algorithm mxl111sf_i2c_algo = { - .master_xfer = mxl111sf_i2c_xfer, - .functionality = mxl111sf_i2c_func, -#ifdef NEED_ALGO_CONTROL - .algo_control = dummy_algo_control, -#endif -}; - -static int mxl111sf_init(struct dvb_usb_device *d) -{ - struct mxl111sf_state *state = d_to_priv(d); - int ret; - static u8 eeprom[256]; - struct i2c_client c; - - ret = get_chip_info(state); - if (mxl_fail(ret)) - err("failed to get chip info during probe"); - - mutex_init(&state->fe_lock); - - if (state->chip_rev > MXL111SF_V6) - mxl111sf_config_pin_mux_modes(state, PIN_MUX_TS_SPI_IN_MODE_1); - - c.adapter = &d->i2c_adap; - c.addr = 0xa0 >> 1; - - ret = tveeprom_read(&c, eeprom, sizeof(eeprom)); - if (mxl_fail(ret)) - return 0; - tveeprom_hauppauge_analog(&c, &state->tv, (0x84 == eeprom[0xa0]) ? - eeprom + 0xa0 : eeprom + 0x80); -#if 0 - switch (state->tv.model) { - case 117001: - case 126001: - case 138001: - break; - default: - printk(KERN_WARNING "%s: warning: " - "unknown hauppauge model #%d\n", - __func__, state->tv.model); - } -#endif - return 0; -} - -static int mxl111sf_frontend_attach_dvbt(struct dvb_usb_adapter *adap) -{ - return mxl111sf_attach_demod(adap, 0); -} - -static int mxl111sf_frontend_attach_atsc(struct dvb_usb_adapter *adap) -{ - return mxl111sf_lgdt3305_frontend_attach(adap, 0); -} - -static int mxl111sf_frontend_attach_mh(struct dvb_usb_adapter *adap) -{ - return mxl111sf_lg2160_frontend_attach(adap, 0); -} - -static int mxl111sf_frontend_attach_atsc_mh(struct dvb_usb_adapter *adap) -{ - int ret; - deb_info("%s\n", __func__); - - ret = mxl111sf_lgdt3305_frontend_attach(adap, 0); - if (ret < 0) - return ret; - - ret = mxl111sf_attach_demod(adap, 1); - if (ret < 0) - return ret; - - ret = mxl111sf_lg2160_frontend_attach(adap, 2); - if (ret < 0) - return ret; - - return ret; -} - -static int mxl111sf_frontend_attach_mercury(struct dvb_usb_adapter *adap) -{ - int ret; - deb_info("%s\n", __func__); - - ret = mxl111sf_lgdt3305_frontend_attach(adap, 0); - if (ret < 0) - return ret; - - ret = mxl111sf_attach_demod(adap, 1); - if (ret < 0) - return ret; - - ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 2); - if (ret < 0) - return ret; - - return ret; -} - -static int mxl111sf_frontend_attach_mercury_mh(struct dvb_usb_adapter *adap) -{ - int ret; - deb_info("%s\n", __func__); - - ret = mxl111sf_attach_demod(adap, 0); - if (ret < 0) - return ret; - - if (dvb_usb_mxl111sf_spi) - ret = mxl111sf_lg2161_frontend_attach(adap, 1); - else - ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 1); - - return ret; -} - -static void mxl111sf_stream_config_bulk(struct usb_data_stream_properties *stream, u8 endpoint) -{ - deb_info("%s: endpoint=%d size=8192\n", __func__, endpoint); - stream->type = USB_BULK; - stream->count = 5; - stream->endpoint = endpoint; - stream->u.bulk.buffersize = 8192; -} - -static void mxl111sf_stream_config_isoc(struct usb_data_stream_properties *stream, - u8 endpoint, int framesperurb, int framesize) -{ - deb_info("%s: endpoint=%d size=%d\n", __func__, endpoint, - framesperurb * framesize); - stream->type = USB_ISOC; - stream->count = 5; - stream->endpoint = endpoint; - stream->u.isoc.framesperurb = framesperurb; - stream->u.isoc.framesize = framesize; - stream->u.isoc.interval = 1; -} - -/* DVB USB Driver stuff */ - -/* dvbt mxl111sf - * bulk EP4/BULK/5/8192 - * isoc EP4/ISOC/5/96/564 - */ -static int mxl111sf_get_stream_config_dvbt(struct dvb_frontend *fe, - u8 *ts_type, struct usb_data_stream_properties *stream) -{ - deb_info("%s: fe=%d\n", __func__, fe->id); - - *ts_type = DVB_USB_FE_TS_TYPE_188; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 4, 96, 564); - else - mxl111sf_stream_config_bulk(stream, 4); - return 0; -} - -static struct dvb_usb_device_properties mxl111sf_props_dvbt = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct mxl111sf_state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .i2c_algo = &mxl111sf_i2c_algo, - .frontend_attach = mxl111sf_frontend_attach_dvbt, - .tuner_attach = mxl111sf_attach_tuner, - .init = mxl111sf_init, - .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, - .get_stream_config = mxl111sf_get_stream_config_dvbt, - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), - } - } -}; - -/* atsc lgdt3305 - * bulk EP6/BULK/5/8192 - * isoc EP6/ISOC/5/24/3072 - */ -static int mxl111sf_get_stream_config_atsc(struct dvb_frontend *fe, - u8 *ts_type, struct usb_data_stream_properties *stream) -{ - deb_info("%s: fe=%d\n", __func__, fe->id); - - *ts_type = DVB_USB_FE_TS_TYPE_188; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 6, 24, 3072); - else - mxl111sf_stream_config_bulk(stream, 6); - return 0; -} - -static struct dvb_usb_device_properties mxl111sf_props_atsc = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct mxl111sf_state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .i2c_algo = &mxl111sf_i2c_algo, - .frontend_attach = mxl111sf_frontend_attach_atsc, - .tuner_attach = mxl111sf_attach_tuner, - .init = mxl111sf_init, - .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, - .get_stream_config = mxl111sf_get_stream_config_atsc, - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), - } - } -}; - -/* mh lg2160 - * bulk EP5/BULK/5/8192/RAW - * isoc EP5/ISOC/5/96/200/RAW - */ -static int mxl111sf_get_stream_config_mh(struct dvb_frontend *fe, - u8 *ts_type, struct usb_data_stream_properties *stream) -{ - deb_info("%s: fe=%d\n", __func__, fe->id); - - *ts_type = DVB_USB_FE_TS_TYPE_RAW; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 5, 96, 200); - else - mxl111sf_stream_config_bulk(stream, 5); - return 0; -} - -static struct dvb_usb_device_properties mxl111sf_props_mh = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct mxl111sf_state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .i2c_algo = &mxl111sf_i2c_algo, - .frontend_attach = mxl111sf_frontend_attach_mh, - .tuner_attach = mxl111sf_attach_tuner, - .init = mxl111sf_init, - .streaming_ctrl = mxl111sf_ep5_streaming_ctrl, - .get_stream_config = mxl111sf_get_stream_config_mh, - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), - } - } -}; - -/* atsc mh lgdt3305 mxl111sf lg2160 - * bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP5/BULK/5/8192/RAW - * isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW - */ -static int mxl111sf_get_stream_config_atsc_mh(struct dvb_frontend *fe, - u8 *ts_type, struct usb_data_stream_properties *stream) -{ - deb_info("%s: fe=%d\n", __func__, fe->id); - - if (fe->id == 0) { - *ts_type = DVB_USB_FE_TS_TYPE_188; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 6, 24, 3072); - else - mxl111sf_stream_config_bulk(stream, 6); - } else if (fe->id == 1) { - *ts_type = DVB_USB_FE_TS_TYPE_188; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 4, 96, 564); - else - mxl111sf_stream_config_bulk(stream, 4); - } else if (fe->id == 2) { - *ts_type = DVB_USB_FE_TS_TYPE_RAW; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 5, 96, 200); - else - mxl111sf_stream_config_bulk(stream, 5); - } - return 0; -} - -static int mxl111sf_streaming_ctrl_atsc_mh(struct dvb_frontend *fe, int onoff) -{ - deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); - - if (fe->id == 0) - return mxl111sf_ep6_streaming_ctrl(fe, onoff); - else if (fe->id == 1) - return mxl111sf_ep4_streaming_ctrl(fe, onoff); - else if (fe->id == 2) - return mxl111sf_ep5_streaming_ctrl(fe, onoff); - return 0; -} - -static struct dvb_usb_device_properties mxl111sf_props_atsc_mh = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct mxl111sf_state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .i2c_algo = &mxl111sf_i2c_algo, - .frontend_attach = mxl111sf_frontend_attach_atsc_mh, - .tuner_attach = mxl111sf_attach_tuner, - .init = mxl111sf_init, - .streaming_ctrl = mxl111sf_streaming_ctrl_atsc_mh, - .get_stream_config = mxl111sf_get_stream_config_atsc_mh, - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), - } - } -}; - -/* mercury lgdt3305 mxl111sf lg2161 - * tp bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP6/BULK/5/8192/RAW - * tp isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP6/ISOC/5/24/3072/RAW - * spi bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP5/BULK/5/8192/RAW - * spi isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW - */ -static int mxl111sf_get_stream_config_mercury(struct dvb_frontend *fe, - u8 *ts_type, struct usb_data_stream_properties *stream) -{ - deb_info("%s: fe=%d\n", __func__, fe->id); - - if (fe->id == 0) { - *ts_type = DVB_USB_FE_TS_TYPE_188; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 6, 24, 3072); - else - mxl111sf_stream_config_bulk(stream, 6); - } else if (fe->id == 1) { - *ts_type = DVB_USB_FE_TS_TYPE_188; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 4, 96, 564); - else - mxl111sf_stream_config_bulk(stream, 4); - } else if (fe->id == 2 && dvb_usb_mxl111sf_spi) { - *ts_type = DVB_USB_FE_TS_TYPE_RAW; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 5, 96, 200); - else - mxl111sf_stream_config_bulk(stream, 5); - } else if (fe->id == 2 && !dvb_usb_mxl111sf_spi) { - *ts_type = DVB_USB_FE_TS_TYPE_RAW; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 6, 24, 3072); - else - mxl111sf_stream_config_bulk(stream, 6); - } - return 0; -} - -static int mxl111sf_streaming_ctrl_mercury(struct dvb_frontend *fe, int onoff) -{ - deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); - - if (fe->id == 0) - return mxl111sf_ep6_streaming_ctrl(fe, onoff); - else if (fe->id == 1) - return mxl111sf_ep4_streaming_ctrl(fe, onoff); - else if (fe->id == 2 && dvb_usb_mxl111sf_spi) - return mxl111sf_ep5_streaming_ctrl(fe, onoff); - else if (fe->id == 2 && !dvb_usb_mxl111sf_spi) - return mxl111sf_ep6_streaming_ctrl(fe, onoff); - return 0; -} - -static struct dvb_usb_device_properties mxl111sf_props_mercury = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct mxl111sf_state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .i2c_algo = &mxl111sf_i2c_algo, - .frontend_attach = mxl111sf_frontend_attach_mercury, - .tuner_attach = mxl111sf_attach_tuner, - .init = mxl111sf_init, - .streaming_ctrl = mxl111sf_streaming_ctrl_mercury, - .get_stream_config = mxl111sf_get_stream_config_mercury, - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), - } - } -}; - -/* mercury mh mxl111sf lg2161 - * tp bulk EP4/BULK/5/8192 EP6/BULK/5/8192/RAW - * tp isoc EP4/ISOC/5/96/564 EP6/ISOC/5/24/3072/RAW - * spi bulk EP4/BULK/5/8192 EP5/BULK/5/8192/RAW - * spi isoc EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW - */ -static int mxl111sf_get_stream_config_mercury_mh(struct dvb_frontend *fe, - u8 *ts_type, struct usb_data_stream_properties *stream) -{ - deb_info("%s: fe=%d\n", __func__, fe->id); - - if (fe->id == 0) { - *ts_type = DVB_USB_FE_TS_TYPE_188; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 4, 96, 564); - else - mxl111sf_stream_config_bulk(stream, 4); - } else if (fe->id == 1 && dvb_usb_mxl111sf_spi) { - *ts_type = DVB_USB_FE_TS_TYPE_RAW; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 5, 96, 200); - else - mxl111sf_stream_config_bulk(stream, 5); - } else if (fe->id == 1 && !dvb_usb_mxl111sf_spi) { - *ts_type = DVB_USB_FE_TS_TYPE_RAW; - if (dvb_usb_mxl111sf_isoc) - mxl111sf_stream_config_isoc(stream, 6, 24, 3072); - else - mxl111sf_stream_config_bulk(stream, 6); - } - return 0; -} - -static int mxl111sf_streaming_ctrl_mercury_mh(struct dvb_frontend *fe, int onoff) -{ - deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); - - if (fe->id == 0) - return mxl111sf_ep4_streaming_ctrl(fe, onoff); - else if (fe->id == 1 && dvb_usb_mxl111sf_spi) - return mxl111sf_ep5_streaming_ctrl(fe, onoff); - else if (fe->id == 1 && !dvb_usb_mxl111sf_spi) - return mxl111sf_ep6_streaming_ctrl(fe, onoff); - return 0; -} - -static struct dvb_usb_device_properties mxl111sf_props_mercury_mh = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct mxl111sf_state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .i2c_algo = &mxl111sf_i2c_algo, - .frontend_attach = mxl111sf_frontend_attach_mercury_mh, - .tuner_attach = mxl111sf_attach_tuner, - .init = mxl111sf_init, - .streaming_ctrl = mxl111sf_streaming_ctrl_mercury_mh, - .get_stream_config = mxl111sf_get_stream_config_mercury_mh, - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), - } - } -}; - -static const struct usb_device_id mxl111sf_id_table[] = { - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc600, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc601, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc602, &mxl111sf_props_mh, "HCW 126xxx", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc603, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc604, &mxl111sf_props_dvbt, "Hauppauge 126xxx DVBT", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc609, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60a, &mxl111sf_props_mh, "HCW 126xxx", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60b, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60c, &mxl111sf_props_dvbt, "Hauppauge 126xxx DVBT", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc653, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc65b, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb700, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb701, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb702, &mxl111sf_props_mh, "HCW 117xxx", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb703, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb704, &mxl111sf_props_dvbt, "Hauppauge 117xxx DVBT", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb753, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb763, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb764, &mxl111sf_props_dvbt, "Hauppauge 117xxx DVBT", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd853, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd854, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd863, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd864, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d3, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d4, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e3, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e4, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8ff, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc612, &mxl111sf_props_mercury_mh, "Hauppauge 126xxx", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc613, &mxl111sf_props_mercury, "Hauppauge WinTV-Aero-M", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61a, &mxl111sf_props_mercury_mh, "Hauppauge 126xxx", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61b, &mxl111sf_props_mercury, "Hauppauge WinTV-Aero-M", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb757, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, - { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb767, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, - { } -}; -MODULE_DEVICE_TABLE(usb, mxl111sf_id_table); - -static struct usb_driver mxl111sf_usb_driver = { - .name = KBUILD_MODNAME, - .id_table = mxl111sf_id_table, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .no_dynamic_id = 1, - .soft_unbind = 1, -}; - -module_usb_driver(mxl111sf_usb_driver); - -MODULE_AUTHOR("Michael Krufky "); -MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.h b/drivers/media/dvb/dvb-usb/mxl111sf.h deleted file mode 100644 index 9816de86e48c..000000000000 --- a/drivers/media/dvb/dvb-usb/mxl111sf.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ - -#ifndef _DVB_USB_MXL111SF_H_ -#define _DVB_USB_MXL111SF_H_ - -#ifdef DVB_USB_LOG_PREFIX -#undef DVB_USB_LOG_PREFIX -#endif -#define DVB_USB_LOG_PREFIX "mxl111sf" -#include "dvb_usb.h" -#include - -#define MXL_EP1_REG_READ 1 -#define MXL_EP2_REG_WRITE 2 -#define MXL_EP3_INTERRUPT 3 -#define MXL_EP4_MPEG2 4 -#define MXL_EP5_I2S 5 -#define MXL_EP6_656 6 -#define MXL_EP6_MPEG2 6 - -#ifdef USING_ENUM_mxl111sf_current_mode -enum mxl111sf_current_mode { - mxl_mode_dvbt = MXL_EP4_MPEG2, - mxl_mode_mh = MXL_EP5_I2S, - mxl_mode_atsc = MXL_EP6_MPEG2, -}; -#endif - -enum mxl111sf_gpio_port_expander { - mxl111sf_gpio_hw, - mxl111sf_PCA9534, -}; - -struct mxl111sf_adap_state { - int alt_mode; - int gpio_mode; - int device_mode; - int ep6_clockphase; - int (*fe_init)(struct dvb_frontend *); - int (*fe_sleep)(struct dvb_frontend *); -}; - -struct mxl111sf_state { - struct dvb_usb_device *d; - - enum mxl111sf_gpio_port_expander gpio_port_expander; - u8 port_expander_addr; - - u8 chip_id; - u8 chip_ver; -#define MXL111SF_V6 1 -#define MXL111SF_V8_100 2 -#define MXL111SF_V8_200 3 - u8 chip_rev; - -#ifdef USING_ENUM_mxl111sf_current_mode - enum mxl111sf_current_mode current_mode; -#endif - -#define MXL_TUNER_MODE 0 -#define MXL_SOC_MODE 1 -#define MXL_DEV_MODE_MASK 0x01 -#if 1 - int device_mode; -#endif - /* use usb alt setting 1 for EP4 ISOC transfer (dvb-t), - EP5 BULK transfer (atsc-mh), - EP6 BULK transfer (atsc/qam), - use usb alt setting 2 for EP4 BULK transfer (dvb-t), - EP5 ISOC transfer (atsc-mh), - EP6 ISOC transfer (atsc/qam), - */ - int alt_mode; - int gpio_mode; - struct tveeprom tv; - - struct mutex fe_lock; - u8 num_frontends; - struct mxl111sf_adap_state adap_state[3]; -}; - -int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data); -int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data); - -struct mxl111sf_reg_ctrl_info { - u8 addr; - u8 mask; - u8 data; -}; - -int mxl111sf_write_reg_mask(struct mxl111sf_state *state, - u8 addr, u8 mask, u8 data); -int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state, - struct mxl111sf_reg_ctrl_info *ctrl_reg_info); - -/* needed for hardware i2c functions in mxl111sf-i2c.c: - * mxl111sf_i2c_send_data / mxl111sf_i2c_get_data */ -int mxl111sf_ctrl_msg(struct dvb_usb_device *d, - u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen); - -#define mxl_printk(kern, fmt, arg...) \ - printk(kern "%s: " fmt "\n", __func__, ##arg) - -#define mxl_info(fmt, arg...) \ - mxl_printk(KERN_INFO, fmt, ##arg) - -extern int dvb_usb_mxl111sf_debug; -#define mxl_debug(fmt, arg...) \ - if (dvb_usb_mxl111sf_debug) \ - mxl_printk(KERN_DEBUG, fmt, ##arg) - -#define MXL_I2C_DBG 0x04 -#define MXL_ADV_DBG 0x10 -#define mxl_debug_adv(fmt, arg...) \ - if (dvb_usb_mxl111sf_debug & MXL_ADV_DBG) \ - mxl_printk(KERN_DEBUG, fmt, ##arg) - -#define mxl_i2c(fmt, arg...) \ - if (dvb_usb_mxl111sf_debug & MXL_I2C_DBG) \ - mxl_printk(KERN_DEBUG, fmt, ##arg) - -#define mxl_i2c_adv(fmt, arg...) \ - if ((dvb_usb_mxl111sf_debug & (MXL_I2C_DBG | MXL_ADV_DBG)) == \ - (MXL_I2C_DBG | MXL_ADV_DBG)) \ - mxl_printk(KERN_DEBUG, fmt, ##arg) - -/* The following allows the mxl_fail() macro defined below to work - * in externel modules, such as mxl111sf-tuner.ko, even though - * dvb_usb_mxl111sf_debug is not defined within those modules */ -#if (defined(__MXL111SF_TUNER_H__)) || (defined(__MXL111SF_DEMOD_H__)) -#define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG -#else -#define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug -#endif - -#define mxl_fail(ret) \ -({ \ - int __ret; \ - __ret = (ret < 0); \ - if ((__ret) && (MXL_ADV_DEBUG_ENABLED & MXL_ADV_DBG)) \ - mxl_printk(KERN_ERR, "error %d on line %d", \ - ret, __LINE__); \ - __ret; \ -}) - -#endif /* _DVB_USB_MXL111SF_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/dvb-usb/usb_urb.c b/drivers/media/dvb/dvb-usb/usb_urb.c deleted file mode 100644 index eaf673a3978d..000000000000 --- a/drivers/media/dvb/dvb-usb/usb_urb.c +++ /dev/null @@ -1,357 +0,0 @@ -/* usb-urb.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file keeps functions for initializing and handling the - * BULK and ISOC USB data transfers in a generic way. - * Can be used for DVB-only and also, that's the plan, for - * Hybrid USB devices (analog and DVB). - */ -#include "dvb_usb_common.h" - -/* URB stuff for streaming */ - -int usb_urb_reconfig(struct usb_data_stream *stream, - struct usb_data_stream_properties *props); - -static void usb_urb_complete(struct urb *urb) -{ - struct usb_data_stream *stream = urb->context; - int ptype = usb_pipetype(urb->pipe); - int i; - u8 *b; - - dev_dbg(&stream->udev->dev, "%s: %s urb completed status=%d " \ - "length=%d/%d pack_num=%d errors=%d\n", __func__, - ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", - urb->status, urb->actual_length, - urb->transfer_buffer_length, - urb->number_of_packets, urb->error_count); - - switch (urb->status) { - case 0: /* success */ - case -ETIMEDOUT: /* NAK */ - break; - case -ECONNRESET: /* kill */ - case -ENOENT: - case -ESHUTDOWN: - return; - default: /* error */ - dev_dbg(&stream->udev->dev, "%s: urb completition failed=%d\n", - __func__, urb->status); - break; - } - - b = (u8 *) urb->transfer_buffer; - switch (ptype) { - case PIPE_ISOCHRONOUS: - for (i = 0; i < urb->number_of_packets; i++) { - if (urb->iso_frame_desc[i].status != 0) - dev_dbg(&stream->udev->dev, "%s: iso frame " \ - "descriptor has an error=%d\n", - __func__, - urb->iso_frame_desc[i].status); - else if (urb->iso_frame_desc[i].actual_length > 0) - stream->complete(stream, - b + urb->iso_frame_desc[i].offset, - urb->iso_frame_desc[i].actual_length); - - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - break; - case PIPE_BULK: - if (urb->actual_length > 0) - stream->complete(stream, b, urb->actual_length); - break; - default: - dev_err(&stream->udev->dev, "%s: unknown endpoint type in " \ - "completition handler\n", KBUILD_MODNAME); - return; - } - usb_submit_urb(urb, GFP_ATOMIC); -} - -int usb_urb_killv2(struct usb_data_stream *stream) -{ - int i; - for (i = 0; i < stream->urbs_submitted; i++) { - dev_dbg(&stream->udev->dev, "%s: kill urb=%d\n", __func__, i); - /* stop the URB */ - usb_kill_urb(stream->urb_list[i]); - } - stream->urbs_submitted = 0; - return 0; -} - -int usb_urb_submitv2(struct usb_data_stream *stream, - struct usb_data_stream_properties *props) -{ - int i, ret; - - if (props) { - ret = usb_urb_reconfig(stream, props); - if (ret < 0) - return ret; - } - - for (i = 0; i < stream->urbs_initialized; i++) { - dev_dbg(&stream->udev->dev, "%s: submit urb=%d\n", __func__, i); - ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC); - if (ret) { - dev_err(&stream->udev->dev, "%s: could not submit " \ - "urb no. %d - get them all back\n", - KBUILD_MODNAME, i); - usb_urb_killv2(stream); - return ret; - } - stream->urbs_submitted++; - } - return 0; -} - -int usb_urb_free_urbs(struct usb_data_stream *stream) -{ - int i; - - usb_urb_killv2(stream); - - for (i = stream->urbs_initialized - 1; i >= 0; i--) { - if (stream->urb_list[i]) { - dev_dbg(&stream->udev->dev, "%s: free urb=%d\n", - __func__, i); - /* free the URBs */ - usb_free_urb(stream->urb_list[i]); - } - } - stream->urbs_initialized = 0; - - return 0; -} - -static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream) -{ - int i, j; - - /* allocate the URBs */ - for (i = 0; i < stream->props.count; i++) { - dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i); - stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); - if (!stream->urb_list[i]) { - dev_dbg(&stream->udev->dev, "%s: failed\n", __func__); - for (j = 0; j < i; j++) - usb_free_urb(stream->urb_list[j]); - return -ENOMEM; - } - usb_fill_bulk_urb(stream->urb_list[i], - stream->udev, - usb_rcvbulkpipe(stream->udev, - stream->props.endpoint), - stream->buf_list[i], - stream->props.u.bulk.buffersize, - usb_urb_complete, stream); - - stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; - stream->urb_list[i]->transfer_dma = stream->dma_addr[i]; - stream->urbs_initialized++; - } - return 0; -} - -static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream) -{ - int i, j; - - /* allocate the URBs */ - for (i = 0; i < stream->props.count; i++) { - struct urb *urb; - int frame_offset = 0; - dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i); - stream->urb_list[i] = usb_alloc_urb( - stream->props.u.isoc.framesperurb, GFP_ATOMIC); - if (!stream->urb_list[i]) { - dev_dbg(&stream->udev->dev, "%s: failed\n", __func__); - for (j = 0; j < i; j++) - usb_free_urb(stream->urb_list[j]); - return -ENOMEM; - } - - urb = stream->urb_list[i]; - - urb->dev = stream->udev; - urb->context = stream; - urb->complete = usb_urb_complete; - urb->pipe = usb_rcvisocpipe(stream->udev, - stream->props.endpoint); - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - urb->interval = stream->props.u.isoc.interval; - urb->number_of_packets = stream->props.u.isoc.framesperurb; - urb->transfer_buffer_length = stream->props.u.isoc.framesize * - stream->props.u.isoc.framesperurb; - urb->transfer_buffer = stream->buf_list[i]; - urb->transfer_dma = stream->dma_addr[i]; - - for (j = 0; j < stream->props.u.isoc.framesperurb; j++) { - urb->iso_frame_desc[j].offset = frame_offset; - urb->iso_frame_desc[j].length = - stream->props.u.isoc.framesize; - frame_offset += stream->props.u.isoc.framesize; - } - - stream->urbs_initialized++; - } - return 0; -} - -int usb_free_stream_buffers(struct usb_data_stream *stream) -{ - if (stream->state & USB_STATE_URB_BUF) { - while (stream->buf_num) { - stream->buf_num--; - dev_dbg(&stream->udev->dev, "%s: free buf=%d\n", - __func__, stream->buf_num); - usb_free_coherent(stream->udev, stream->buf_size, - stream->buf_list[stream->buf_num], - stream->dma_addr[stream->buf_num]); - } - } - - stream->state &= ~USB_STATE_URB_BUF; - - return 0; -} - -int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num, - unsigned long size) -{ - stream->buf_num = 0; - stream->buf_size = size; - - dev_dbg(&stream->udev->dev, "%s: all in all I will use %lu bytes for " \ - "streaming\n", __func__, num * size); - - for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { - stream->buf_list[stream->buf_num] = usb_alloc_coherent( - stream->udev, size, GFP_ATOMIC, - &stream->dma_addr[stream->buf_num]); - if (!stream->buf_list[stream->buf_num]) { - dev_dbg(&stream->udev->dev, "%s: alloc buf=%d failed\n", - __func__, stream->buf_num); - usb_free_stream_buffers(stream); - return -ENOMEM; - } - - dev_dbg(&stream->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n", - __func__, stream->buf_num, - stream->buf_list[stream->buf_num], - (long long)stream->dma_addr[stream->buf_num]); - memset(stream->buf_list[stream->buf_num], 0, size); - stream->state |= USB_STATE_URB_BUF; - } - - return 0; -} - -int usb_urb_reconfig(struct usb_data_stream *stream, - struct usb_data_stream_properties *props) -{ - int buf_size; - - if (!props) - return 0; - - /* check allocated buffers are large enough for the request */ - if (props->type == USB_BULK) { - buf_size = stream->props.u.bulk.buffersize; - } else if (props->type == USB_ISOC) { - buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb; - } else { - dev_err(&stream->udev->dev, "%s: invalid endpoint type=%d\n", - KBUILD_MODNAME, props->type); - return -EINVAL; - } - - if (stream->buf_num < props->count || stream->buf_size < buf_size) { - dev_err(&stream->udev->dev, "%s: cannot reconfigure as " \ - "allocated buffers are too small\n", - KBUILD_MODNAME); - return -EINVAL; - } - - /* check if all fields are same */ - if (stream->props.type == props->type && - stream->props.count == props->count && - stream->props.endpoint == props->endpoint) { - if (props->type == USB_BULK && - props->u.bulk.buffersize == - stream->props.u.bulk.buffersize) - return 0; - else if (props->type == USB_ISOC && - props->u.isoc.framesperurb == - stream->props.u.isoc.framesperurb && - props->u.isoc.framesize == - stream->props.u.isoc.framesize && - props->u.isoc.interval == - stream->props.u.isoc.interval) - return 0; - } - - dev_dbg(&stream->udev->dev, "%s: re-alloc urbs\n", __func__); - - usb_urb_free_urbs(stream); - memcpy(&stream->props, props, sizeof(*props)); - if (props->type == USB_BULK) - return usb_urb_alloc_bulk_urbs(stream); - else if (props->type == USB_ISOC) - return usb_urb_alloc_isoc_urbs(stream); - - return 0; -} - -int usb_urb_initv2(struct usb_data_stream *stream, - const struct usb_data_stream_properties *props) -{ - int ret; - - if (!stream || !props) - return -EINVAL; - - memcpy(&stream->props, props, sizeof(*props)); - - if (!stream->complete) { - dev_err(&stream->udev->dev, "%s: there is no data callback - " \ - "this doesn't make sense\n", KBUILD_MODNAME); - return -EINVAL; - } - - switch (stream->props.type) { - case USB_BULK: - ret = usb_alloc_stream_buffers(stream, stream->props.count, - stream->props.u.bulk.buffersize); - if (ret < 0) - return ret; - - return usb_urb_alloc_bulk_urbs(stream); - case USB_ISOC: - ret = usb_alloc_stream_buffers(stream, stream->props.count, - stream->props.u.isoc.framesize * - stream->props.u.isoc.framesperurb); - if (ret < 0) - return ret; - - return usb_urb_alloc_isoc_urbs(stream); - default: - dev_err(&stream->udev->dev, "%s: unknown urb-type for data " \ - "transfer\n", KBUILD_MODNAME); - return -EINVAL; - } -} - -int usb_urb_exitv2(struct usb_data_stream *stream) -{ - usb_urb_free_urbs(stream); - usb_free_stream_buffers(stream); - - return 0; -}