TerraTec Cinergy T USB RC
From LinuxTVWiki
(Difference between revisions)
| Line 39: | Line 39: | ||
input: NEWMI USB2.0 DVB-T TV Stick as /devices/pci0000:00/0000:00:1a.7/usb3/3-3/3-3:1.1/input/input8 | input: NEWMI USB2.0 DVB-T TV Stick as /devices/pci0000:00/0000:00:1a.7/usb3/3-3/3-3:1.1/input/input8 | ||
generic-usb 0003:0CCD:0097.0002: input,hidraw0: USB HID v1.01 Keyboard [NEWMI USB2.0 DVB-T TV Stick] on usb-0000:00:1a.7-3/input1 | generic-usb 0003:0CCD:0097.0002: input,hidraw0: USB HID v1.01 Keyboard [NEWMI USB2.0 DVB-T TV Stick] on usb-0000:00:1a.7-3/input1 | ||
| + | </pre> | ||
| + | |||
| + | === [http://www.mail-archive.com/linux-media@vger.kernel.org/msg16117.html patch] with changes to linux-2.6.35.4 === | ||
| + | <pre> | ||
| + | diff -Nru linux-2.6.35.4/drivers/media/common/tuners/Kconfig /usr/src/linux-2.6.35.4/drivers/media/common/tuners/Kconfig | ||
| + | --- linux-2.6.35.4/drivers/media/common/tuners/Kconfig 2010-08-27 01:47:12.000000000 +0200 | ||
| + | +++ /usr/src/linux-2.6.35.4/drivers/media/common/tuners/Kconfig 2011-01-04 13:59:07.642000010 +0100 | ||
| + | @@ -179,4 +179,11 @@ | ||
| + | help | ||
| + | A driver for the silicon tuner MAX2165 from Maxim. | ||
| + | |||
| + | +config MEDIA_TUNER_TDA18218 | ||
| + | + tristate "NXP TDA18218 silicon tuner" | ||
| + | + depends on VIDEO_MEDIA && I2C | ||
| + | + default m if MEDIA_TUNER_CUSTOMISE | ||
| + | + help | ||
| + | + A driver for the silicon tuner TDA18218 from NXP. | ||
| + | + | ||
| + | endif # MEDIA_TUNER_CUSTOMISE | ||
| + | diff -Nru linux-2.6.35.4/drivers/media/common/tuners/Makefile /usr/src/linux-2.6.35.4/drivers/media/common/tuners/Makefile | ||
| + | --- linux-2.6.35.4/drivers/media/common/tuners/Makefile 2010-08-27 01:47:12.000000000 +0200 | ||
| + | +++ /usr/src/linux-2.6.35.4/drivers/media/common/tuners/Makefile 2011-01-04 13:59:50.733000011 +0100 | ||
| + | @@ -24,6 +24,7 @@ | ||
| + | obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o | ||
| + | obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o | ||
| + | obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o | ||
| + | +obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o | ||
| + | |||
| + | EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core | ||
| + | EXTRA_CFLAGS += -Idrivers/media/dvb/frontends | ||
| + | diff -Nru linux-2.6.35.4/drivers/media/common/tuners/tda18218.c /usr/src/linux-2.6.35.4/drivers/media/common/tuners/tda18218.c | ||
| + | --- linux-2.6.35.4/drivers/media/common/tuners/tda18218.c 1970-01-01 01:00:00.000000000 +0100 | ||
| + | +++ /usr/src/linux-2.6.35.4/drivers/media/common/tuners/tda18218.c 2011-01-04 15:22:54.068000023 +0100 | ||
| + | @@ -0,0 +1,471 @@ | ||
| + | +/* | ||
| + | + * Driver for NXP TDA18218 silicon tuner | ||
| + | + * | ||
| + | + * Copyright (C) 2010 Lauris Ding <ld...@gmx.de> | ||
| + | + * 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 "tda18218.h" | ||
| + | +//#include "compat.h" | ||
| + | +#include "tda18218_priv.h" | ||
| + | + | ||
| + | +static int tda18218_write_reg(struct dvb_frontend *fe, u8 reg, u8 val) | ||
| + | +{ | ||
| + | + struct tda18218_priv *priv = fe->tuner_priv; | ||
| + | + u8 buf[2] = { reg, val }; | ||
| + | + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, | ||
| + | + .buf = buf, .len = 2 }; | ||
| + | + int ret; | ||
| + | + | ||
| + | + if (fe->ops.i2c_gate_ctrl) | ||
| + | + fe->ops.i2c_gate_ctrl(fe, 1); | ||
| + | + /* write register */ | ||
| + | + ret = i2c_transfer(priv->i2c, &msg, 1); | ||
| + | + if (fe->ops.i2c_gate_ctrl) | ||
| + | + fe->ops.i2c_gate_ctrl(fe, 0); | ||
| + | + | ||
| + | + if (ret != 1) | ||
| + | + printk(KERN_WARNING "I2C write failed ret: %d reg: %02x\n", ret, reg); | ||
| + | + | ||
| + | + return (ret == 1 ? 0 : ret); | ||
| + | +} | ||
| + | + | ||
| + | +static int tda18218_write_regs(struct dvb_frontend *fe, u8 reg, | ||
| + | + u8 *val, u8 len) | ||
| + | +{ | ||
| + | + struct tda18218_priv *priv = fe->tuner_priv; | ||
| + | + u8 buf[1+len]; | ||
| + | + struct i2c_msg msg = { | ||
| + | + .addr = priv->cfg->i2c_address, | ||
| + | + .flags = 0, | ||
| + | + .len = sizeof(buf), | ||
| + | + .buf = buf }; | ||
| + | + | ||
| + | + int ret; | ||
| + | + | ||
| + | + buf[0] = reg; | ||
| + | + memcpy(&buf[1], val, len); | ||
| + | + | ||
| + | + if (fe->ops.i2c_gate_ctrl) | ||
| + | + fe->ops.i2c_gate_ctrl(fe, 1); | ||
| + | + ret = i2c_transfer(priv->i2c, &msg, 1); | ||
| + | + if (fe->ops.i2c_gate_ctrl) | ||
| + | + fe->ops.i2c_gate_ctrl(fe, 1); | ||
| + | + | ||
| + | + if (ret != 1) | ||
| + | + printk(KERN_WARNING "I2C write failed ret: %d reg: %02x len: %d\n", ret, reg, len); | ||
| + | + | ||
| + | + return (ret == 1 ? 0 : ret); | ||
| + | +} | ||
| + | + | ||
| + | +/*static int tda18218_read_reg(struct tda18218_priv *priv, u16 reg, u8 *val) | ||
| + | +{ | ||
| + | + u8 obuf[3] = { reg >> 8, reg & 0xff, 0 }; | ||
| + | + u8 ibuf[1]; | ||
| + | + struct i2c_msg msg[2] = { | ||
| + | + { | ||
| + | + .addr = 0x3a, | ||
| + | + .flags = 0, | ||
| + | + .len = sizeof(obuf), | ||
| + | + .buf = obuf | ||
| + | + }, { | ||
| + | + .addr = 0x3a, | ||
| + | + .flags = I2C_M_RD, | ||
| + | + .len = sizeof(ibuf), | ||
| + | + .buf = ibuf | ||
| + | + } | ||
| + | + }; | ||
| + | + | ||
| + | + if (i2c_transfer(priv->i2c, msg, 2) != 2) { | ||
| + | + printk(KERN_WARNING "I2C read failed reg:%04x\n", reg); | ||
| + | + return -EREMOTEIO; | ||
| + | + } | ||
| + | + *val = ibuf[0]; | ||
| + | + return 0; | ||
| + | +}*/ | ||
| + | + | ||
| + | +static int tda18218_read_regs(struct dvb_frontend *fe) | ||
| + | +{ | ||
| + | + struct tda18218_priv *priv = fe->tuner_priv; | ||
| + | + u8 *regs = priv->tda18218_regs; | ||
| + | + u8 buf = 0x00; | ||
| + | + int ret; | ||
| + | + //int i; | ||
| + | + struct i2c_msg msg[] = { | ||
| + | + { .addr = 0xc0, .flags = 0, | ||
| + | + .buf = &buf, .len = 1 }, | ||
| + | + { .addr = 0xc0, .flags = I2C_M_RD, | ||
| + | + .buf = regs, .len = 59 } | ||
| + | + }; | ||
| + | + | ||
| + | + if (fe->ops.i2c_gate_ctrl) | ||
| + | + fe->ops.i2c_gate_ctrl(fe, 1); | ||
| + | + | ||
| + | + /* read all registers */ | ||
| + | + ret = i2c_transfer(priv->i2c, msg, 2); | ||
| + | + | ||
| + | + if (fe->ops.i2c_gate_ctrl) | ||
| + | + fe->ops.i2c_gate_ctrl(fe, 0); | ||
| + | + | ||
| + | + if (ret != 2) | ||
| + | + printk(KERN_WARNING "I2C read failed ret: %d\n", ret); | ||
| + | + | ||
| + | + /*for(i = 0; i <= 58; i++) | ||
| + | + printk("Register %d: %02x\n", i, 0xff & regs[i]);*/ | ||
| + | + | ||
| + | + return (ret == 2 ? 0 : ret); | ||
| + | +} | ||
| + | + | ||
| + | +static int tda18218_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | ||
| + | +{ | ||
| + | + struct tda18218_priv *priv = fe->tuner_priv; | ||
| + | + u8 *regs = priv->tda18218_regs; | ||
| + | + u8 Fc, BP; | ||
| + | + int i, ret; | ||
| + | + u16 if1, bw; | ||
| + | + u32 freq; | ||
| + | + | ||
| + | + u8 paramsbuf[4][6] = { | ||
| + | + { 0x03, 0x1a }, | ||
| + | + { 0x04, 0x0a }, | ||
| + | + { 0x01, 0x0f }, | ||
| + | + { 0x01, 0x0f }, | ||
| + | + }; | ||
| + | + | ||
| + | + u8 agcbuf[][2] = { | ||
| + | + { 0x1a, 0x0e }, | ||
| + | + { 0x20, 0x60 }, | ||
| + | + { 0x23, 0x02 }, | ||
| + | + { 0x20, 0xa0 }, | ||
| + | + { 0x23, 0x09 }, | ||
| + | + { 0x20, 0xe0 }, | ||
| + | + { 0x23, 0x0c }, | ||
| + | + { 0x20, 0x40 }, | ||
| + | + { 0x23, 0x01 }, | ||
| + | + { 0x20, 0x80 }, | ||
| + | + { 0x23, 0x08 }, | ||
| + | + { 0x20, 0xc0 }, | ||
| + | + { 0x23, 0x0b }, | ||
| + | + { 0x24, 0x1c }, | ||
| + | + { 0x24, 0x0c }, | ||
| + | + }; | ||
| + | + | ||
| + | + switch (params->u.ofdm.bandwidth) { | ||
| + | + case BANDWIDTH_6_MHZ: | ||
| + | + bw = 6000; | ||
| + | + Fc = 0; | ||
| + | + break; | ||
| + | + case BANDWIDTH_7_MHZ: | ||
| + | + bw = 7000; | ||
| + | + Fc = 1; | ||
| + | + break; | ||
| + | + case BANDWIDTH_8_MHZ: | ||
| + | + bw = 8000; | ||
| + | + Fc = 2; | ||
| + | + break; | ||
| + | + default: | ||
| + | + printk(KERN_WARNING "Invalid bandwidth"); | ||
| + | + return -EINVAL; | ||
| + | + } | ||
| + | + | ||
| + | + if1 = bw / 2; | ||
| + | + | ||
| + | + if((params->frequency >= 174000000) && (params->frequency < 188000000)) { | ||
| + | + BP = 3; | ||
| + | + } | ||
| + | + else if((params->frequency >= 188000000) && (params->frequency < 253000000)) { | ||
| + | + BP = 4; | ||
| + | + } | ||
| + | + else if((params->frequency >= 253000000) && (params->frequency < 343000000)) { | ||
| + | + BP = 5; | ||
| + | + } | ||
| + | + else if((params->frequency >= 343000000) && (params->frequency <= 870000000)) { | ||
| + | + BP = 6; | ||
| + | + } | ||
| + | + else { | ||
| + | + printk(KERN_WARNING "Frequency out of range"); | ||
| + | + return -EINVAL; | ||
| + | + } | ||
| + | + | ||
| + | + freq = params->frequency; | ||
| + | + freq /= 1000; | ||
| + | + freq +=if1; | ||
| + | + freq *= 16; | ||
| + | + | ||
| + | + tda18218_read_regs(fe); | ||
| + | + | ||
| + | + paramsbuf[0][2] = regs[0x1a] | BP; | ||
| + | + paramsbuf[0][3] = regs[0x1b] & ~3; | ||
| + | + paramsbuf[0][3] = regs[0x1b] | Fc; | ||
| + | + paramsbuf[0][4] = regs[0x1c] | 0x0a; | ||
| + | + | ||
| + | + paramsbuf[1][2] = freq >> 16; | ||
| + | + paramsbuf[1][3] = freq >> 8; | ||
| + | + paramsbuf[1][4] = (freq & 0xf0) | (regs[0x0c] & 0x0f); | ||
| + | + paramsbuf[1][5] = 0xff; | ||
| + | + paramsbuf[2][2] = regs[0x0f] | 0x40; | ||
| + | + paramsbuf[3][2] = 0x09; | ||
| + | + | ||
| + | + tda18218_write_reg(fe, 0x04, 0x03); | ||
| + | + | ||
| + | + for(i = 0; i < ARRAY_SIZE(paramsbuf); i++) { | ||
| + | + | ||
| + | + /* write registers */ | ||
| + | + ret = tda18218_write_regs(fe, paramsbuf[i][1], ¶msbuf[i][2], paramsbuf[i][0]); | ||
| + | + | ||
| + | + if (ret) | ||
| + | + goto error; | ||
| + | + } | ||
| + | + for(i = 0; i < ARRAY_SIZE(agcbuf); i++) { | ||
| + | + tda18218_write_reg(fe, agcbuf[i][0], agcbuf[i][1]); | ||
| + | + } | ||
| + | + | ||
| + | + //tda18218_write_reg(fe, 0x03, 0x00); | ||
| + | + //tda18218_write_reg(fe, 0x04, 0x00); | ||
| + | + //tda18218_write_reg(fe, 0x20, 0xc7); | ||
| + | + | ||
| + | + msleep(60); | ||
| + | + i = 0; | ||
| + | + while(i < 10) { | ||
| + | + tda18218_read_regs(fe); | ||
| + | + if((regs[0x01] & 0x60) == 0x60) | ||
| + | + printk(KERN_INFO "We've got a lock!"); break; | ||
| + | + msleep(20); | ||
| + | + i++; | ||
| + | + } | ||
| + | + | ||
| + | + priv->bandwidth = params->u.ofdm.bandwidth; | ||
| + | + priv->frequency = params->frequency; | ||
| + | + return 0; | ||
| + | +error: | ||
| + | + return ret; | ||
| + | +} | ||
| + | + | ||
| + | +static int tda18218_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
| + | +{ | ||
| + | + struct tda18218_priv *priv = fe->tuner_priv; | ||
| + | + *frequency = priv->frequency; | ||
| + | + return 0; | ||
| + | +} | ||
| + | + | ||
| + | +static int tda18218_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
| + | +{ | ||
| + | + struct tda18218_priv *priv = fe->tuner_priv; | ||
| + | + *bandwidth = priv->bandwidth; | ||
| + | + return 0; | ||
| + | +} | ||
| + | + | ||
| + | +static int tda18218_init(struct dvb_frontend *fe) | ||
| + | +{ | ||
| + | + //struct tda18218_priv *priv = fe->tuner_priv; | ||
| + | + //u8 *regs = priv->tda18218_regs; | ||
| + | + int i; | ||
| + | + int ret; | ||
| + | + | ||
| + | + u8 initbuf[][18] = { | ||
| + | + { 0x10, 0x05, 0x00, 0x00, 0xd0, 0x00, 0x40, 0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00, 0x01 }, | ||
| + | + { 0x0b, 0x15, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x0e, 0x29, 0x98, 0x00, 0x00, 0x58 }, | ||
| + | + { 0x10, 0x24, 0x0c, 0x48, 0x85, 0xc9, 0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00, 0x8a, 0x00 }, | ||
| + | + { 0x07, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6 }, | ||
| + | + }; | ||
| + | + | ||
| + | + u8 initbuf2[4]; | ||
| + | + | ||
| + | + for(i = 0; i < ARRAY_SIZE(initbuf); i++) { | ||
| + | + | ||
| + | + /* write registers */ | ||
| + | + ret = tda18218_write_regs(fe, initbuf[i][1], &initbuf[i][2], initbuf[i][0]); | ||
| + | + | ||
| + | + if (ret != 0) { | ||
| + | + printk(KERN_ERR "init: ERROR: i2c_transfer returned: %d\n", ret); | ||
| + | + return -EREMOTEIO; | ||
| + | + } | ||
| + | + if(i == 1) { | ||
| + | + tda18218_write_reg(fe, 0x22, 0x8c); | ||
| + | + } | ||
| + | + } | ||
| + | + | ||
| + | + tda18218_write_reg(fe, 0x05, 0x80); | ||
| + | + tda18218_write_reg(fe, 0x05, 0x00); | ||
| + | + tda18218_write_reg(fe, 0x05, 0x20); | ||
| + | + tda18218_write_reg(fe, 0x05, 0x00); | ||
| + | + tda18218_write_reg(fe, 0x27, 0xde); | ||
| + | + tda18218_write_reg(fe, 0x17, 0xf8); | ||
| + | + tda18218_write_reg(fe, 0x18, 0x0f); | ||
| + | + tda18218_write_reg(fe, 0x1c, 0x8b); | ||
| + | + tda18218_write_reg(fe, 0x29, 0x02); | ||
| + | + tda18218_write_reg(fe, 0x19, 0x1a); | ||
| + | + tda18218_write_reg(fe, 0x11, 0x13); | ||
| + | + | ||
| + | + initbuf2[0] = 0x0a; | ||
| + | + initbuf2[1] = 0x5c; | ||
| + | + initbuf2[2] = 0xc6; | ||
| + | + initbuf2[3] = 0x07; | ||
| + | + tda18218_write_regs(fe, initbuf2[0], &initbuf2[1], 3); | ||
| + | + tda18218_write_reg(fe, 0x0f, 0x49); | ||
| + | + tda18218_write_reg(fe, 0x05, 0x40); | ||
| + | + tda18218_write_reg(fe, 0x05, 0x00); | ||
| + | + tda18218_write_reg(fe, 0x05, 0x20); | ||
| + | + tda18218_write_reg(fe, 0x11, 0xed); | ||
| + | + tda18218_write_reg(fe, 0x0f, 0x49); | ||
| + | + tda18218_write_reg(fe, 0x19, 0x2a); | ||
| + | + tda18218_write_reg(fe, 0x05, 0x58); | ||
| + | + tda18218_write_reg(fe, 0x05, 0x18); | ||
| + | + tda18218_write_reg(fe, 0x05, 0x38); | ||
| + | + tda18218_write_reg(fe, 0x29, 0x03); | ||
| + | + tda18218_write_reg(fe, 0x19, 0x1a); | ||
| + | + tda18218_write_reg(fe, 0x11, 0x13); | ||
| + | + initbuf2[0] = 0x0a; | ||
| + | + initbuf2[1] = 0xbe; | ||
| + | + initbuf2[2] = 0x6e; | ||
| + | + initbuf2[3] = 0x07; | ||
| + | + tda18218_write_regs(fe, initbuf2[0], &initbuf2[1], 3); | ||
| + | + tda18218_write_reg(fe, 0x0f, 0x49); | ||
| + | + tda18218_write_reg(fe, 0x05, 0x58); | ||
| + | + tda18218_write_reg(fe, 0x05, 0x18); | ||
| + | + tda18218_write_reg(fe, 0x05, 0x38); | ||
| + | + tda18218_write_reg(fe, 0x11, 0xed); | ||
| + | + tda18218_write_reg(fe, 0x0f, 0x49); | ||
| + | + tda18218_write_reg(fe, 0x19, 0x2a); | ||
| + | + tda18218_write_reg(fe, 0x05, 0x58); | ||
| + | + tda18218_write_reg(fe, 0x05, 0x18); | ||
| + | + tda18218_write_reg(fe, 0x05, 0x38); | ||
| + | + tda18218_write_reg(fe, 0x19, 0x0a); | ||
| + | + tda18218_write_reg(fe, 0x27, 0xc9); | ||
| + | + tda18218_write_reg(fe, 0x11, 0x13); | ||
| + | + initbuf2[0] = 0x17; | ||
| + | + initbuf2[1] = 0xf0; | ||
| + | + initbuf2[2] = 0x19; | ||
| + | + initbuf2[3] = 0x00; | ||
| + | + tda18218_write_regs(fe, initbuf2[0], &initbuf2[1], 2); | ||
| + | + tda18218_write_reg(fe, 0x1c, 0x98); | ||
| + | + tda18218_write_reg(fe, 0x29, 0x03); | ||
| + | + tda18218_write_reg(fe, 0x2a, 0x00); | ||
| + | + tda18218_write_reg(fe, 0x2a, 0x01); | ||
| + | + tda18218_write_reg(fe, 0x2a, 0x02); | ||
| + | + tda18218_write_reg(fe, 0x2a, 0x03); | ||
| + | + tda18218_write_reg(fe, 0x1c, 0x98); | ||
| + | + tda18218_write_reg(fe, 0x18, 0x19); | ||
| + | + tda18218_write_reg(fe, 0x22, 0x9c); | ||
| + | + tda18218_write_reg(fe, 0x1f, 0x58); | ||
| + | + tda18218_write_reg(fe, 0x24, 0x0c); | ||
| + | + tda18218_write_reg(fe, 0x1c, 0x88); | ||
| + | + tda18218_write_reg(fe, 0x20, 0x10); | ||
| + | + tda18218_write_reg(fe, 0x21, 0x4c); | ||
| + | + tda18218_write_reg(fe, 0x20, 0x00); | ||
| + | + tda18218_write_reg(fe, 0x21, 0x48); | ||
| + | + tda18218_write_reg(fe, 0x1f, 0x5b); | ||
| + | + tda18218_write_reg(fe, 0x20, 0x00); | ||
| + | + tda18218_write_reg(fe, 0x1f, 0x59); | ||
| + | + tda18218_write_reg(fe, 0x20, 0x00); | ||
| + | + tda18218_write_reg(fe, 0x1f, 0x5a); | ||
| + | + tda18218_write_reg(fe, 0x20, 0x00); | ||
| + | + tda18218_write_reg(fe, 0x1f, 0x5f); | ||
| + | + tda18218_write_reg(fe, 0x20, 0x00); | ||
| + | + tda18218_write_reg(fe, 0x1f, 0x5d); | ||
| + | + tda18218_write_reg(fe, 0x20, 0x00); | ||
| + | + tda18218_write_reg(fe, 0x1f, 0x5e); | ||
| + | + tda18218_write_reg(fe, 0x20, 0x00); | ||
| + | + tda18218_write_reg(fe, 0x20, 0x60); | ||
| + | + tda18218_write_reg(fe, 0x23, 0x02); | ||
| + | + tda18218_write_reg(fe, 0x20, 0xa0); | ||
| + | + tda18218_write_reg(fe, 0x23, 0x09); | ||
| + | + tda18218_write_reg(fe, 0x20, 0xe0); | ||
| + | + tda18218_write_reg(fe, 0x23, 0x0c); | ||
| + | + tda18218_write_reg(fe, 0x20, 0x40); | ||
| + | + tda18218_write_reg(fe, 0x23, 0x01); | ||
| + | + tda18218_write_reg(fe, 0x20, 0x80); | ||
| + | + tda18218_write_reg(fe, 0x23, 0x08); | ||
| + | + tda18218_write_reg(fe, 0x20, 0xc0); | ||
| + | + tda18218_write_reg(fe, 0x23, 0x0b); | ||
| + | + tda18218_write_reg(fe, 0x1c, 0x98); | ||
| + | + tda18218_write_reg(fe, 0x22, 0x8c); | ||
| + | + initbuf2[0] = 0x17; | ||
| + | + initbuf2[1] = 0xb0; | ||
| + | + initbuf2[2] = 0x59; | ||
| + | + initbuf2[3] = 0x00; | ||
| + | + //tda18218_write_regs(fe, initbuf2[0], &initbuf2[1], 2); | ||
| + | + initbuf2[0] = 0x1a; | ||
| + | + initbuf2[1] = 0x0e; | ||
| + | + initbuf2[2] = 0x2a; | ||
| + | + initbuf2[3] = 0x98; | ||
| + | + tda18218_write_regs(fe, initbuf2[0], &initbuf2[1], 3); | ||
| + | + initbuf2[0] = 0x17; | ||
| + | + initbuf2[1] = 0xb0; | ||
| + | + initbuf2[2] = 0x59; | ||
| + | + initbuf2[3] = 0x00; | ||
| + | + tda18218_write_regs(fe, initbuf2[0], &initbuf2[1], 2); | ||
| + | + tda18218_write_reg(fe, 0x2d, 0x81); | ||
| + | + tda18218_write_reg(fe, 0x29, 0x02); | ||
| + | + | ||
| + | + return 0; | ||
| + | +} | ||
| + | + | ||
| + | +static int tda18218_release(struct dvb_frontend *fe) | ||
| + | +{ | ||
| + | + kfree(fe->tuner_priv); | ||
| + | + fe->tuner_priv = NULL; | ||
| + | + return 0; | ||
| + | +} | ||
| + | + | ||
| + | +static const struct dvb_tuner_ops tda18218_tuner_ops = { | ||
| + | + .info = { | ||
| + | + .name = "NXP TDA18218", | ||
| + | + .frequency_min = TDA18218_MIN_FREQ, | ||
| + | + .frequency_max = TDA18218_MAX_FREQ, | ||
| + | + .frequency_step = TDA18218_STEP, | ||
| + | + }, | ||
| + | + | ||
| + | + .release = tda18218_release, | ||
| + | + .init = tda18218_init, | ||
| + | + | ||
| + | + .set_params = tda18218_set_params, | ||
| + | + .get_frequency = tda18218_get_frequency, | ||
| + | + .get_bandwidth = tda18218_get_bandwidth, | ||
| + | +}; | ||
| + | + | ||
| + | +struct dvb_frontend * tda18218_attach(struct dvb_frontend *fe, | ||
| + | + struct i2c_adapter *i2c, | ||
| + | + struct tda18218_config *cfg) | ||
| + | +{ | ||
| + | + struct tda18218_priv *priv = NULL; | ||
| + | + | ||
| + | + priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL); | ||
| + | + if (priv == NULL) | ||
| + | + return NULL; | ||
| + | + | ||
| + | + priv->cfg = cfg; | ||
| + | + priv->i2c = i2c; | ||
| + | + | ||
| + | + fe->tuner_priv = priv; | ||
| + | + | ||
| + | + tda18218_read_regs(fe); | ||
| + | + if (priv->tda18218_regs[0x00] != 0xc0) { | ||
| + | + printk(KERN_WARNING "Device is not a TDA18218!\n"); | ||
| + | + kfree(priv); | ||
| + | + return NULL; | ||
| + | + } | ||
| + | + | ||
| + | + printk(KERN_INFO "NXP TDA18218 successfully identified.\n"); | ||
| + | + memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops, | ||
| + | + sizeof(struct dvb_tuner_ops)); | ||
| + | + | ||
| + | + return fe; | ||
| + | +} | ||
| + | +EXPORT_SYMBOL(tda18218_attach); | ||
| + | + | ||
| + | +MODULE_DESCRIPTION("NXP TDA18218 silicon tuner driver"); | ||
| + | +MODULE_AUTHOR("Lauris Ding <ld...@gmx.de>"); | ||
| + | +MODULE_VERSION("0.1"); | ||
| + | +MODULE_LICENSE("GPL"); | ||
| + | diff -Nru linux-2.6.35.4/drivers/media/common/tuners/tda18218.h /usr/src/linux-2.6.35.4/drivers/media/common/tuners/tda18218.h | ||
| + | --- linux-2.6.35.4/drivers/media/common/tuners/tda18218.h 1970-01-01 01:00:00.000000000 +0100 | ||
| + | +++ /usr/src/linux-2.6.35.4/drivers/media/common/tuners/tda18218.h 2011-01-04 14:03:39.306000007 +0100 | ||
| + | @@ -0,0 +1,44 @@ | ||
| + | +/* | ||
| + | + * Driver for NXP TDA18218 silicon tuner | ||
| + | + * | ||
| + | + * Copyright (C) 2010 Lauris Ding <ld...@gmx.de> | ||
| + | + * | ||
| + | + * 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 TDA18218_H | ||
| + | +#define TDA18218_H | ||
| + | + | ||
| + | +#include "dvb_frontend.h" | ||
| + | + | ||
| + | +struct tda18218_config { | ||
| + | + u8 i2c_address; | ||
| + | +}; | ||
| + | + | ||
| + | +#if defined(CONFIG_MEDIA_TUNER_TDA18218) || (defined(CONFIG_MEDIA_TUNER_TDA18218_MODULE) && defined(MODULE)) | ||
| + | +extern struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, | ||
| + | + struct i2c_adapter *i2c, | ||
| + | + struct tda18218_config *cfg); | ||
| + | +#else | ||
| + | +static inline struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, | ||
| + | + struct i2c_adapter *i2c, | ||
| + | + struct tda18218_config *cfg) | ||
| + | +{ | ||
| + | + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| + | + return NULL; | ||
| + | +} | ||
| + | +#endif // CONFIG_MEDIA_TUNER_TDA18218 | ||
| + | + | ||
| + | +#endif | ||
| + | diff -Nru linux-2.6.35.4/drivers/media/common/tuners/tda18218_priv.h /usr/src/linux-2.6.35.4/drivers/media/common/tuners/tda18218_priv.h | ||
| + | --- linux-2.6.35.4/drivers/media/common/tuners/tda18218_priv.h 1970-01-01 01:00:00.000000000 +0100 | ||
| + | +++ /usr/src/linux-2.6.35.4/drivers/media/common/tuners/tda18218_priv.h 2011-01-04 14:04:36.744000011 +0100 | ||
| + | @@ -0,0 +1,36 @@ | ||
| + | +/* | ||
| + | + * Driver for NXP TDA18218 silicon tuner | ||
| + | + * | ||
| + | + * Copyright (C) 2010 Lauris Ding <ld...@gmx.de> | ||
| + | + * 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 TDA18218_PRIV_H | ||
| + | +#define TDA18218_PRIV_H | ||
| + | + | ||
| + | +#define TDA18218_STEP 1000 /* 1 kHz */ | ||
| + | +#define TDA18218_MIN_FREQ 174000000 /* 174 MHz */ | ||
| + | +#define TDA18218_MAX_FREQ 864000000 /* 864 MHz */ | ||
| + | + | ||
| + | +struct tda18218_priv { | ||
| + | + u8 tda18218_regs[0x3b]; | ||
| + | + struct tda18218_config *cfg; | ||
| + | + struct i2c_adapter *i2c; | ||
| + | + | ||
| + | + u32 frequency; | ||
| + | + u32 bandwidth; | ||
| + | +}; | ||
| + | + | ||
| + | +#endif | ||
| + | diff -Nru linux-2.6.35.4/drivers/media/dvb/dvb-usb/af9015.c /usr/src/linux-2.6.35.4/drivers/media/dvb/dvb-usb/af9015.c | ||
| + | --- linux-2.6.35.4/drivers/media/dvb/dvb-usb/af9015.c 2010-08-27 01:47:12.000000000 +0200 | ||
| + | +++ /usr/src/linux-2.6.35.4/drivers/media/dvb/dvb-usb/af9015.c 2011-01-05 10:21:43.993000001 +0100 | ||
| + | @@ -31,6 +31,7 @@ | ||
| + | #include "tda18271.h" | ||
| + | #include "mxl5005s.h" | ||
| + | #include "mc44s803.h" | ||
| + | +#include "tda18218.h" | ||
| + | |||
| + | static int dvb_usb_af9015_debug; | ||
| + | module_param_named(debug, dvb_usb_af9015_debug, int, 0644); | ||
| + | @@ -272,7 +273,8 @@ | ||
| + | |||
| + | while (i < num) { | ||
| + | if (msg[i].addr == af9015_af9013_config[0].demod_address || | ||
| + | - msg[i].addr == af9015_af9013_config[1].demod_address) { | ||
| + | + msg[i].addr == af9015_af9013_config[1].demod_address || | ||
| + | + msg[i].addr == 0x3a) { | ||
| + | addr = msg[i].buf[0] << 8; | ||
| + | addr += msg[i].buf[1]; | ||
| + | mbox = msg[i].buf[2]; | ||
| + | @@ -285,7 +287,8 @@ | ||
| + | |||
| + | if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { | ||
| + | if (msg[i].addr == | ||
| + | - af9015_af9013_config[0].demod_address) | ||
| + | + af9015_af9013_config[0].demod_address || | ||
| + | + msg[i].addr == 0x3a) | ||
| + | req.cmd = READ_MEMORY; | ||
| + | else | ||
| + | req.cmd = READ_I2C; | ||
| + | @@ -300,7 +303,8 @@ | ||
| + | } else if (msg[i].flags & I2C_M_RD) { | ||
| + | ret = -EINVAL; | ||
| + | if (msg[i].addr == | ||
| + | - af9015_af9013_config[0].demod_address) | ||
| + | + af9015_af9013_config[0].demod_address || | ||
| + | + msg[i].addr == 0x3a) | ||
| + | goto error; | ||
| + | else | ||
| + | req.cmd = READ_I2C; | ||
| + | @@ -314,7 +318,8 @@ | ||
| + | i += 1; | ||
| + | } else { | ||
| + | if (msg[i].addr == | ||
| + | - af9015_af9013_config[0].demod_address) | ||
| + | + af9015_af9013_config[0].demod_address || | ||
| + | + msg[i].addr == 0x3a) | ||
| + | req.cmd = WRITE_MEMORY; | ||
| + | else | ||
| + | req.cmd = WRITE_I2C; | ||
| + | @@ -556,46 +561,6 @@ | ||
| + | return ret; | ||
| + | } | ||
| + | |||
| + | -/* hash (and dump) eeprom */ | ||
| + | -static int af9015_eeprom_hash(struct usb_device *udev) | ||
| + | -{ | ||
| + | - static const unsigned int eeprom_size = 256; | ||
| + | - unsigned int reg; | ||
| + | - int ret; | ||
| + | - 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_rw_udev(udev, &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); | ||
| + | - | ||
| + | - af9015_config.eeprom_sum = 0; | ||
| + | - for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) { | ||
| + | - af9015_config.eeprom_sum *= GOLDEN_RATIO_PRIME_32; | ||
| + | - af9015_config.eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]); | ||
| + | - } | ||
| + | - | ||
| + | - deb_info("%s: eeprom sum=%.8x\n", __func__, af9015_config.eeprom_sum); | ||
| + | - | ||
| + | - ret = 0; | ||
| + | -free: | ||
| + | - kfree(eeprom); | ||
| + | - return ret; | ||
| + | -} | ||
| + | |||
| + | static int af9015_download_ir_table(struct dvb_usb_device *d) | ||
| + | { | ||
| + | @@ -733,132 +698,12 @@ | ||
| + | return ret; | ||
| + | } | ||
| + | |||
| + | -struct af9015_setup { | ||
| + | - unsigned int id; | ||
| + | - struct dvb_usb_rc_key *rc_key_map; | ||
| + | - unsigned int rc_key_map_size; | ||
| + | - u8 *ir_table; | ||
| + | - unsigned int ir_table_size; | ||
| + | -}; | ||
| + | - | ||
| + | -static const struct af9015_setup *af9015_setup_match(unsigned int id, | ||
| + | - const struct af9015_setup *table) | ||
| + | -{ | ||
| + | - for (; table->rc_key_map; table++) | ||
| + | - if (table->id == id) | ||
| + | - return table; | ||
| + | - return NULL; | ||
| + | -} | ||
| + | - | ||
| + | -static const struct af9015_setup af9015_setup_modparam[] = { | ||
| + | - { AF9015_REMOTE_A_LINK_DTU_M, | ||
| + | - ir_codes_af9015_table_a_link, ARRAY_SIZE(ir_codes_af9015_table_a_link), | ||
| + | - af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) }, | ||
| + | - { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, | ||
| + | - ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi), | ||
| + | - af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) }, | ||
| + | - { AF9015_REMOTE_MYGICTV_U718, | ||
| + | - ir_codes_af9015_table_mygictv, ARRAY_SIZE(ir_codes_af9015_table_mygictv), | ||
| + | - af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) }, | ||
| + | - { AF9015_REMOTE_DIGITTRADE_DVB_T, | ||
| + | - ir_codes_af9015_table_digittrade, ARRAY_SIZE(ir_codes_af9015_table_digittrade), | ||
| + | - af9015_ir_table_digittrade, ARRAY_SIZE(af9015_ir_table_digittrade) }, | ||
| + | - { AF9015_REMOTE_AVERMEDIA_KS, | ||
| + | - ir_codes_af9015_table_avermedia, ARRAY_SIZE(ir_codes_af9015_table_avermedia), | ||
| + | - af9015_ir_table_avermedia_ks, ARRAY_SIZE(af9015_ir_table_avermedia_ks) }, | ||
| + | - { } | ||
| + | -}; | ||
| + | - | ||
| + | -/* don't add new entries here anymore, use hashes instead */ | ||
| + | -static const struct af9015_setup af9015_setup_usbids[] = { | ||
| + | - { USB_VID_LEADTEK, | ||
| + | - ir_codes_af9015_table_leadtek, ARRAY_SIZE(ir_codes_af9015_table_leadtek), | ||
| + | - af9015_ir_table_leadtek, ARRAY_SIZE(af9015_ir_table_leadtek) }, | ||
| + | - { USB_VID_VISIONPLUS, | ||
| + | - ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan), | ||
| + | - af9015_ir_table_twinhan, ARRAY_SIZE(af9015_ir_table_twinhan) }, | ||
| + | - { USB_VID_KWORLD_2, /* TODO: use correct rc keys */ | ||
| + | - ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan), | ||
| + | - af9015_ir_table_kworld, ARRAY_SIZE(af9015_ir_table_kworld) }, | ||
| + | - { USB_VID_AVERMEDIA, | ||
| + | - ir_codes_af9015_table_avermedia, ARRAY_SIZE(ir_codes_af9015_table_avermedia), | ||
| + | - af9015_ir_table_avermedia, ARRAY_SIZE(af9015_ir_table_avermedia) }, | ||
| + | - { USB_VID_MSI_2, | ||
| + | - ir_codes_af9015_table_msi_digivox_iii, ARRAY_SIZE(ir_codes_af9015_table_msi_digivox_iii), | ||
| + | - af9015_ir_table_msi_digivox_iii, ARRAY_SIZE(af9015_ir_table_msi_digivox_iii) }, | ||
| + | - { } | ||
| + | -}; | ||
| + | - | ||
| + | -static const struct af9015_setup af9015_setup_hashes[] = { | ||
| + | - { 0xb8feb708, | ||
| + | - ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi), | ||
| + | - af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) }, | ||
| + | - { 0xa3703d00, | ||
| + | - ir_codes_af9015_table_a_link, ARRAY_SIZE(ir_codes_af9015_table_a_link), | ||
| + | - af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) }, | ||
| + | - { 0x9b7dc64e, | ||
| + | - ir_codes_af9015_table_mygictv, ARRAY_SIZE(ir_codes_af9015_table_mygictv), | ||
| + | - af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) }, | ||
| + | - { } | ||
| + | -}; | ||
| + | - | ||
| + | -static void af9015_set_remote_config(struct usb_device *udev, | ||
| + | - struct dvb_usb_device_properties *props) | ||
| + | -{ | ||
| + | - const struct af9015_setup *table = NULL; | ||
| + | - | ||
| + | - if (dvb_usb_af9015_remote) { | ||
| + | - /* load remote defined as module param */ | ||
| + | - table = af9015_setup_match(dvb_usb_af9015_remote, | ||
| + | - af9015_setup_modparam); | ||
| + | - } else { | ||
| + | - u16 vendor = le16_to_cpu(udev->descriptor.idVendor); | ||
| + | - | ||
| + | - table = af9015_setup_match(af9015_config.eeprom_sum, | ||
| + | - af9015_setup_hashes); | ||
| + | - | ||
| + | - if (!table && vendor == 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(udev, udev->descriptor.iManufacturer, | ||
| + | - manufacturer, sizeof(manufacturer)); | ||
| + | - if (!strcmp("MSI", manufacturer)) { | ||
| + | - /* iManufacturer 1 MSI | ||
| + | - iProduct 2 MSI K-VOX */ | ||
| + | - table = af9015_setup_match( | ||
| + | - AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, | ||
| + | - af9015_setup_modparam); | ||
| + | - } else if (udev->descriptor.idProduct == | ||
| + | - cpu_to_le16(USB_PID_TREKSTOR_DVBT)) { | ||
| + | - table = &(const struct af9015_setup){ 0, | ||
| + | - ir_codes_af9015_table_trekstor, | ||
| + | - ARRAY_SIZE(ir_codes_af9015_table_trekstor), | ||
| + | - af9015_ir_table_trekstor, | ||
| + | - ARRAY_SIZE(af9015_ir_table_trekstor) | ||
| + | - }; | ||
| + | - } | ||
| + | - } else if (!table) | ||
| + | - table = af9015_setup_match(vendor, af9015_setup_usbids); | ||
| + | - } | ||
| + | - | ||
| + | - if (table) { | ||
| + | - props->rc_key_map = table->rc_key_map; | ||
| + | - props->rc_key_map_size = table->rc_key_map_size; | ||
| + | - af9015_config.ir_table = table->ir_table; | ||
| + | - af9015_config.ir_table_size = table->ir_table_size; | ||
| + | - } | ||
| + | -} | ||
| + | - | ||
| + | static int af9015_read_config(struct usb_device *udev) | ||
| + | { | ||
| + | int ret; | ||
| + | u8 val, i, offset = 0; | ||
| + | struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; | ||
| + | + char manufacturer[10]; | ||
| + | |||
| + | /* IR remote controller */ | ||
| + | req.addr = AF9015_EEPROM_IR_MODE; | ||
| + | @@ -871,17 +716,158 @@ | ||
| + | if (ret) | ||
| + | goto error; | ||
| + | |||
| + | - ret = af9015_eeprom_hash(udev); | ||
| + | - if (ret) | ||
| + | - goto error; | ||
| + | - | ||
| + | deb_info("%s: IR mode:%d\n", __func__, val); | ||
| + | for (i = 0; i < af9015_properties_count; i++) { | ||
| + | if (val == AF9015_IR_MODE_DISABLED) { | ||
| + | af9015_properties[i].rc_key_map = NULL; | ||
| + | af9015_properties[i].rc_key_map_size = 0; | ||
| + | - } else | ||
| + | - af9015_set_remote_config(udev, &af9015_properties[i]); | ||
| + | + } else if (dvb_usb_af9015_remote) { | ||
| + | + /* load remote defined as module param */ | ||
| + | + switch (dvb_usb_af9015_remote) { | ||
| + | + case AF9015_REMOTE_A_LINK_DTU_M: | ||
| + | + af9015_properties[i].rc_key_map = | ||
| + | + ir_codes_af9015_table_a_link; | ||
| + | + af9015_properties[i].rc_key_map_size = | ||
| + | + ARRAY_SIZE(ir_codes_af9015_table_a_link); | ||
| + | + af9015_config.ir_table = af9015_ir_table_a_link; | ||
| + | + af9015_config.ir_table_size = | ||
| + | + ARRAY_SIZE(af9015_ir_table_a_link); | ||
| + | + break; | ||
| + | + case AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3: | ||
| + | + af9015_properties[i].rc_key_map = | ||
| + | + ir_codes_af9015_table_msi; | ||
| + | + af9015_properties[i].rc_key_map_size = | ||
| + | + ARRAY_SIZE(ir_codes_af9015_table_msi); | ||
| + | + af9015_config.ir_table = af9015_ir_table_msi; | ||
| + | + af9015_config.ir_table_size = | ||
| + | + ARRAY_SIZE(af9015_ir_table_msi); | ||
| + | + break; | ||
| + | + case AF9015_REMOTE_MYGICTV_U718: | ||
| + | + af9015_properties[i].rc_key_map = | ||
| + | + ir_codes_af9015_table_mygictv; | ||
| + | + af9015_properties[i].rc_key_map_size = | ||
| + | + ARRAY_SIZE(ir_codes_af9015_table_mygictv); | ||
| + | + af9015_config.ir_table = | ||
| + | + af9015_ir_table_mygictv; | ||
| + | + af9015_config.ir_table_size = | ||
| + | + ARRAY_SIZE(af9015_ir_table_mygictv); | ||
| + | + break; | ||
| + | + case AF9015_REMOTE_DIGITTRADE_DVB_T: | ||
| + | + af9015_properties[i].rc_key_map = | ||
| + | + ir_codes_af9015_table_digittrade; | ||
| + | + af9015_properties[i].rc_key_map_size = | ||
| + | + ARRAY_SIZE(ir_codes_af9015_table_digittrade); | ||
| + | + af9015_config.ir_table = | ||
| + | + af9015_ir_table_digittrade; | ||
| + | + af9015_config.ir_table_size = | ||
| + | + ARRAY_SIZE(af9015_ir_table_digittrade); | ||
| + | + break; | ||
| + | + case AF9015_REMOTE_AVERMEDIA_KS: | ||
| + | + af9015_properties[i].rc_key_map = | ||
| + | + ir_codes_af9015_table_avermedia; | ||
| + | + af9015_properties[i].rc_key_map_size = | ||
| + | + ARRAY_SIZE(ir_codes_af9015_table_avermedia); | ||
| + | + af9015_config.ir_table = | ||
| + | + af9015_ir_table_avermedia_ks; | ||
| + | + af9015_config.ir_table_size = | ||
| + | + ARRAY_SIZE(af9015_ir_table_avermedia_ks); | ||
| + | + break; | ||
| + | + } | ||
| + | + } else { | ||
| + | + switch (le16_to_cpu(udev->descriptor.idVendor)) { | ||
| + | + case USB_VID_LEADTEK: | ||
| + | + af9015_properties[i].rc_key_map = | ||
| + | + ir_codes_af9015_table_leadtek; | ||
| + | + af9015_properties[i].rc_key_map_size = | ||
| + | + ARRAY_SIZE(ir_codes_af9015_table_leadtek); | ||
| + | + af9015_config.ir_table = | ||
| + | + af9015_ir_table_leadtek; | ||
| + | + af9015_config.ir_table_size = | ||
| + | + ARRAY_SIZE(af9015_ir_table_leadtek); | ||
| + | + break; | ||
| + | + case USB_VID_VISIONPLUS: | ||
| + | + af9015_properties[i].rc_key_map = | ||
| + | + ir_codes_af9015_table_twinhan; | ||
| + | + af9015_properties[i].rc_key_map_size = | ||
| + | + ARRAY_SIZE(ir_codes_af9015_table_twinhan); | ||
| + | + af9015_config.ir_table = | ||
| + | + af9015_ir_table_twinhan; | ||
| + | + af9015_config.ir_table_size = | ||
| + | + ARRAY_SIZE(af9015_ir_table_twinhan); | ||
| + | + break; | ||
| + | + case USB_VID_KWORLD_2: | ||
| + | + /* TODO: use correct rc keys */ | ||
| + | + af9015_properties[i].rc_key_map = | ||
| + | + ir_codes_af9015_table_twinhan; | ||
| + | + af9015_properties[i].rc_key_map_size = | ||
| + | + ARRAY_SIZE(ir_codes_af9015_table_twinhan); | ||
| + | + af9015_config.ir_table = af9015_ir_table_kworld; | ||
| + | + af9015_config.ir_table_size = | ||
| + | + ARRAY_SIZE(af9015_ir_table_kworld); | ||
| + | + break; | ||
| + | + /* Check USB manufacturer and product strings and try | ||
| + | + to determine correct remote in case of chip vendor | ||
| + | + reference IDs are used. */ | ||
| + | + case USB_VID_AFATECH: | ||
| + | + memset(manufacturer, 0, sizeof(manufacturer)); | ||
| + | + usb_string(udev, udev->descriptor.iManufacturer, | ||
| + | + manufacturer, sizeof(manufacturer)); | ||
| + | + if (!strcmp("Geniatech", manufacturer)) { | ||
| + | + /* iManufacturer 1 Geniatech | ||
| + | + iProduct 2 AF9015 */ | ||
| + | + af9015_properties[i].rc_key_map = | ||
| + | + ir_codes_af9015_table_mygictv; | ||
| + | + af9015_properties[i].rc_key_map_size = | ||
| + | + ARRAY_SIZE(ir_codes_af9015_table_mygictv); | ||
| + | + af9015_config.ir_table = | ||
| + | + af9015_ir_table_mygictv; | ||
| + | + af9015_config.ir_table_size = | ||
| + | + ARRAY_SIZE(af9015_ir_table_mygictv); | ||
| + | + } else if (!strcmp("MSI", manufacturer)) { | ||
| + | + /* iManufacturer 1 MSI | ||
| + | + iProduct 2 MSI K-VOX */ | ||
| + | + af9015_properties[i].rc_key_map = | ||
| + | + ir_codes_af9015_table_msi; | ||
| + | + af9015_properties[i].rc_key_map_size = | ||
| + | + ARRAY_SIZE(ir_codes_af9015_table_msi); | ||
| + | + af9015_config.ir_table = | ||
| + | + af9015_ir_table_msi; | ||
| + | + af9015_config.ir_table_size = | ||
| + | + ARRAY_SIZE(af9015_ir_table_msi); | ||
| + | + } else if (udev->descriptor.idProduct == | ||
| + | + cpu_to_le16(USB_PID_TREKSTOR_DVBT)) { | ||
| + | + af9015_properties[i].rc_key_map = | ||
| + | + ir_codes_af9015_table_trekstor; | ||
| + | + af9015_properties[i].rc_key_map_size = | ||
| + | + ARRAY_SIZE(ir_codes_af9015_table_trekstor); | ||
| + | + af9015_config.ir_table = | ||
| + | + af9015_ir_table_trekstor; | ||
| + | + af9015_config.ir_table_size = | ||
| + | + ARRAY_SIZE(af9015_ir_table_trekstor); | ||
| + | + } | ||
| + | + break; | ||
| + | + case USB_VID_AVERMEDIA: | ||
| + | + af9015_properties[i].rc_key_map = | ||
| + | + ir_codes_af9015_table_avermedia; | ||
| + | + af9015_properties[i].rc_key_map_size = | ||
| + | + ARRAY_SIZE(ir_codes_af9015_table_avermedia); | ||
| + | + af9015_config.ir_table = | ||
| + | + af9015_ir_table_avermedia; | ||
| + | + af9015_config.ir_table_size = | ||
| + | + ARRAY_SIZE(af9015_ir_table_avermedia); | ||
| + | + break; | ||
| + | + case USB_VID_MSI_2: | ||
| + | + af9015_properties[i].rc_key_map = | ||
| + | + ir_codes_af9015_table_msi_digivox_iii; | ||
| + | + af9015_properties[i].rc_key_map_size = | ||
| + | + ARRAY_SIZE(ir_codes_af9015_table_msi_digivox_iii); | ||
| + | + af9015_config.ir_table = | ||
| + | + af9015_ir_table_msi_digivox_iii; | ||
| + | + af9015_config.ir_table_size = | ||
| + | + ARRAY_SIZE(af9015_ir_table_msi_digivox_iii); | ||
| + | + break; | ||
| + | + } | ||
| + | + } | ||
| + | } | ||
| + | |||
| + | /* TS mode - one or two receivers */ | ||
| + | @@ -992,6 +978,7 @@ | ||
| + | case AF9013_TUNER_MT2060_2: | ||
| + | case AF9013_TUNER_TDA18271: | ||
| + | case AF9013_TUNER_QT1010A: | ||
| + | + case AF9013_TUNER_TDA18218: | ||
| + | af9015_af9013_config[i].rf_spec_inv = 1; | ||
| + | break; | ||
| + | case AF9013_TUNER_MXL5003D: | ||
| + | @@ -1003,9 +990,6 @@ | ||
| + | af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO; | ||
| + | af9015_af9013_config[i].rf_spec_inv = 1; | ||
| + | break; | ||
| + | - case AF9013_TUNER_TDA18218: | ||
| + | - warn("tuner NXP TDA18218 not supported yet"); | ||
| + | - return -ENODEV; | ||
| + | default: | ||
| + | warn("tuner id:%d not supported, please report!", val); | ||
| + | return -ENODEV; | ||
| + | @@ -1208,6 +1192,10 @@ | ||
| + | .dig_out = 1, | ||
| + | }; | ||
| + | |||
| + | +static struct tda18218_config af9015_tda18218_config = { | ||
| + | + .i2c_address = 0xc0, | ||
| + | +}; | ||
| + | + | ||
| + | static int af9015_tuner_attach(struct dvb_usb_adapter *adap) | ||
| + | { | ||
| + | struct af9015_state *state = adap->dev->priv; | ||
| + | @@ -1255,6 +1243,10 @@ | ||
| + | ret = dvb_attach(mc44s803_attach, adap->fe, i2c_adap, | ||
| + | &af9015_mc44s803_config) == NULL ? -ENODEV : 0; | ||
| + | break; | ||
| + | + case AF9013_TUNER_TDA18218: | ||
| + | + ret = dvb_attach(tda18218_attach, adap->fe, i2c_adap, | ||
| + | + &af9015_tda18218_config) == NULL ? -ENODEV : 0; | ||
| + | + break; | ||
| + | case AF9013_TUNER_UNKNOWN: | ||
| + | default: | ||
| + | ret = -ENODEV; | ||
| + | @@ -1299,6 +1291,7 @@ | ||
| + | {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)}, | ||
| + | /* 30 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)}, | ||
| + | {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)}, | ||
| + | + {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC)}, | ||
| + | {0}, | ||
| + | }; | ||
| + | MODULE_DEVICE_TABLE(usb, af9015_usb_table); | ||
| + | @@ -1607,8 +1600,8 @@ | ||
| + | .warm_ids = {NULL}, | ||
| + | }, | ||
| + | { | ||
| + | - .name = "Leadtek WinFast DTV2000DS", | ||
| + | - .cold_ids = {&af9015_usb_table[29], NULL}, | ||
| + | + .name = "TerraTec Cinergy T Stick RC", | ||
| + | + .cold_ids = {&af9015_usb_table[32], NULL}, | ||
| + | .warm_ids = {NULL}, | ||
| + | }, | ||
| + | { | ||
| + | diff -Nru linux-2.6.35.4/drivers/media/dvb/dvb-usb/dvb-usb-ids.h /usr/src/linux-2.6.35.4/drivers/media/dvb/dvb-usb/dvb-usb-ids.h | ||
| + | --- linux-2.6.35.4/drivers/media/dvb/dvb-usb/dvb-usb-ids.h 2010-08-27 01:47:12.000000000 +0200 | ||
| + | +++ /usr/src/linux-2.6.35.4/drivers/media/dvb/dvb-usb/dvb-usb-ids.h 2011-01-04 14:45:53.600000024 +0100 | ||
| + | @@ -133,6 +133,7 @@ | ||
| + | #define USB_PID_KWORLD_VSTREAM_WARM 0x17df | ||
| + | #define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055 | ||
| + | #define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069 | ||
| + | +#define USB_PID_TERRATEC_CINERGY_T_STICK_RC 0x0097 | ||
| + | #define USB_PID_TWINHAN_VP7041_COLD 0x3201 | ||
| + | #define USB_PID_TWINHAN_VP7041_WARM 0x3202 | ||
| + | #define USB_PID_TWINHAN_VP7020_COLD 0x3203 | ||
| + | diff -Nru linux-2.6.35.4/drivers/media/dvb/frontends/af9013.c /usr/src/linux-2.6.35.4/drivers/media/dvb/frontends/af9013.c | ||
| + | --- linux-2.6.35.4/drivers/media/dvb/frontends/af9013.c 2010-08-27 01:47:12.000000000 +0200 | ||
| + | +++ /usr/src/linux-2.6.35.4/drivers/media/dvb/frontends/af9013.c 2011-01-04 14:48:59.535000023 +0100 | ||
| + | @@ -487,6 +487,20 @@ | ||
| + | break; | ||
| + | } | ||
| + | } | ||
| + | + else if(state->config.tuner == AF9013_TUNER_TDA18218) { | ||
| + | + switch (bw) { | ||
| + | + case BANDWIDTH_6_MHZ: | ||
| + | + if_sample_freq = 3000000; /* 3 MHz */ | ||
| + | + break; | ||
| + | + case BANDWIDTH_7_MHZ: | ||
| + | + if_sample_freq = 3500000; /* 3.5 MHz */ | ||
| + | + break; | ||
| + | + case BANDWIDTH_8_MHZ: | ||
| + | + default: | ||
| + | + if_sample_freq = 4000000; /* 4 MHz */ | ||
| + | + break; | ||
| + | + } | ||
| + | + } | ||
| + | |||
| + | while (if_sample_freq > (adc_freq / 2)) | ||
| + | if_sample_freq = if_sample_freq - adc_freq; | ||
| + | @@ -1389,6 +1403,7 @@ | ||
| + | init = tuner_init_mt2060_2; | ||
| + | break; | ||
| + | case AF9013_TUNER_TDA18271: | ||
| + | + case AF9013_TUNER_TDA18218: | ||
| + | len = ARRAY_SIZE(tuner_init_tda18271); | ||
| + | init = tuner_init_tda18271; | ||
| + | break; | ||
| + | diff -Nru linux-2.6.35.4/drivers/media/dvb/frontends/af9013_priv.h /usr/src/linux-2.6.35.4/drivers/media/dvb/frontends/af9013_priv.h | ||
| + | --- linux-2.6.35.4/drivers/media/dvb/frontends/af9013_priv.h 2010-08-27 01:47:12.000000000 +0200 | ||
| + | +++ /usr/src/linux-2.6.35.4/drivers/media/dvb/frontends/af9013_priv.h 2011-01-04 14:52:02.621000024 +0100 | ||
| + | @@ -789,8 +789,9 @@ | ||
| + | { 0x9bd9, 0, 8, 0x08 }, | ||
| + | }; | ||
| + | |||
| + | -/* NXP TDA18271 tuner init | ||
| + | - AF9013_TUNER_TDA18271 = 156 */ | ||
| + | +/* NXP TDA18271 & TDA18218 tuner init | ||
| + | + AF9013_TUNER_TDA18271 = 156 | ||
| + | + AF9013_TUNER_TDA18218 = 179 */ | ||
| + | static struct regdesc tuner_init_tda18271[] = { | ||
| + | { 0x9bd5, 0, 8, 0x01 }, | ||
| + | { 0x9bd6, 0, 8, 0x04 }, | ||
</pre> | </pre> | ||
[[Category: DVB-T USB Devices]] | [[Category: DVB-T USB Devices]] | ||
Revision as of 09:29, 5 January 2011
| Vendor Device/Model | Supported | ID on Interface | Hardware | Firmware | Comment / Pictures | URL | E |
|---|---|---|---|---|---|---|---|
| TerraTec Cinergy T USB RC (mk II) | ✔ Yes, in kernel since 2.6.37 | 0ccd:0097 USB2.0 | Afatech AF9015A + TDA18218HN + EM24C02A | dvb-usb-af9015.fw | | [1] | |
Version 2 AF9015
USB ID: 0ccd:0097 Manufacturer: NEWMI
There is a patch available to support this device: http://www.mail-archive.com/linux-media@vger.kernel.org/msg16117.html
However, this patch doesnt fit anymore perfectly on 2.6.35.4 due to some changes on IR and there is no official support in dvb-hg; so this patch needs to be adapted and applied. Testing afterwards can be done as usual, for example with tzap, scan or w_scan. Needs also firmware dvb-usb-af9015.fw.
Uses tuner NXP TDA18218, which is quite similiar to TDA18271. Preliminary support for this tuner is added with the patch above.
After applying patch and loading dvb-usb-af9015 you should see the following:
usb 3-3: new high speed USB device using ehci_hcd and address 3 usb 3-3: New USB device found, idVendor=0ccd, idProduct=0097 usb 3-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3 usb 3-3: Product: USB2.0 DVB-T TV Stick usb 3-3: Manufacturer: NEWMI usb 3-3: SerialNumber: xxxxxxxxxxxxxx dvb-usb: found a 'TerraTec Cinergy T Stick RC' in cold state, will try to load a firmware dvb-usb: downloading firmware from file 'dvb-usb-af9015.fw' dvb-usb: found a 'TerraTec Cinergy T Stick RC' in warm state. dvb-usb: will pass the complete MPEG2 transport stream to the software demuxer. DVB: registering new adapter (TerraTec Cinergy T Stick RC) af9013: firmware version:4.95.0 DVB: registering adapter 4 frontend 0 (Afatech AF9013 DVB-T)... NXP TDA18218 successfully identified. dvb-usb: TerraTec Cinergy T Stick RC successfully initialized and connected. input: NEWMI USB2.0 DVB-T TV Stick as /devices/pci0000:00/0000:00:1a.7/usb3/3-3/3-3:1.1/input/input8 generic-usb 0003:0CCD:0097.0002: input,hidraw0: USB HID v1.01 Keyboard [NEWMI USB2.0 DVB-T TV Stick] on usb-0000:00:1a.7-3/input1
patch with changes to linux-2.6.35.4
diff -Nru linux-2.6.35.4/drivers/media/common/tuners/Kconfig /usr/src/linux-2.6.35.4/drivers/media/common/tuners/Kconfig
--- linux-2.6.35.4/drivers/media/common/tuners/Kconfig 2010-08-27 01:47:12.000000000 +0200
+++ /usr/src/linux-2.6.35.4/drivers/media/common/tuners/Kconfig 2011-01-04 13:59:07.642000010 +0100
@@ -179,4 +179,11 @@
help
A driver for the silicon tuner MAX2165 from Maxim.
+config MEDIA_TUNER_TDA18218
+ tristate "NXP TDA18218 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ A driver for the silicon tuner TDA18218 from NXP.
+
endif # MEDIA_TUNER_CUSTOMISE
diff -Nru linux-2.6.35.4/drivers/media/common/tuners/Makefile /usr/src/linux-2.6.35.4/drivers/media/common/tuners/Makefile
--- linux-2.6.35.4/drivers/media/common/tuners/Makefile 2010-08-27 01:47:12.000000000 +0200
+++ /usr/src/linux-2.6.35.4/drivers/media/common/tuners/Makefile 2011-01-04 13:59:50.733000011 +0100
@@ -24,6 +24,7 @@
obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
+obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff -Nru linux-2.6.35.4/drivers/media/common/tuners/tda18218.c /usr/src/linux-2.6.35.4/drivers/media/common/tuners/tda18218.c
--- linux-2.6.35.4/drivers/media/common/tuners/tda18218.c 1970-01-01 01:00:00.000000000 +0100
+++ /usr/src/linux-2.6.35.4/drivers/media/common/tuners/tda18218.c 2011-01-04 15:22:54.068000023 +0100
@@ -0,0 +1,471 @@
+/*
+ * Driver for NXP TDA18218 silicon tuner
+ *
+ * Copyright (C) 2010 Lauris Ding <ld...@gmx.de>
+ * 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 "tda18218.h"
+//#include "compat.h"
+#include "tda18218_priv.h"
+
+static int tda18218_write_reg(struct dvb_frontend *fe, u8 reg, u8 val)
+{
+ struct tda18218_priv *priv = fe->tuner_priv;
+ u8 buf[2] = { reg, val };
+ struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0,
+ .buf = buf, .len = 2 };
+ int ret;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ /* write register */
+ ret = i2c_transfer(priv->i2c, &msg, 1);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ if (ret != 1)
+ printk(KERN_WARNING "I2C write failed ret: %d reg: %02x\n", ret, reg);
+
+ return (ret == 1 ? 0 : ret);
+}
+
+static int tda18218_write_regs(struct dvb_frontend *fe, u8 reg,
+ u8 *val, u8 len)
+{
+ struct tda18218_priv *priv = fe->tuner_priv;
+ u8 buf[1+len];
+ struct i2c_msg msg = {
+ .addr = priv->cfg->i2c_address,
+ .flags = 0,
+ .len = sizeof(buf),
+ .buf = buf };
+
+ int ret;
+
+ buf[0] = reg;
+ memcpy(&buf[1], val, len);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ ret = i2c_transfer(priv->i2c, &msg, 1);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (ret != 1)
+ printk(KERN_WARNING "I2C write failed ret: %d reg: %02x len: %d\n", ret, reg, len);
+
+ return (ret == 1 ? 0 : ret);
+}
+
+/*static int tda18218_read_reg(struct tda18218_priv *priv, u16 reg, u8 *val)
+{
+ u8 obuf[3] = { reg >> 8, reg & 0xff, 0 };
+ u8 ibuf[1];
+ struct i2c_msg msg[2] = {
+ {
+ .addr = 0x3a,
+ .flags = 0,
+ .len = sizeof(obuf),
+ .buf = obuf
+ }, {
+ .addr = 0x3a,
+ .flags = I2C_M_RD,
+ .len = sizeof(ibuf),
+ .buf = ibuf
+ }
+ };
+
+ if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+ printk(KERN_WARNING "I2C read failed reg:%04x\n", reg);
+ return -EREMOTEIO;
+ }
+ *val = ibuf[0];
+ return 0;
+}*/
+
+static int tda18218_read_regs(struct dvb_frontend *fe)
+{
+ struct tda18218_priv *priv = fe->tuner_priv;
+ u8 *regs = priv->tda18218_regs;
+ u8 buf = 0x00;
+ int ret;
+ //int i;
+ struct i2c_msg msg[] = {
+ { .addr = 0xc0, .flags = 0,
+ .buf = &buf, .len = 1 },
+ { .addr = 0xc0, .flags = I2C_M_RD,
+ .buf = regs, .len = 59 }
+ };
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ /* read all registers */
+ ret = i2c_transfer(priv->i2c, msg, 2);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ if (ret != 2)
+ printk(KERN_WARNING "I2C read failed ret: %d\n", ret);
+
+ /*for(i = 0; i <= 58; i++)
+ printk("Register %d: %02x\n", i, 0xff & regs[i]);*/
+
+ return (ret == 2 ? 0 : ret);
+}
+
+static int tda18218_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct tda18218_priv *priv = fe->tuner_priv;
+ u8 *regs = priv->tda18218_regs;
+ u8 Fc, BP;
+ int i, ret;
+ u16 if1, bw;
+ u32 freq;
+
+ u8 paramsbuf[4][6] = {
+ { 0x03, 0x1a },
+ { 0x04, 0x0a },
+ { 0x01, 0x0f },
+ { 0x01, 0x0f },
+ };
+
+ u8 agcbuf[][2] = {
+ { 0x1a, 0x0e },
+ { 0x20, 0x60 },
+ { 0x23, 0x02 },
+ { 0x20, 0xa0 },
+ { 0x23, 0x09 },
+ { 0x20, 0xe0 },
+ { 0x23, 0x0c },
+ { 0x20, 0x40 },
+ { 0x23, 0x01 },
+ { 0x20, 0x80 },
+ { 0x23, 0x08 },
+ { 0x20, 0xc0 },
+ { 0x23, 0x0b },
+ { 0x24, 0x1c },
+ { 0x24, 0x0c },
+ };
+
+ switch (params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ bw = 6000;
+ Fc = 0;
+ break;
+ case BANDWIDTH_7_MHZ:
+ bw = 7000;
+ Fc = 1;
+ break;
+ case BANDWIDTH_8_MHZ:
+ bw = 8000;
+ Fc = 2;
+ break;
+ default:
+ printk(KERN_WARNING "Invalid bandwidth");
+ return -EINVAL;
+ }
+
+ if1 = bw / 2;
+
+ if((params->frequency >= 174000000) && (params->frequency < 188000000)) {
+ BP = 3;
+ }
+ else if((params->frequency >= 188000000) && (params->frequency < 253000000)) {
+ BP = 4;
+ }
+ else if((params->frequency >= 253000000) && (params->frequency < 343000000)) {
+ BP = 5;
+ }
+ else if((params->frequency >= 343000000) && (params->frequency <= 870000000)) {
+ BP = 6;
+ }
+ else {
+ printk(KERN_WARNING "Frequency out of range");
+ return -EINVAL;
+ }
+
+ freq = params->frequency;
+ freq /= 1000;
+ freq +=if1;
+ freq *= 16;
+
+ tda18218_read_regs(fe);
+
+ paramsbuf[0][2] = regs[0x1a] | BP;
+ paramsbuf[0][3] = regs[0x1b] & ~3;
+ paramsbuf[0][3] = regs[0x1b] | Fc;
+ paramsbuf[0][4] = regs[0x1c] | 0x0a;
+
+ paramsbuf[1][2] = freq >> 16;
+ paramsbuf[1][3] = freq >> 8;
+ paramsbuf[1][4] = (freq & 0xf0) | (regs[0x0c] & 0x0f);
+ paramsbuf[1][5] = 0xff;
+ paramsbuf[2][2] = regs[0x0f] | 0x40;
+ paramsbuf[3][2] = 0x09;
+
+ tda18218_write_reg(fe, 0x04, 0x03);
+
+ for(i = 0; i < ARRAY_SIZE(paramsbuf); i++) {
+
+ /* write registers */
+ ret = tda18218_write_regs(fe, paramsbuf[i][1], ¶msbuf[i][2], paramsbuf[i][0]);
+
+ if (ret)
+ goto error;
+ }
+ for(i = 0; i < ARRAY_SIZE(agcbuf); i++) {
+ tda18218_write_reg(fe, agcbuf[i][0], agcbuf[i][1]);
+ }
+
+ //tda18218_write_reg(fe, 0x03, 0x00);
+ //tda18218_write_reg(fe, 0x04, 0x00);
+ //tda18218_write_reg(fe, 0x20, 0xc7);
+
+ msleep(60);
+ i = 0;
+ while(i < 10) {
+ tda18218_read_regs(fe);
+ if((regs[0x01] & 0x60) == 0x60)
+ printk(KERN_INFO "We've got a lock!"); break;
+ msleep(20);
+ i++;
+ }
+
+ priv->bandwidth = params->u.ofdm.bandwidth;
+ priv->frequency = params->frequency;
+ return 0;
+error:
+ return ret;
+}
+
+static int tda18218_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct tda18218_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static int tda18218_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct tda18218_priv *priv = fe->tuner_priv;
+ *bandwidth = priv->bandwidth;
+ return 0;
+}
+
+static int tda18218_init(struct dvb_frontend *fe)
+{
+ //struct tda18218_priv *priv = fe->tuner_priv;
+ //u8 *regs = priv->tda18218_regs;
+ int i;
+ int ret;
+
+ u8 initbuf[][18] = {
+ { 0x10, 0x05, 0x00, 0x00, 0xd0, 0x00, 0x40, 0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00, 0x01 },
+ { 0x0b, 0x15, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x0e, 0x29, 0x98, 0x00, 0x00, 0x58 },
+ { 0x10, 0x24, 0x0c, 0x48, 0x85, 0xc9, 0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00, 0x8a, 0x00 },
+ { 0x07, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6 },
+ };
+
+ u8 initbuf2[4];
+
+ for(i = 0; i < ARRAY_SIZE(initbuf); i++) {
+
+ /* write registers */
+ ret = tda18218_write_regs(fe, initbuf[i][1], &initbuf[i][2], initbuf[i][0]);
+
+ if (ret != 0) {
+ printk(KERN_ERR "init: ERROR: i2c_transfer returned: %d\n", ret);
+ return -EREMOTEIO;
+ }
+ if(i == 1) {
+ tda18218_write_reg(fe, 0x22, 0x8c);
+ }
+ }
+
+ tda18218_write_reg(fe, 0x05, 0x80);
+ tda18218_write_reg(fe, 0x05, 0x00);
+ tda18218_write_reg(fe, 0x05, 0x20);
+ tda18218_write_reg(fe, 0x05, 0x00);
+ tda18218_write_reg(fe, 0x27, 0xde);
+ tda18218_write_reg(fe, 0x17, 0xf8);
+ tda18218_write_reg(fe, 0x18, 0x0f);
+ tda18218_write_reg(fe, 0x1c, 0x8b);
+ tda18218_write_reg(fe, 0x29, 0x02);
+ tda18218_write_reg(fe, 0x19, 0x1a);
+ tda18218_write_reg(fe, 0x11, 0x13);
+
+ initbuf2[0] = 0x0a;
+ initbuf2[1] = 0x5c;
+ initbuf2[2] = 0xc6;
+ initbuf2[3] = 0x07;
+ tda18218_write_regs(fe, initbuf2[0], &initbuf2[1], 3);
+ tda18218_write_reg(fe, 0x0f, 0x49);
+ tda18218_write_reg(fe, 0x05, 0x40);
+ tda18218_write_reg(fe, 0x05, 0x00);
+ tda18218_write_reg(fe, 0x05, 0x20);
+ tda18218_write_reg(fe, 0x11, 0xed);
+ tda18218_write_reg(fe, 0x0f, 0x49);
+ tda18218_write_reg(fe, 0x19, 0x2a);
+ tda18218_write_reg(fe, 0x05, 0x58);
+ tda18218_write_reg(fe, 0x05, 0x18);
+ tda18218_write_reg(fe, 0x05, 0x38);
+ tda18218_write_reg(fe, 0x29, 0x03);
+ tda18218_write_reg(fe, 0x19, 0x1a);
+ tda18218_write_reg(fe, 0x11, 0x13);
+ initbuf2[0] = 0x0a;
+ initbuf2[1] = 0xbe;
+ initbuf2[2] = 0x6e;
+ initbuf2[3] = 0x07;
+ tda18218_write_regs(fe, initbuf2[0], &initbuf2[1], 3);
+ tda18218_write_reg(fe, 0x0f, 0x49);
+ tda18218_write_reg(fe, 0x05, 0x58);
+ tda18218_write_reg(fe, 0x05, 0x18);
+ tda18218_write_reg(fe, 0x05, 0x38);
+ tda18218_write_reg(fe, 0x11, 0xed);
+ tda18218_write_reg(fe, 0x0f, 0x49);
+ tda18218_write_reg(fe, 0x19, 0x2a);
+ tda18218_write_reg(fe, 0x05, 0x58);
+ tda18218_write_reg(fe, 0x05, 0x18);
+ tda18218_write_reg(fe, 0x05, 0x38);
+ tda18218_write_reg(fe, 0x19, 0x0a);
+ tda18218_write_reg(fe, 0x27, 0xc9);
+ tda18218_write_reg(fe, 0x11, 0x13);
+ initbuf2[0] = 0x17;
+ initbuf2[1] = 0xf0;
+ initbuf2[2] = 0x19;
+ initbuf2[3] = 0x00;
+ tda18218_write_regs(fe, initbuf2[0], &initbuf2[1], 2);
+ tda18218_write_reg(fe, 0x1c, 0x98);
+ tda18218_write_reg(fe, 0x29, 0x03);
+ tda18218_write_reg(fe, 0x2a, 0x00);
+ tda18218_write_reg(fe, 0x2a, 0x01);
+ tda18218_write_reg(fe, 0x2a, 0x02);
+ tda18218_write_reg(fe, 0x2a, 0x03);
+ tda18218_write_reg(fe, 0x1c, 0x98);
+ tda18218_write_reg(fe, 0x18, 0x19);
+ tda18218_write_reg(fe, 0x22, 0x9c);
+ tda18218_write_reg(fe, 0x1f, 0x58);
+ tda18218_write_reg(fe, 0x24, 0x0c);
+ tda18218_write_reg(fe, 0x1c, 0x88);
+ tda18218_write_reg(fe, 0x20, 0x10);
+ tda18218_write_reg(fe, 0x21, 0x4c);
+ tda18218_write_reg(fe, 0x20, 0x00);
+ tda18218_write_reg(fe, 0x21, 0x48);
+ tda18218_write_reg(fe, 0x1f, 0x5b);
+ tda18218_write_reg(fe, 0x20, 0x00);
+ tda18218_write_reg(fe, 0x1f, 0x59);
+ tda18218_write_reg(fe, 0x20, 0x00);
+ tda18218_write_reg(fe, 0x1f, 0x5a);
+ tda18218_write_reg(fe, 0x20, 0x00);
+ tda18218_write_reg(fe, 0x1f, 0x5f);
+ tda18218_write_reg(fe, 0x20, 0x00);
+ tda18218_write_reg(fe, 0x1f, 0x5d);
+ tda18218_write_reg(fe, 0x20, 0x00);
+ tda18218_write_reg(fe, 0x1f, 0x5e);
+ tda18218_write_reg(fe, 0x20, 0x00);
+ tda18218_write_reg(fe, 0x20, 0x60);
+ tda18218_write_reg(fe, 0x23, 0x02);
+ tda18218_write_reg(fe, 0x20, 0xa0);
+ tda18218_write_reg(fe, 0x23, 0x09);
+ tda18218_write_reg(fe, 0x20, 0xe0);
+ tda18218_write_reg(fe, 0x23, 0x0c);
+ tda18218_write_reg(fe, 0x20, 0x40);
+ tda18218_write_reg(fe, 0x23, 0x01);
+ tda18218_write_reg(fe, 0x20, 0x80);
+ tda18218_write_reg(fe, 0x23, 0x08);
+ tda18218_write_reg(fe, 0x20, 0xc0);
+ tda18218_write_reg(fe, 0x23, 0x0b);
+ tda18218_write_reg(fe, 0x1c, 0x98);
+ tda18218_write_reg(fe, 0x22, 0x8c);
+ initbuf2[0] = 0x17;
+ initbuf2[1] = 0xb0;
+ initbuf2[2] = 0x59;
+ initbuf2[3] = 0x00;
+ //tda18218_write_regs(fe, initbuf2[0], &initbuf2[1], 2);
+ initbuf2[0] = 0x1a;
+ initbuf2[1] = 0x0e;
+ initbuf2[2] = 0x2a;
+ initbuf2[3] = 0x98;
+ tda18218_write_regs(fe, initbuf2[0], &initbuf2[1], 3);
+ initbuf2[0] = 0x17;
+ initbuf2[1] = 0xb0;
+ initbuf2[2] = 0x59;
+ initbuf2[3] = 0x00;
+ tda18218_write_regs(fe, initbuf2[0], &initbuf2[1], 2);
+ tda18218_write_reg(fe, 0x2d, 0x81);
+ tda18218_write_reg(fe, 0x29, 0x02);
+
+ return 0;
+}
+
+static int tda18218_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static const struct dvb_tuner_ops tda18218_tuner_ops = {
+ .info = {
+ .name = "NXP TDA18218",
+ .frequency_min = TDA18218_MIN_FREQ,
+ .frequency_max = TDA18218_MAX_FREQ,
+ .frequency_step = TDA18218_STEP,
+ },
+
+ .release = tda18218_release,
+ .init = tda18218_init,
+
+ .set_params = tda18218_set_params,
+ .get_frequency = tda18218_get_frequency,
+ .get_bandwidth = tda18218_get_bandwidth,
+};
+
+struct dvb_frontend * tda18218_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct tda18218_config *cfg)
+{
+ struct tda18218_priv *priv = NULL;
+
+ priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->cfg = cfg;
+ priv->i2c = i2c;
+
+ fe->tuner_priv = priv;
+
+ tda18218_read_regs(fe);
+ if (priv->tda18218_regs[0x00] != 0xc0) {
+ printk(KERN_WARNING "Device is not a TDA18218!\n");
+ kfree(priv);
+ return NULL;
+ }
+
+ printk(KERN_INFO "NXP TDA18218 successfully identified.\n");
+ memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ return fe;
+}
+EXPORT_SYMBOL(tda18218_attach);
+
+MODULE_DESCRIPTION("NXP TDA18218 silicon tuner driver");
+MODULE_AUTHOR("Lauris Ding <ld...@gmx.de>");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff -Nru linux-2.6.35.4/drivers/media/common/tuners/tda18218.h /usr/src/linux-2.6.35.4/drivers/media/common/tuners/tda18218.h
--- linux-2.6.35.4/drivers/media/common/tuners/tda18218.h 1970-01-01 01:00:00.000000000 +0100
+++ /usr/src/linux-2.6.35.4/drivers/media/common/tuners/tda18218.h 2011-01-04 14:03:39.306000007 +0100
@@ -0,0 +1,44 @@
+/*
+ * Driver for NXP TDA18218 silicon tuner
+ *
+ * Copyright (C) 2010 Lauris Ding <ld...@gmx.de>
+ *
+ * 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 TDA18218_H
+#define TDA18218_H
+
+#include "dvb_frontend.h"
+
+struct tda18218_config {
+ u8 i2c_address;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_TDA18218) || (defined(CONFIG_MEDIA_TUNER_TDA18218_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct tda18218_config *cfg);
+#else
+static inline struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct tda18218_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif // CONFIG_MEDIA_TUNER_TDA18218
+
+#endif
diff -Nru linux-2.6.35.4/drivers/media/common/tuners/tda18218_priv.h /usr/src/linux-2.6.35.4/drivers/media/common/tuners/tda18218_priv.h
--- linux-2.6.35.4/drivers/media/common/tuners/tda18218_priv.h 1970-01-01 01:00:00.000000000 +0100
+++ /usr/src/linux-2.6.35.4/drivers/media/common/tuners/tda18218_priv.h 2011-01-04 14:04:36.744000011 +0100
@@ -0,0 +1,36 @@
+/*
+ * Driver for NXP TDA18218 silicon tuner
+ *
+ * Copyright (C) 2010 Lauris Ding <ld...@gmx.de>
+ * 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 TDA18218_PRIV_H
+#define TDA18218_PRIV_H
+
+#define TDA18218_STEP 1000 /* 1 kHz */
+#define TDA18218_MIN_FREQ 174000000 /* 174 MHz */
+#define TDA18218_MAX_FREQ 864000000 /* 864 MHz */
+
+struct tda18218_priv {
+ u8 tda18218_regs[0x3b];
+ struct tda18218_config *cfg;
+ struct i2c_adapter *i2c;
+
+ u32 frequency;
+ u32 bandwidth;
+};
+
+#endif
diff -Nru linux-2.6.35.4/drivers/media/dvb/dvb-usb/af9015.c /usr/src/linux-2.6.35.4/drivers/media/dvb/dvb-usb/af9015.c
--- linux-2.6.35.4/drivers/media/dvb/dvb-usb/af9015.c 2010-08-27 01:47:12.000000000 +0200
+++ /usr/src/linux-2.6.35.4/drivers/media/dvb/dvb-usb/af9015.c 2011-01-05 10:21:43.993000001 +0100
@@ -31,6 +31,7 @@
#include "tda18271.h"
#include "mxl5005s.h"
#include "mc44s803.h"
+#include "tda18218.h"
static int dvb_usb_af9015_debug;
module_param_named(debug, dvb_usb_af9015_debug, int, 0644);
@@ -272,7 +273,8 @@
while (i < num) {
if (msg[i].addr == af9015_af9013_config[0].demod_address ||
- msg[i].addr == af9015_af9013_config[1].demod_address) {
+ msg[i].addr == af9015_af9013_config[1].demod_address ||
+ msg[i].addr == 0x3a) {
addr = msg[i].buf[0] << 8;
addr += msg[i].buf[1];
mbox = msg[i].buf[2];
@@ -285,7 +287,8 @@
if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
if (msg[i].addr ==
- af9015_af9013_config[0].demod_address)
+ af9015_af9013_config[0].demod_address ||
+ msg[i].addr == 0x3a)
req.cmd = READ_MEMORY;
else
req.cmd = READ_I2C;
@@ -300,7 +303,8 @@
} else if (msg[i].flags & I2C_M_RD) {
ret = -EINVAL;
if (msg[i].addr ==
- af9015_af9013_config[0].demod_address)
+ af9015_af9013_config[0].demod_address ||
+ msg[i].addr == 0x3a)
goto error;
else
req.cmd = READ_I2C;
@@ -314,7 +318,8 @@
i += 1;
} else {
if (msg[i].addr ==
- af9015_af9013_config[0].demod_address)
+ af9015_af9013_config[0].demod_address ||
+ msg[i].addr == 0x3a)
req.cmd = WRITE_MEMORY;
else
req.cmd = WRITE_I2C;
@@ -556,46 +561,6 @@
return ret;
}
-/* hash (and dump) eeprom */
-static int af9015_eeprom_hash(struct usb_device *udev)
-{
- static const unsigned int eeprom_size = 256;
- unsigned int reg;
- int ret;
- 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_rw_udev(udev, &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);
-
- af9015_config.eeprom_sum = 0;
- for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) {
- af9015_config.eeprom_sum *= GOLDEN_RATIO_PRIME_32;
- af9015_config.eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]);
- }
-
- deb_info("%s: eeprom sum=%.8x\n", __func__, af9015_config.eeprom_sum);
-
- ret = 0;
-free:
- kfree(eeprom);
- return ret;
-}
static int af9015_download_ir_table(struct dvb_usb_device *d)
{
@@ -733,132 +698,12 @@
return ret;
}
-struct af9015_setup {
- unsigned int id;
- struct dvb_usb_rc_key *rc_key_map;
- unsigned int rc_key_map_size;
- u8 *ir_table;
- unsigned int ir_table_size;
-};
-
-static const struct af9015_setup *af9015_setup_match(unsigned int id,
- const struct af9015_setup *table)
-{
- for (; table->rc_key_map; table++)
- if (table->id == id)
- return table;
- return NULL;
-}
-
-static const struct af9015_setup af9015_setup_modparam[] = {
- { AF9015_REMOTE_A_LINK_DTU_M,
- ir_codes_af9015_table_a_link, ARRAY_SIZE(ir_codes_af9015_table_a_link),
- af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
- { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
- ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi),
- af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
- { AF9015_REMOTE_MYGICTV_U718,
- ir_codes_af9015_table_mygictv, ARRAY_SIZE(ir_codes_af9015_table_mygictv),
- af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
- { AF9015_REMOTE_DIGITTRADE_DVB_T,
- ir_codes_af9015_table_digittrade, ARRAY_SIZE(ir_codes_af9015_table_digittrade),
- af9015_ir_table_digittrade, ARRAY_SIZE(af9015_ir_table_digittrade) },
- { AF9015_REMOTE_AVERMEDIA_KS,
- ir_codes_af9015_table_avermedia, ARRAY_SIZE(ir_codes_af9015_table_avermedia),
- af9015_ir_table_avermedia_ks, ARRAY_SIZE(af9015_ir_table_avermedia_ks) },
- { }
-};
-
-/* don't add new entries here anymore, use hashes instead */
-static const struct af9015_setup af9015_setup_usbids[] = {
- { USB_VID_LEADTEK,
- ir_codes_af9015_table_leadtek, ARRAY_SIZE(ir_codes_af9015_table_leadtek),
- af9015_ir_table_leadtek, ARRAY_SIZE(af9015_ir_table_leadtek) },
- { USB_VID_VISIONPLUS,
- ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan),
- af9015_ir_table_twinhan, ARRAY_SIZE(af9015_ir_table_twinhan) },
- { USB_VID_KWORLD_2, /* TODO: use correct rc keys */
- ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan),
- af9015_ir_table_kworld, ARRAY_SIZE(af9015_ir_table_kworld) },
- { USB_VID_AVERMEDIA,
- ir_codes_af9015_table_avermedia, ARRAY_SIZE(ir_codes_af9015_table_avermedia),
- af9015_ir_table_avermedia, ARRAY_SIZE(af9015_ir_table_avermedia) },
- { USB_VID_MSI_2,
- ir_codes_af9015_table_msi_digivox_iii, ARRAY_SIZE(ir_codes_af9015_table_msi_digivox_iii),
- af9015_ir_table_msi_digivox_iii, ARRAY_SIZE(af9015_ir_table_msi_digivox_iii) },
- { }
-};
-
-static const struct af9015_setup af9015_setup_hashes[] = {
- { 0xb8feb708,
- ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi),
- af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
- { 0xa3703d00,
- ir_codes_af9015_table_a_link, ARRAY_SIZE(ir_codes_af9015_table_a_link),
- af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
- { 0x9b7dc64e,
- ir_codes_af9015_table_mygictv, ARRAY_SIZE(ir_codes_af9015_table_mygictv),
- af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
- { }
-};
-
-static void af9015_set_remote_config(struct usb_device *udev,
- struct dvb_usb_device_properties *props)
-{
- const struct af9015_setup *table = NULL;
-
- if (dvb_usb_af9015_remote) {
- /* load remote defined as module param */
- table = af9015_setup_match(dvb_usb_af9015_remote,
- af9015_setup_modparam);
- } else {
- u16 vendor = le16_to_cpu(udev->descriptor.idVendor);
-
- table = af9015_setup_match(af9015_config.eeprom_sum,
- af9015_setup_hashes);
-
- if (!table && vendor == 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(udev, udev->descriptor.iManufacturer,
- manufacturer, sizeof(manufacturer));
- if (!strcmp("MSI", manufacturer)) {
- /* iManufacturer 1 MSI
- iProduct 2 MSI K-VOX */
- table = af9015_setup_match(
- AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
- af9015_setup_modparam);
- } else if (udev->descriptor.idProduct ==
- cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
- table = &(const struct af9015_setup){ 0,
- ir_codes_af9015_table_trekstor,
- ARRAY_SIZE(ir_codes_af9015_table_trekstor),
- af9015_ir_table_trekstor,
- ARRAY_SIZE(af9015_ir_table_trekstor)
- };
- }
- } else if (!table)
- table = af9015_setup_match(vendor, af9015_setup_usbids);
- }
-
- if (table) {
- props->rc_key_map = table->rc_key_map;
- props->rc_key_map_size = table->rc_key_map_size;
- af9015_config.ir_table = table->ir_table;
- af9015_config.ir_table_size = table->ir_table_size;
- }
-}
-
static int af9015_read_config(struct usb_device *udev)
{
int ret;
u8 val, i, offset = 0;
struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
+ char manufacturer[10];
/* IR remote controller */
req.addr = AF9015_EEPROM_IR_MODE;
@@ -871,17 +716,158 @@
if (ret)
goto error;
- ret = af9015_eeprom_hash(udev);
- if (ret)
- goto error;
-
deb_info("%s: IR mode:%d\n", __func__, val);
for (i = 0; i < af9015_properties_count; i++) {
if (val == AF9015_IR_MODE_DISABLED) {
af9015_properties[i].rc_key_map = NULL;
af9015_properties[i].rc_key_map_size = 0;
- } else
- af9015_set_remote_config(udev, &af9015_properties[i]);
+ } else if (dvb_usb_af9015_remote) {
+ /* load remote defined as module param */
+ switch (dvb_usb_af9015_remote) {
+ case AF9015_REMOTE_A_LINK_DTU_M:
+ af9015_properties[i].rc_key_map =
+ ir_codes_af9015_table_a_link;
+ af9015_properties[i].rc_key_map_size =
+ ARRAY_SIZE(ir_codes_af9015_table_a_link);
+ af9015_config.ir_table = af9015_ir_table_a_link;
+ af9015_config.ir_table_size =
+ ARRAY_SIZE(af9015_ir_table_a_link);
+ break;
+ case AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3:
+ af9015_properties[i].rc_key_map =
+ ir_codes_af9015_table_msi;
+ af9015_properties[i].rc_key_map_size =
+ ARRAY_SIZE(ir_codes_af9015_table_msi);
+ af9015_config.ir_table = af9015_ir_table_msi;
+ af9015_config.ir_table_size =
+ ARRAY_SIZE(af9015_ir_table_msi);
+ break;
+ case AF9015_REMOTE_MYGICTV_U718:
+ af9015_properties[i].rc_key_map =
+ ir_codes_af9015_table_mygictv;
+ af9015_properties[i].rc_key_map_size =
+ ARRAY_SIZE(ir_codes_af9015_table_mygictv);
+ af9015_config.ir_table =
+ af9015_ir_table_mygictv;
+ af9015_config.ir_table_size =
+ ARRAY_SIZE(af9015_ir_table_mygictv);
+ break;
+ case AF9015_REMOTE_DIGITTRADE_DVB_T:
+ af9015_properties[i].rc_key_map =
+ ir_codes_af9015_table_digittrade;
+ af9015_properties[i].rc_key_map_size =
+ ARRAY_SIZE(ir_codes_af9015_table_digittrade);
+ af9015_config.ir_table =
+ af9015_ir_table_digittrade;
+ af9015_config.ir_table_size =
+ ARRAY_SIZE(af9015_ir_table_digittrade);
+ break;
+ case AF9015_REMOTE_AVERMEDIA_KS:
+ af9015_properties[i].rc_key_map =
+ ir_codes_af9015_table_avermedia;
+ af9015_properties[i].rc_key_map_size =
+ ARRAY_SIZE(ir_codes_af9015_table_avermedia);
+ af9015_config.ir_table =
+ af9015_ir_table_avermedia_ks;
+ af9015_config.ir_table_size =
+ ARRAY_SIZE(af9015_ir_table_avermedia_ks);
+ break;
+ }
+ } else {
+ switch (le16_to_cpu(udev->descriptor.idVendor)) {
+ case USB_VID_LEADTEK:
+ af9015_properties[i].rc_key_map =
+ ir_codes_af9015_table_leadtek;
+ af9015_properties[i].rc_key_map_size =
+ ARRAY_SIZE(ir_codes_af9015_table_leadtek);
+ af9015_config.ir_table =
+ af9015_ir_table_leadtek;
+ af9015_config.ir_table_size =
+ ARRAY_SIZE(af9015_ir_table_leadtek);
+ break;
+ case USB_VID_VISIONPLUS:
+ af9015_properties[i].rc_key_map =
+ ir_codes_af9015_table_twinhan;
+ af9015_properties[i].rc_key_map_size =
+ ARRAY_SIZE(ir_codes_af9015_table_twinhan);
+ af9015_config.ir_table =
+ af9015_ir_table_twinhan;
+ af9015_config.ir_table_size =
+ ARRAY_SIZE(af9015_ir_table_twinhan);
+ break;
+ case USB_VID_KWORLD_2:
+ /* TODO: use correct rc keys */
+ af9015_properties[i].rc_key_map =
+ ir_codes_af9015_table_twinhan;
+ af9015_properties[i].rc_key_map_size =
+ ARRAY_SIZE(ir_codes_af9015_table_twinhan);
+ af9015_config.ir_table = af9015_ir_table_kworld;
+ af9015_config.ir_table_size =
+ ARRAY_SIZE(af9015_ir_table_kworld);
+ break;
+ /* Check USB manufacturer and product strings and try
+ to determine correct remote in case of chip vendor
+ reference IDs are used. */
+ case USB_VID_AFATECH:
+ memset(manufacturer, 0, sizeof(manufacturer));
+ usb_string(udev, udev->descriptor.iManufacturer,
+ manufacturer, sizeof(manufacturer));
+ if (!strcmp("Geniatech", manufacturer)) {
+ /* iManufacturer 1 Geniatech
+ iProduct 2 AF9015 */
+ af9015_properties[i].rc_key_map =
+ ir_codes_af9015_table_mygictv;
+ af9015_properties[i].rc_key_map_size =
+ ARRAY_SIZE(ir_codes_af9015_table_mygictv);
+ af9015_config.ir_table =
+ af9015_ir_table_mygictv;
+ af9015_config.ir_table_size =
+ ARRAY_SIZE(af9015_ir_table_mygictv);
+ } else if (!strcmp("MSI", manufacturer)) {
+ /* iManufacturer 1 MSI
+ iProduct 2 MSI K-VOX */
+ af9015_properties[i].rc_key_map =
+ ir_codes_af9015_table_msi;
+ af9015_properties[i].rc_key_map_size =
+ ARRAY_SIZE(ir_codes_af9015_table_msi);
+ af9015_config.ir_table =
+ af9015_ir_table_msi;
+ af9015_config.ir_table_size =
+ ARRAY_SIZE(af9015_ir_table_msi);
+ } else if (udev->descriptor.idProduct ==
+ cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
+ af9015_properties[i].rc_key_map =
+ ir_codes_af9015_table_trekstor;
+ af9015_properties[i].rc_key_map_size =
+ ARRAY_SIZE(ir_codes_af9015_table_trekstor);
+ af9015_config.ir_table =
+ af9015_ir_table_trekstor;
+ af9015_config.ir_table_size =
+ ARRAY_SIZE(af9015_ir_table_trekstor);
+ }
+ break;
+ case USB_VID_AVERMEDIA:
+ af9015_properties[i].rc_key_map =
+ ir_codes_af9015_table_avermedia;
+ af9015_properties[i].rc_key_map_size =
+ ARRAY_SIZE(ir_codes_af9015_table_avermedia);
+ af9015_config.ir_table =
+ af9015_ir_table_avermedia;
+ af9015_config.ir_table_size =
+ ARRAY_SIZE(af9015_ir_table_avermedia);
+ break;
+ case USB_VID_MSI_2:
+ af9015_properties[i].rc_key_map =
+ ir_codes_af9015_table_msi_digivox_iii;
+ af9015_properties[i].rc_key_map_size =
+ ARRAY_SIZE(ir_codes_af9015_table_msi_digivox_iii);
+ af9015_config.ir_table =
+ af9015_ir_table_msi_digivox_iii;
+ af9015_config.ir_table_size =
+ ARRAY_SIZE(af9015_ir_table_msi_digivox_iii);
+ break;
+ }
+ }
}
/* TS mode - one or two receivers */
@@ -992,6 +978,7 @@
case AF9013_TUNER_MT2060_2:
case AF9013_TUNER_TDA18271:
case AF9013_TUNER_QT1010A:
+ case AF9013_TUNER_TDA18218:
af9015_af9013_config[i].rf_spec_inv = 1;
break;
case AF9013_TUNER_MXL5003D:
@@ -1003,9 +990,6 @@
af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO;
af9015_af9013_config[i].rf_spec_inv = 1;
break;
- case AF9013_TUNER_TDA18218:
- warn("tuner NXP TDA18218 not supported yet");
- return -ENODEV;
default:
warn("tuner id:%d not supported, please report!", val);
return -ENODEV;
@@ -1208,6 +1192,10 @@
.dig_out = 1,
};
+static struct tda18218_config af9015_tda18218_config = {
+ .i2c_address = 0xc0,
+};
+
static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
{
struct af9015_state *state = adap->dev->priv;
@@ -1255,6 +1243,10 @@
ret = dvb_attach(mc44s803_attach, adap->fe, i2c_adap,
&af9015_mc44s803_config) == NULL ? -ENODEV : 0;
break;
+ case AF9013_TUNER_TDA18218:
+ ret = dvb_attach(tda18218_attach, adap->fe, i2c_adap,
+ &af9015_tda18218_config) == NULL ? -ENODEV : 0;
+ break;
case AF9013_TUNER_UNKNOWN:
default:
ret = -ENODEV;
@@ -1299,6 +1291,7 @@
{USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)},
/* 30 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)},
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)},
+ {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC)},
{0},
};
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1607,8 +1600,8 @@
.warm_ids = {NULL},
},
{
- .name = "Leadtek WinFast DTV2000DS",
- .cold_ids = {&af9015_usb_table[29], NULL},
+ .name = "TerraTec Cinergy T Stick RC",
+ .cold_ids = {&af9015_usb_table[32], NULL},
.warm_ids = {NULL},
},
{
diff -Nru linux-2.6.35.4/drivers/media/dvb/dvb-usb/dvb-usb-ids.h /usr/src/linux-2.6.35.4/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
--- linux-2.6.35.4/drivers/media/dvb/dvb-usb/dvb-usb-ids.h 2010-08-27 01:47:12.000000000 +0200
+++ /usr/src/linux-2.6.35.4/drivers/media/dvb/dvb-usb/dvb-usb-ids.h 2011-01-04 14:45:53.600000024 +0100
@@ -133,6 +133,7 @@
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
#define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055
#define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069
+#define USB_PID_TERRATEC_CINERGY_T_STICK_RC 0x0097
#define USB_PID_TWINHAN_VP7041_COLD 0x3201
#define USB_PID_TWINHAN_VP7041_WARM 0x3202
#define USB_PID_TWINHAN_VP7020_COLD 0x3203
diff -Nru linux-2.6.35.4/drivers/media/dvb/frontends/af9013.c /usr/src/linux-2.6.35.4/drivers/media/dvb/frontends/af9013.c
--- linux-2.6.35.4/drivers/media/dvb/frontends/af9013.c 2010-08-27 01:47:12.000000000 +0200
+++ /usr/src/linux-2.6.35.4/drivers/media/dvb/frontends/af9013.c 2011-01-04 14:48:59.535000023 +0100
@@ -487,6 +487,20 @@
break;
}
}
+ else if(state->config.tuner == AF9013_TUNER_TDA18218) {
+ switch (bw) {
+ case BANDWIDTH_6_MHZ:
+ if_sample_freq = 3000000; /* 3 MHz */
+ break;
+ case BANDWIDTH_7_MHZ:
+ if_sample_freq = 3500000; /* 3.5 MHz */
+ break;
+ case BANDWIDTH_8_MHZ:
+ default:
+ if_sample_freq = 4000000; /* 4 MHz */
+ break;
+ }
+ }
while (if_sample_freq > (adc_freq / 2))
if_sample_freq = if_sample_freq - adc_freq;
@@ -1389,6 +1403,7 @@
init = tuner_init_mt2060_2;
break;
case AF9013_TUNER_TDA18271:
+ case AF9013_TUNER_TDA18218:
len = ARRAY_SIZE(tuner_init_tda18271);
init = tuner_init_tda18271;
break;
diff -Nru linux-2.6.35.4/drivers/media/dvb/frontends/af9013_priv.h /usr/src/linux-2.6.35.4/drivers/media/dvb/frontends/af9013_priv.h
--- linux-2.6.35.4/drivers/media/dvb/frontends/af9013_priv.h 2010-08-27 01:47:12.000000000 +0200
+++ /usr/src/linux-2.6.35.4/drivers/media/dvb/frontends/af9013_priv.h 2011-01-04 14:52:02.621000024 +0100
@@ -789,8 +789,9 @@
{ 0x9bd9, 0, 8, 0x08 },
};
-/* NXP TDA18271 tuner init
- AF9013_TUNER_TDA18271 = 156 */
+/* NXP TDA18271 & TDA18218 tuner init
+ AF9013_TUNER_TDA18271 = 156
+ AF9013_TUNER_TDA18218 = 179 */
static struct regdesc tuner_init_tda18271[] = {
{ 0x9bd5, 0, 8, 0x01 },
{ 0x9bd6, 0, 8, 0x04 },