From 25aee3debe0464f6c680173041fa3de30ec9ff54 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 14 Jun 2012 16:35:57 -0300 Subject: [media] Rename media/dvb as media/pci The remaining dvb drivers are pci, so rename them to match the bus. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/Kconfig | 13 + drivers/media/pci/ngene/Makefile | 14 + drivers/media/pci/ngene/ngene-cards.c | 823 ++++++++++++++++ drivers/media/pci/ngene/ngene-core.c | 1707 +++++++++++++++++++++++++++++++++ drivers/media/pci/ngene/ngene-dvb.c | 261 +++++ drivers/media/pci/ngene/ngene-i2c.c | 176 ++++ drivers/media/pci/ngene/ngene.h | 921 ++++++++++++++++++ 7 files changed, 3915 insertions(+) create mode 100644 drivers/media/pci/ngene/Kconfig create mode 100644 drivers/media/pci/ngene/Makefile create mode 100644 drivers/media/pci/ngene/ngene-cards.c create mode 100644 drivers/media/pci/ngene/ngene-core.c create mode 100644 drivers/media/pci/ngene/ngene-dvb.c create mode 100644 drivers/media/pci/ngene/ngene-i2c.c create mode 100644 drivers/media/pci/ngene/ngene.h (limited to 'drivers/media/pci/ngene') diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig new file mode 100644 index 000000000000..64c84702ba5c --- /dev/null +++ b/drivers/media/pci/ngene/Kconfig @@ -0,0 +1,13 @@ +config DVB_NGENE + tristate "Micronas nGene support" + depends on DVB_CORE && PCI && I2C + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_STV6110x if !DVB_FE_CUSTOMISE + select DVB_STV090x if !DVB_FE_CUSTOMISE + select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_DRXK if !DVB_FE_CUSTOMISE + select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE + ---help--- + Support for Micronas PCI express cards with nGene bridge. + diff --git a/drivers/media/pci/ngene/Makefile b/drivers/media/pci/ngene/Makefile new file mode 100644 index 000000000000..63997089f9d1 --- /dev/null +++ b/drivers/media/pci/ngene/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for the nGene device driver +# + +ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o + +obj-$(CONFIG_DVB_NGENE) += ngene.o + +ccflags-y += -Idrivers/media/dvb-core/ +ccflags-y += -Idrivers/media/dvb-frontends/ +ccflags-y += -Idrivers/media/common/tuners/ + +# For the staging CI driver cxd2099 +ccflags-y += -Idrivers/staging/media/cxd2099/ diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c new file mode 100644 index 000000000000..a6cd6959ad19 --- /dev/null +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -0,0 +1,823 @@ +/* + * ngene-cards.c: nGene PCIe bridge driver - card specific info + * + * Copyright (C) 2005-2007 Micronas + * + * Copyright (C) 2008-2009 Ralph Metzler + * Modifications for new nGene firmware, + * support for EEPROM-copying, + * support for new dual DVB-S2 card prototype + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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 + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include + +#include "ngene.h" + +/* demods/tuners */ +#include "stv6110x.h" +#include "stv090x.h" +#include "lnbh24.h" +#include "lgdt330x.h" +#include "mt2131.h" +#include "tda18271c2dd.h" +#include "drxk.h" +#include "drxd.h" +#include "dvb-pll.h" + + +/****************************************************************************/ +/* Demod/tuner attachment ***************************************************/ +/****************************************************************************/ + +static int tuner_attach_stv6110(struct ngene_channel *chan) +{ + struct i2c_adapter *i2c; + struct stv090x_config *feconf = (struct stv090x_config *) + chan->dev->card_info->fe_config[chan->number]; + struct stv6110x_config *tunerconf = (struct stv6110x_config *) + chan->dev->card_info->tuner_config[chan->number]; + struct stv6110x_devctl *ctl; + + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + if (chan->number < 2) + i2c = &chan->dev->channel[0].i2c_adapter; + else + i2c = &chan->dev->channel[1].i2c_adapter; + + ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c); + if (ctl == NULL) { + printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n"); + return -ENODEV; + } + + feconf->tuner_init = ctl->tuner_init; + feconf->tuner_sleep = ctl->tuner_sleep; + feconf->tuner_set_mode = ctl->tuner_set_mode; + feconf->tuner_set_frequency = ctl->tuner_set_frequency; + feconf->tuner_get_frequency = ctl->tuner_get_frequency; + feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth; + feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth; + feconf->tuner_set_bbgain = ctl->tuner_set_bbgain; + feconf->tuner_get_bbgain = ctl->tuner_get_bbgain; + feconf->tuner_set_refclk = ctl->tuner_set_refclk; + feconf->tuner_get_status = ctl->tuner_get_status; + + return 0; +} + + +static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct ngene_channel *chan = fe->sec_priv; + int status; + + if (enable) { + down(&chan->dev->pll_mutex); + status = chan->gate_ctrl(fe, 1); + } else { + status = chan->gate_ctrl(fe, 0); + up(&chan->dev->pll_mutex); + } + return status; +} + +static int tuner_attach_tda18271(struct ngene_channel *chan) +{ + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + + i2c = &chan->dev->channel[0].i2c_adapter; + if (chan->fe->ops.i2c_gate_ctrl) + chan->fe->ops.i2c_gate_ctrl(chan->fe, 1); + fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60); + if (chan->fe->ops.i2c_gate_ctrl) + chan->fe->ops.i2c_gate_ctrl(chan->fe, 0); + if (!fe) { + printk(KERN_ERR "No TDA18271 found!\n"); + return -ENODEV; + } + + return 0; +} + +static int tuner_attach_probe(struct ngene_channel *chan) +{ + if (chan->demod_type == 0) + return tuner_attach_stv6110(chan); + if (chan->demod_type == 1) + return tuner_attach_tda18271(chan); + return -EINVAL; +} + +static int demod_attach_stv0900(struct ngene_channel *chan) +{ + struct i2c_adapter *i2c; + struct stv090x_config *feconf = (struct stv090x_config *) + chan->dev->card_info->fe_config[chan->number]; + + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + /* Note: Both adapters share the same i2c bus, but the demod */ + /* driver requires that each demod has its own i2c adapter */ + if (chan->number < 2) + i2c = &chan->dev->channel[0].i2c_adapter; + else + i2c = &chan->dev->channel[1].i2c_adapter; + + chan->fe = dvb_attach(stv090x_attach, feconf, i2c, + (chan->number & 1) == 0 ? STV090x_DEMODULATOR_0 + : STV090x_DEMODULATOR_1); + if (chan->fe == NULL) { + printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n"); + return -ENODEV; + } + + /* store channel info */ + if (feconf->tuner_i2c_lock) + chan->fe->analog_demod_priv = chan; + + if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0, + 0, chan->dev->card_info->lnb[chan->number])) { + printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n"); + dvb_frontend_detach(chan->fe); + chan->fe = NULL; + return -ENODEV; + } + + return 0; +} + +static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock) +{ + struct ngene_channel *chan = fe->analog_demod_priv; + + if (lock) + down(&chan->dev->pll_mutex); + else + up(&chan->dev->pll_mutex); +} + +static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) +{ + struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1 } }; + return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; +} + +static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, + u16 reg, u8 *val) +{ + u8 msg[2] = {reg>>8, reg&0xff}; + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = msg, .len = 2}, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1} }; + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int port_has_stv0900(struct i2c_adapter *i2c, int port) +{ + u8 val; + if (i2c_read_reg16(i2c, 0x68+port/2, 0xf100, &val) < 0) + return 0; + return 1; +} + +static int port_has_drxk(struct i2c_adapter *i2c, int port) +{ + u8 val; + + if (i2c_read(i2c, 0x29+port, &val) < 0) + return 0; + return 1; +} + +static int demod_attach_drxk(struct ngene_channel *chan, + struct i2c_adapter *i2c) +{ + struct drxk_config config; + + memset(&config, 0, sizeof(config)); + config.microcode_name = "drxk_a3.mc"; + config.qam_demod_parameter_count = 4; + config.adr = 0x29 + (chan->number ^ 2); + + chan->fe = dvb_attach(drxk_attach, &config, i2c); + if (!chan->fe) { + printk(KERN_ERR "No DRXK found!\n"); + return -ENODEV; + } + chan->fe->sec_priv = chan; + chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl; + chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; + return 0; +} + +static int cineS2_probe(struct ngene_channel *chan) +{ + struct i2c_adapter *i2c; + struct stv090x_config *fe_conf; + u8 buf[3]; + struct i2c_msg i2c_msg = { .flags = 0, .buf = buf }; + int rc; + + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + if (chan->number < 2) + i2c = &chan->dev->channel[0].i2c_adapter; + else + i2c = &chan->dev->channel[1].i2c_adapter; + + if (port_has_stv0900(i2c, chan->number)) { + chan->demod_type = 0; + fe_conf = chan->dev->card_info->fe_config[chan->number]; + /* demod found, attach it */ + rc = demod_attach_stv0900(chan); + if (rc < 0 || chan->number < 2) + return rc; + + /* demod #2: reprogram outputs DPN1 & DPN2 */ + i2c_msg.addr = fe_conf->address; + i2c_msg.len = 3; + buf[0] = 0xf1; + switch (chan->number) { + case 2: + buf[1] = 0x5c; + buf[2] = 0xc2; + break; + case 3: + buf[1] = 0x61; + buf[2] = 0xcc; + break; + default: + return -ENODEV; + } + rc = i2c_transfer(i2c, &i2c_msg, 1); + if (rc != 1) { + printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n"); + return -EIO; + } + } else if (port_has_drxk(i2c, chan->number^2)) { + chan->demod_type = 1; + demod_attach_drxk(chan, i2c); + } else { + printk(KERN_ERR "No demod found on chan %d\n", chan->number); + return -ENODEV; + } + return 0; +} + + +static struct lgdt330x_config aver_m780 = { + .demod_address = 0xb2 >> 1, + .demod_chip = LGDT3303, + .serial_mpeg = 0x00, /* PARALLEL */ + .clock_polarity_flip = 1, +}; + +static struct mt2131_config m780_tunerconfig = { + 0xc0 >> 1 +}; + +/* A single func to attach the demo and tuner, rather than + * use two sep funcs like the current design mandates. + */ +static int demod_attach_lg330x(struct ngene_channel *chan) +{ + chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, &chan->i2c_adapter); + if (chan->fe == NULL) { + printk(KERN_ERR DEVICE_NAME ": No LGDT330x found!\n"); + return -ENODEV; + } + + dvb_attach(mt2131_attach, chan->fe, &chan->i2c_adapter, + &m780_tunerconfig, 0); + + return (chan->fe) ? 0 : -ENODEV; +} + +static int demod_attach_drxd(struct ngene_channel *chan) +{ + struct drxd_config *feconf; + + feconf = chan->dev->card_info->fe_config[chan->number]; + + chan->fe = dvb_attach(drxd_attach, feconf, chan, + &chan->i2c_adapter, &chan->dev->pci_dev->dev); + if (!chan->fe) { + pr_err("No DRXD found!\n"); + return -ENODEV; + } + + if (!dvb_attach(dvb_pll_attach, chan->fe, feconf->pll_address, + &chan->i2c_adapter, + feconf->pll_type)) { + pr_err("No pll(%d) found!\n", feconf->pll_type); + return -ENODEV; + } + return 0; +} + +/****************************************************************************/ +/* EEPROM TAGS **************************************************************/ +/****************************************************************************/ + +#define MICNG_EE_START 0x0100 +#define MICNG_EE_END 0x0FF0 + +#define MICNG_EETAG_END0 0x0000 +#define MICNG_EETAG_END1 0xFFFF + +/* 0x0001 - 0x000F reserved for housekeeping */ +/* 0xFFFF - 0xFFFE reserved for housekeeping */ + +/* Micronas assigned tags + EEProm tags for hardware support */ + +#define MICNG_EETAG_DRXD1_OSCDEVIATION 0x1000 /* 2 Bytes data */ +#define MICNG_EETAG_DRXD2_OSCDEVIATION 0x1001 /* 2 Bytes data */ + +#define MICNG_EETAG_MT2060_1_1STIF 0x1100 /* 2 Bytes data */ +#define MICNG_EETAG_MT2060_2_1STIF 0x1101 /* 2 Bytes data */ + +/* Tag range for OEMs */ + +#define MICNG_EETAG_OEM_FIRST 0xC000 +#define MICNG_EETAG_OEM_LAST 0xFFEF + +static int i2c_write_eeprom(struct i2c_adapter *adapter, + u8 adr, u16 reg, u8 data) +{ + u8 m[3] = {(reg >> 8), (reg & 0xff), data}; + struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, + .len = sizeof(m)}; + + if (i2c_transfer(adapter, &msg, 1) != 1) { + pr_err(DEVICE_NAME ": Error writing EEPROM!\n"); + return -EIO; + } + return 0; +} + +static int i2c_read_eeprom(struct i2c_adapter *adapter, + u8 adr, u16 reg, u8 *data, int len) +{ + u8 msg[2] = {(reg >> 8), (reg & 0xff)}; + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = msg, .len = 2 }, + {.addr = adr, .flags = I2C_M_RD, + .buf = data, .len = len} }; + + if (i2c_transfer(adapter, msgs, 2) != 2) { + pr_err(DEVICE_NAME ": Error reading EEPROM\n"); + return -EIO; + } + return 0; +} + +static int ReadEEProm(struct i2c_adapter *adapter, + u16 Tag, u32 MaxLen, u8 *data, u32 *pLength) +{ + int status = 0; + u16 Addr = MICNG_EE_START, Length, tag = 0; + u8 EETag[3]; + + while (Addr + sizeof(u16) + 1 < MICNG_EE_END) { + if (i2c_read_eeprom(adapter, 0x50, Addr, EETag, sizeof(EETag))) + return -1; + tag = (EETag[0] << 8) | EETag[1]; + if (tag == MICNG_EETAG_END0 || tag == MICNG_EETAG_END1) + return -1; + if (tag == Tag) + break; + Addr += sizeof(u16) + 1 + EETag[2]; + } + if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) { + pr_err(DEVICE_NAME + ": Reached EOEE @ Tag = %04x Length = %3d\n", + tag, EETag[2]); + return -1; + } + Length = EETag[2]; + if (Length > MaxLen) + Length = (u16) MaxLen; + if (Length > 0) { + Addr += sizeof(u16) + 1; + status = i2c_read_eeprom(adapter, 0x50, Addr, data, Length); + if (!status) { + *pLength = EETag[2]; + if (Length < EETag[2]) + ; /*status=STATUS_BUFFER_OVERFLOW; */ + } + } + return status; +} + +static int WriteEEProm(struct i2c_adapter *adapter, + u16 Tag, u32 Length, u8 *data) +{ + int status = 0; + u16 Addr = MICNG_EE_START; + u8 EETag[3]; + u16 tag = 0; + int retry, i; + + while (Addr + sizeof(u16) + 1 < MICNG_EE_END) { + if (i2c_read_eeprom(adapter, 0x50, Addr, EETag, sizeof(EETag))) + return -1; + tag = (EETag[0] << 8) | EETag[1]; + if (tag == MICNG_EETAG_END0 || tag == MICNG_EETAG_END1) + return -1; + if (tag == Tag) + break; + Addr += sizeof(u16) + 1 + EETag[2]; + } + if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) { + pr_err(DEVICE_NAME + ": Reached EOEE @ Tag = %04x Length = %3d\n", + tag, EETag[2]); + return -1; + } + + if (Length > EETag[2]) + return -EINVAL; + /* Note: We write the data one byte at a time to avoid + issues with page sizes. (which are different for + each manufacture and eeprom size) + */ + Addr += sizeof(u16) + 1; + for (i = 0; i < Length; i++, Addr++) { + status = i2c_write_eeprom(adapter, 0x50, Addr, data[i]); + + if (status) + break; + + /* Poll for finishing write cycle */ + retry = 10; + while (retry) { + u8 Tmp; + + msleep(50); + status = i2c_read_eeprom(adapter, 0x50, Addr, &Tmp, 1); + if (status) + break; + if (Tmp != data[i]) + pr_err(DEVICE_NAME + "eeprom write error\n"); + retry -= 1; + } + if (status) { + pr_err(DEVICE_NAME + ": Timeout polling eeprom\n"); + break; + } + } + return status; +} + +static int eeprom_read_ushort(struct i2c_adapter *adapter, u16 tag, u16 *data) +{ + int stat; + u8 buf[2]; + u32 len = 0; + + stat = ReadEEProm(adapter, tag, 2, buf, &len); + if (stat) + return stat; + if (len != 2) + return -EINVAL; + + *data = (buf[0] << 8) | buf[1]; + return 0; +} + +static int eeprom_write_ushort(struct i2c_adapter *adapter, u16 tag, u16 data) +{ + int stat; + u8 buf[2]; + + buf[0] = data >> 8; + buf[1] = data & 0xff; + stat = WriteEEProm(adapter, tag, 2, buf); + if (stat) + return stat; + return 0; +} + +static s16 osc_deviation(void *priv, s16 deviation, int flag) +{ + struct ngene_channel *chan = priv; + struct i2c_adapter *adap = &chan->i2c_adapter; + u16 data = 0; + + if (flag) { + data = (u16) deviation; + pr_info(DEVICE_NAME ": write deviation %d\n", + deviation); + eeprom_write_ushort(adap, 0x1000 + chan->number, data); + } else { + if (eeprom_read_ushort(adap, 0x1000 + chan->number, &data)) + data = 0; + pr_info(DEVICE_NAME ": read deviation %d\n", + (s16) data); + } + + return (s16) data; +} + +/****************************************************************************/ +/* Switch control (I2C gates, etc.) *****************************************/ +/****************************************************************************/ + + +static struct stv090x_config fe_cineS2 = { + .device = STV0900, + .demod_mode = STV090x_DUAL, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 27000000, + .address = 0x68, + + .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + + .repeater_level = STV090x_RPTLEVEL_16, + + .adc1_range = STV090x_ADC_1Vpp, + .adc2_range = STV090x_ADC_1Vpp, + + .diseqc_envelope_mode = true, + + .tuner_i2c_lock = cineS2_tuner_i2c_lock, +}; + +static struct stv090x_config fe_cineS2_2 = { + .device = STV0900, + .demod_mode = STV090x_DUAL, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 27000000, + .address = 0x69, + + .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + + .repeater_level = STV090x_RPTLEVEL_16, + + .adc1_range = STV090x_ADC_1Vpp, + .adc2_range = STV090x_ADC_1Vpp, + + .diseqc_envelope_mode = true, + + .tuner_i2c_lock = cineS2_tuner_i2c_lock, +}; + +static struct stv6110x_config tuner_cineS2_0 = { + .addr = 0x60, + .refclk = 27000000, + .clk_div = 1, +}; + +static struct stv6110x_config tuner_cineS2_1 = { + .addr = 0x63, + .refclk = 27000000, + .clk_div = 1, +}; + +static struct ngene_info ngene_info_cineS2 = { + .type = NGENE_SIDEWINDER, + .name = "Linux4Media cineS2 DVB-S2 Twin Tuner", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, + .fe_config = {&fe_cineS2, &fe_cineS2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0b, 0x08}, + .tsf = {3, 3}, + .fw_version = 18, + .msi_supported = true, +}; + +static struct ngene_info ngene_info_satixS2 = { + .type = NGENE_SIDEWINDER, + .name = "Mystique SaTiX-S2 Dual", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, + .fe_config = {&fe_cineS2, &fe_cineS2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0b, 0x08}, + .tsf = {3, 3}, + .fw_version = 18, + .msi_supported = true, +}; + +static struct ngene_info ngene_info_satixS2v2 = { + .type = NGENE_SIDEWINDER, + .name = "Mystique SaTiX-S2 Dual (v2)", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, + NGENE_IO_TSOUT}, + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe}, + .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0a, 0x08, 0x0b, 0x09}, + .tsf = {3, 3}, + .fw_version = 18, + .msi_supported = true, +}; + +static struct ngene_info ngene_info_cineS2v5 = { + .type = NGENE_SIDEWINDER, + .name = "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, + NGENE_IO_TSOUT}, + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe}, + .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0a, 0x08, 0x0b, 0x09}, + .tsf = {3, 3}, + .fw_version = 18, + .msi_supported = true, +}; + + +static struct ngene_info ngene_info_duoFlex = { + .type = NGENE_SIDEWINDER, + .name = "Digital Devices DuoFlex PCIe or miniPCIe", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, + NGENE_IO_TSOUT}, + .demod_attach = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe}, + .tuner_attach = {tuner_attach_probe, tuner_attach_probe, tuner_attach_probe, tuner_attach_probe}, + .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0a, 0x08, 0x0b, 0x09}, + .tsf = {3, 3}, + .fw_version = 18, + .msi_supported = true, +}; + +static struct ngene_info ngene_info_m780 = { + .type = NGENE_APP, + .name = "Aver M780 ATSC/QAM-B", + + /* Channel 0 is analog, which is currently unsupported */ + .io_type = { NGENE_IO_NONE, NGENE_IO_TSIN }, + .demod_attach = { NULL, demod_attach_lg330x }, + + /* Ensure these are NULL else the frame will call them (as funcs) */ + .tuner_attach = { 0, 0, 0, 0 }, + .fe_config = { NULL, &aver_m780 }, + .avf = { 0 }, + + /* A custom electrical interface config for the demod to bridge */ + .tsf = { 4, 4 }, + .fw_version = 15, +}; + +static struct drxd_config fe_terratec_dvbt_0 = { + .index = 0, + .demod_address = 0x70, + .demod_revision = 0xa2, + .demoda_address = 0x00, + .pll_address = 0x60, + .pll_type = DVB_PLL_THOMSON_DTT7520X, + .clock = 20000, + .osc_deviation = osc_deviation, +}; + +static struct drxd_config fe_terratec_dvbt_1 = { + .index = 1, + .demod_address = 0x71, + .demod_revision = 0xa2, + .demoda_address = 0x00, + .pll_address = 0x60, + .pll_type = DVB_PLL_THOMSON_DTT7520X, + .clock = 20000, + .osc_deviation = osc_deviation, +}; + +static struct ngene_info ngene_info_terratec = { + .type = NGENE_TERRATEC, + .name = "Terratec Integra/Cinergy2400i Dual DVB-T", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, + .demod_attach = {demod_attach_drxd, demod_attach_drxd}, + .fe_config = {&fe_terratec_dvbt_0, &fe_terratec_dvbt_1}, + .i2c_access = 1, +}; + +/****************************************************************************/ + + + +/****************************************************************************/ +/* PCI Subsystem ID *********************************************************/ +/****************************************************************************/ + +#define NGENE_ID(_subvend, _subdev, _driverdata) { \ + .vendor = NGENE_VID, .device = NGENE_PID, \ + .subvendor = _subvend, .subdevice = _subdev, \ + .driver_data = (unsigned long) &_driverdata } + +/****************************************************************************/ + +static const struct pci_device_id ngene_id_tbl[] __devinitdata = { + NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2), + NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2), + NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2), + NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2), + NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5), + NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlex), + NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlex), + NGENE_ID(0x1461, 0x062e, ngene_info_m780), + NGENE_ID(0x153b, 0x1167, ngene_info_terratec), + {0} +}; +MODULE_DEVICE_TABLE(pci, ngene_id_tbl); + +/****************************************************************************/ +/* Init/Exit ****************************************************************/ +/****************************************************************************/ + +static pci_ers_result_t ngene_error_detected(struct pci_dev *dev, + enum pci_channel_state state) +{ + printk(KERN_ERR DEVICE_NAME ": PCI error\n"); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (state == pci_channel_io_frozen) + return PCI_ERS_RESULT_NEED_RESET; + return PCI_ERS_RESULT_CAN_RECOVER; +} + +static pci_ers_result_t ngene_link_reset(struct pci_dev *dev) +{ + printk(KERN_INFO DEVICE_NAME ": link reset\n"); + return 0; +} + +static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev) +{ + printk(KERN_INFO DEVICE_NAME ": slot reset\n"); + return 0; +} + +static void ngene_resume(struct pci_dev *dev) +{ + printk(KERN_INFO DEVICE_NAME ": resume\n"); +} + +static struct pci_error_handlers ngene_errors = { + .error_detected = ngene_error_detected, + .link_reset = ngene_link_reset, + .slot_reset = ngene_slot_reset, + .resume = ngene_resume, +}; + +static struct pci_driver ngene_pci_driver = { + .name = "ngene", + .id_table = ngene_id_tbl, + .probe = ngene_probe, + .remove = __devexit_p(ngene_remove), + .err_handler = &ngene_errors, + .shutdown = ngene_shutdown, +}; + +static __init int module_init_ngene(void) +{ + printk(KERN_INFO + "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n"); + return pci_register_driver(&ngene_pci_driver); +} + +static __exit void module_exit_ngene(void) +{ + pci_unregister_driver(&ngene_pci_driver); +} + +module_init(module_init_ngene); +module_exit(module_exit_ngene); + +MODULE_DESCRIPTION("nGene"); +MODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c new file mode 100644 index 000000000000..c8e0d5b99d4c --- /dev/null +++ b/drivers/media/pci/ngene/ngene-core.c @@ -0,0 +1,1707 @@ +/* + * ngene.c: nGene PCIe bridge driver + * + * Copyright (C) 2005-2007 Micronas + * + * Copyright (C) 2008-2009 Ralph Metzler + * Modifications for new nGene firmware, + * support for EEPROM-copying, + * support for new dual DVB-S2 card prototype + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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 + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ngene.h" + +static int one_adapter; +module_param(one_adapter, int, 0444); +MODULE_PARM_DESC(one_adapter, "Use only one adapter."); + +static int shutdown_workaround; +module_param(shutdown_workaround, int, 0644); +MODULE_PARM_DESC(shutdown_workaround, "Activate workaround for shutdown problem with some chipsets."); + +static int debug; +module_param(debug, int, 0444); +MODULE_PARM_DESC(debug, "Print debugging information."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define dprintk if (debug) printk + +#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) +#define ngwritel(dat, adr) writel((dat), (char *)(dev->iomem + (adr))) +#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) +#define ngreadl(adr) readl(dev->iomem + (adr)) +#define ngreadb(adr) readb(dev->iomem + (adr)) +#define ngcpyto(adr, src, count) memcpy_toio((char *) \ + (dev->iomem + (adr)), (src), (count)) +#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \ + (dev->iomem + (adr)), (count)) + +/****************************************************************************/ +/* nGene interrupt handler **************************************************/ +/****************************************************************************/ + +static void event_tasklet(unsigned long data) +{ + struct ngene *dev = (struct ngene *)data; + + while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) { + struct EVENT_BUFFER Event = + dev->EventQueue[dev->EventQueueReadIndex]; + dev->EventQueueReadIndex = + (dev->EventQueueReadIndex + 1) & (EVENT_QUEUE_SIZE - 1); + + if ((Event.UARTStatus & 0x01) && (dev->TxEventNotify)) + dev->TxEventNotify(dev, Event.TimeStamp); + if ((Event.UARTStatus & 0x02) && (dev->RxEventNotify)) + dev->RxEventNotify(dev, Event.TimeStamp, + Event.RXCharacter); + } +} + +static void demux_tasklet(unsigned long data) +{ + struct ngene_channel *chan = (struct ngene_channel *)data; + struct SBufferHeader *Cur = chan->nextBuffer; + + spin_lock_irq(&chan->state_lock); + + while (Cur->ngeneBuffer.SR.Flags & 0x80) { + if (chan->mode & NGENE_IO_TSOUT) { + u32 Flags = chan->DataFormatFlags; + if (Cur->ngeneBuffer.SR.Flags & 0x20) + Flags |= BEF_OVERFLOW; + if (chan->pBufferExchange) { + if (!chan->pBufferExchange(chan, + Cur->Buffer1, + chan->Capture1Length, + Cur->ngeneBuffer.SR. + Clock, Flags)) { + /* + We didn't get data + Clear in service flag to make sure we + get called on next interrupt again. + leave fill/empty (0x80) flag alone + to avoid hardware running out of + buffers during startup, we hold only + in run state ( the source may be late + delivering data ) + */ + + if (chan->HWState == HWSTATE_RUN) { + Cur->ngeneBuffer.SR.Flags &= + ~0x40; + break; + /* Stop processing stream */ + } + } else { + /* We got a valid buffer, + so switch to run state */ + chan->HWState = HWSTATE_RUN; + } + } else { + printk(KERN_ERR DEVICE_NAME ": OOPS\n"); + if (chan->HWState == HWSTATE_RUN) { + Cur->ngeneBuffer.SR.Flags &= ~0x40; + break; /* Stop processing stream */ + } + } + if (chan->AudioDTOUpdated) { + printk(KERN_INFO DEVICE_NAME + ": Update AudioDTO = %d\n", + chan->AudioDTOValue); + Cur->ngeneBuffer.SR.DTOUpdate = + chan->AudioDTOValue; + chan->AudioDTOUpdated = 0; + } + } else { + if (chan->HWState == HWSTATE_RUN) { + u32 Flags = chan->DataFormatFlags; + IBufferExchange *exch1 = chan->pBufferExchange; + IBufferExchange *exch2 = chan->pBufferExchange2; + if (Cur->ngeneBuffer.SR.Flags & 0x01) + Flags |= BEF_EVEN_FIELD; + if (Cur->ngeneBuffer.SR.Flags & 0x20) + Flags |= BEF_OVERFLOW; + spin_unlock_irq(&chan->state_lock); + if (exch1) + exch1(chan, Cur->Buffer1, + chan->Capture1Length, + Cur->ngeneBuffer.SR.Clock, + Flags); + if (exch2) + exch2(chan, Cur->Buffer2, + chan->Capture2Length, + Cur->ngeneBuffer.SR.Clock, + Flags); + spin_lock_irq(&chan->state_lock); + } else if (chan->HWState != HWSTATE_STOP) + chan->HWState = HWSTATE_RUN; + } + Cur->ngeneBuffer.SR.Flags = 0x00; + Cur = Cur->Next; + } + chan->nextBuffer = Cur; + + spin_unlock_irq(&chan->state_lock); +} + +static irqreturn_t irq_handler(int irq, void *dev_id) +{ + struct ngene *dev = (struct ngene *)dev_id; + u32 icounts = 0; + irqreturn_t rc = IRQ_NONE; + u32 i = MAX_STREAM; + u8 *tmpCmdDoneByte; + + if (dev->BootFirmware) { + icounts = ngreadl(NGENE_INT_COUNTS); + if (icounts != dev->icounts) { + ngwritel(0, FORCE_NMI); + dev->cmd_done = 1; + wake_up(&dev->cmd_wq); + dev->icounts = icounts; + rc = IRQ_HANDLED; + } + return rc; + } + + ngwritel(0, FORCE_NMI); + + spin_lock(&dev->cmd_lock); + tmpCmdDoneByte = dev->CmdDoneByte; + if (tmpCmdDoneByte && + (*tmpCmdDoneByte || + (dev->ngenetohost[0] == 1 && dev->ngenetohost[1] != 0))) { + dev->CmdDoneByte = NULL; + dev->cmd_done = 1; + wake_up(&dev->cmd_wq); + rc = IRQ_HANDLED; + } + spin_unlock(&dev->cmd_lock); + + if (dev->EventBuffer->EventStatus & 0x80) { + u8 nextWriteIndex = + (dev->EventQueueWriteIndex + 1) & + (EVENT_QUEUE_SIZE - 1); + if (nextWriteIndex != dev->EventQueueReadIndex) { + dev->EventQueue[dev->EventQueueWriteIndex] = + *(dev->EventBuffer); + dev->EventQueueWriteIndex = nextWriteIndex; + } else { + printk(KERN_ERR DEVICE_NAME ": event overflow\n"); + dev->EventQueueOverflowCount += 1; + dev->EventQueueOverflowFlag = 1; + } + dev->EventBuffer->EventStatus &= ~0x80; + tasklet_schedule(&dev->event_tasklet); + rc = IRQ_HANDLED; + } + + while (i > 0) { + i--; + spin_lock(&dev->channel[i].state_lock); + /* if (dev->channel[i].State>=KSSTATE_RUN) { */ + if (dev->channel[i].nextBuffer) { + if ((dev->channel[i].nextBuffer-> + ngeneBuffer.SR.Flags & 0xC0) == 0x80) { + dev->channel[i].nextBuffer-> + ngeneBuffer.SR.Flags |= 0x40; + tasklet_schedule( + &dev->channel[i].demux_tasklet); + rc = IRQ_HANDLED; + } + } + spin_unlock(&dev->channel[i].state_lock); + } + + /* Request might have been processed by a previous call. */ + return IRQ_HANDLED; +} + +/****************************************************************************/ +/* nGene command interface **************************************************/ +/****************************************************************************/ + +static void dump_command_io(struct ngene *dev) +{ + u8 buf[8], *b; + + ngcpyfrom(buf, HOST_TO_NGENE, 8); + printk(KERN_ERR "host_to_ngene (%04x): %*ph\n", HOST_TO_NGENE, 8, buf); + + ngcpyfrom(buf, NGENE_TO_HOST, 8); + printk(KERN_ERR "ngene_to_host (%04x): %*ph\n", NGENE_TO_HOST, 8, buf); + + b = dev->hosttongene; + printk(KERN_ERR "dev->hosttongene (%p): %*ph\n", b, 8, b); + + b = dev->ngenetohost; + printk(KERN_ERR "dev->ngenetohost (%p): %*ph\n", b, 8, b); +} + +static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com) +{ + int ret; + u8 *tmpCmdDoneByte; + + dev->cmd_done = 0; + + if (com->cmd.hdr.Opcode == CMD_FWLOAD_PREPARE) { + dev->BootFirmware = 1; + dev->icounts = ngreadl(NGENE_INT_COUNTS); + ngwritel(0, NGENE_COMMAND); + ngwritel(0, NGENE_COMMAND_HI); + ngwritel(0, NGENE_STATUS); + ngwritel(0, NGENE_STATUS_HI); + ngwritel(0, NGENE_EVENT); + ngwritel(0, NGENE_EVENT_HI); + } else if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) { + u64 fwio = dev->PAFWInterfaceBuffer; + + ngwritel(fwio & 0xffffffff, NGENE_COMMAND); + ngwritel(fwio >> 32, NGENE_COMMAND_HI); + ngwritel((fwio + 256) & 0xffffffff, NGENE_STATUS); + ngwritel((fwio + 256) >> 32, NGENE_STATUS_HI); + ngwritel((fwio + 512) & 0xffffffff, NGENE_EVENT); + ngwritel((fwio + 512) >> 32, NGENE_EVENT_HI); + } + + memcpy(dev->FWInterfaceBuffer, com->cmd.raw8, com->in_len + 2); + + if (dev->BootFirmware) + ngcpyto(HOST_TO_NGENE, com->cmd.raw8, com->in_len + 2); + + spin_lock_irq(&dev->cmd_lock); + tmpCmdDoneByte = dev->ngenetohost + com->out_len; + if (!com->out_len) + tmpCmdDoneByte++; + *tmpCmdDoneByte = 0; + dev->ngenetohost[0] = 0; + dev->ngenetohost[1] = 0; + dev->CmdDoneByte = tmpCmdDoneByte; + spin_unlock_irq(&dev->cmd_lock); + + /* Notify 8051. */ + ngwritel(1, FORCE_INT); + + ret = wait_event_timeout(dev->cmd_wq, dev->cmd_done == 1, 2 * HZ); + if (!ret) { + /*ngwritel(0, FORCE_NMI);*/ + + printk(KERN_ERR DEVICE_NAME + ": Command timeout cmd=%02x prev=%02x\n", + com->cmd.hdr.Opcode, dev->prev_cmd); + dump_command_io(dev); + return -1; + } + if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) + dev->BootFirmware = 0; + + dev->prev_cmd = com->cmd.hdr.Opcode; + + if (!com->out_len) + return 0; + + memcpy(com->cmd.raw8, dev->ngenetohost, com->out_len); + + return 0; +} + +int ngene_command(struct ngene *dev, struct ngene_command *com) +{ + int result; + + down(&dev->cmd_mutex); + result = ngene_command_mutex(dev, com); + up(&dev->cmd_mutex); + return result; +} + + +static int ngene_command_load_firmware(struct ngene *dev, + u8 *ngene_fw, u32 size) +{ +#define FIRSTCHUNK (1024) + u32 cleft; + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_FWLOAD_PREPARE; + com.cmd.hdr.Length = 0; + com.in_len = 0; + com.out_len = 0; + + ngene_command(dev, &com); + + cleft = (size + 3) & ~3; + if (cleft > FIRSTCHUNK) { + ngcpyto(PROGRAM_SRAM + FIRSTCHUNK, ngene_fw + FIRSTCHUNK, + cleft - FIRSTCHUNK); + cleft = FIRSTCHUNK; + } + ngcpyto(DATA_FIFO_AREA, ngene_fw, cleft); + + memset(&com, 0, sizeof(struct ngene_command)); + com.cmd.hdr.Opcode = CMD_FWLOAD_FINISH; + com.cmd.hdr.Length = 4; + com.cmd.FWLoadFinish.Address = DATA_FIFO_AREA; + com.cmd.FWLoadFinish.Length = (unsigned short)cleft; + com.in_len = 4; + com.out_len = 0; + + return ngene_command(dev, &com); +} + + +static int ngene_command_config_buf(struct ngene *dev, u8 config) +{ + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_CONFIGURE_BUFFER; + com.cmd.hdr.Length = 1; + com.cmd.ConfigureBuffers.config = config; + com.in_len = 1; + com.out_len = 0; + + if (ngene_command(dev, &com) < 0) + return -EIO; + return 0; +} + +static int ngene_command_config_free_buf(struct ngene *dev, u8 *config) +{ + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_CONFIGURE_FREE_BUFFER; + com.cmd.hdr.Length = 6; + memcpy(&com.cmd.ConfigureBuffers.config, config, 6); + com.in_len = 6; + com.out_len = 0; + + if (ngene_command(dev, &com) < 0) + return -EIO; + + return 0; +} + +int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level) +{ + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_SET_GPIO_PIN; + com.cmd.hdr.Length = 1; + com.cmd.SetGpioPin.select = select | (level << 7); + com.in_len = 1; + com.out_len = 0; + + return ngene_command(dev, &com); +} + + +/* + 02000640 is sample on rising edge. + 02000740 is sample on falling edge. + 02000040 is ignore "valid" signal + + 0: FD_CTL1 Bit 7,6 must be 0,1 + 7 disable(fw controlled) + 6 0-AUX,1-TS + 5 0-par,1-ser + 4 0-lsb/1-msb + 3,2 reserved + 1,0 0-no sync, 1-use ext. start, 2-use 0x47, 3-both + 1: FD_CTL2 has 3-valid must be hi, 2-use valid, 1-edge + 2: FD_STA is read-only. 0-sync + 3: FD_INSYNC is number of 47s to trigger "in sync". + 4: FD_OUTSYNC is number of 47s to trigger "out of sync". + 5: FD_MAXBYTE1 is low-order of bytes per packet. + 6: FD_MAXBYTE2 is high-order of bytes per packet. + 7: Top byte is unused. +*/ + +/****************************************************************************/ + +static u8 TSFeatureDecoderSetup[8 * 5] = { + 0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, + 0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXH */ + 0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXHser */ + 0x72, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */ + 0x40, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* LGDT3303 */ +}; + +/* Set NGENE I2S Config to 16 bit packed */ +static u8 I2SConfiguration[] = { + 0x00, 0x10, 0x00, 0x00, + 0x80, 0x10, 0x00, 0x00, +}; + +static u8 SPDIFConfiguration[10] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* Set NGENE I2S Config to transport stream compatible mode */ + +static u8 TS_I2SConfiguration[4] = { 0x3E, 0x18, 0x00, 0x00 }; + +static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x04, 0x00, 0x00 }; + +static u8 ITUDecoderSetup[4][16] = { + {0x1c, 0x13, 0x01, 0x68, 0x3d, 0x90, 0x14, 0x20, /* SDTV */ + 0x00, 0x00, 0x01, 0xb0, 0x9c, 0x00, 0x00, 0x00}, + {0x9c, 0x03, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, + {0x9f, 0x00, 0x23, 0xC0, 0x60, 0x0F, 0x13, 0x00, /* HDTV 1080i50 */ + 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, + {0x9c, 0x01, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, /* HDTV 1080i60 */ + 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, +}; + +/* + * 50 48 60 gleich + * 27p50 9f 00 22 80 42 69 18 ... + * 27p60 93 00 22 80 82 69 1c ... + */ + +/* Maxbyte to 1144 (for raw data) */ +static u8 ITUFeatureDecoderSetup[8] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x00 +}; + +void FillTSBuffer(void *Buffer, int Length, u32 Flags) +{ + u32 *ptr = Buffer; + + memset(Buffer, TS_FILLER, Length); + while (Length > 0) { + if (Flags & DF_SWAP32) + *ptr = 0x471FFF10; + else + *ptr = 0x10FF1F47; + ptr += (188 / 4); + Length -= 188; + } +} + + +static void flush_buffers(struct ngene_channel *chan) +{ + u8 val; + + do { + msleep(1); + spin_lock_irq(&chan->state_lock); + val = chan->nextBuffer->ngeneBuffer.SR.Flags & 0x80; + spin_unlock_irq(&chan->state_lock); + } while (val); +} + +static void clear_buffers(struct ngene_channel *chan) +{ + struct SBufferHeader *Cur = chan->nextBuffer; + + do { + memset(&Cur->ngeneBuffer.SR, 0, sizeof(Cur->ngeneBuffer.SR)); + if (chan->mode & NGENE_IO_TSOUT) + FillTSBuffer(Cur->Buffer1, + chan->Capture1Length, + chan->DataFormatFlags); + Cur = Cur->Next; + } while (Cur != chan->nextBuffer); + + if (chan->mode & NGENE_IO_TSOUT) { + chan->nextBuffer->ngeneBuffer.SR.DTOUpdate = + chan->AudioDTOValue; + chan->AudioDTOUpdated = 0; + + Cur = chan->TSIdleBuffer.Head; + + do { + memset(&Cur->ngeneBuffer.SR, 0, + sizeof(Cur->ngeneBuffer.SR)); + FillTSBuffer(Cur->Buffer1, + chan->Capture1Length, + chan->DataFormatFlags); + Cur = Cur->Next; + } while (Cur != chan->TSIdleBuffer.Head); + } +} + +static int ngene_command_stream_control(struct ngene *dev, u8 stream, + u8 control, u8 mode, u8 flags) +{ + struct ngene_channel *chan = &dev->channel[stream]; + struct ngene_command com; + u16 BsUVI = ((stream & 1) ? 0x9400 : 0x9300); + u16 BsSDI = ((stream & 1) ? 0x9600 : 0x9500); + u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700); + u16 BsSDO = 0x9B00; + + down(&dev->stream_mutex); + memset(&com, 0, sizeof(com)); + com.cmd.hdr.Opcode = CMD_CONTROL; + com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2; + com.cmd.StreamControl.Stream = stream | (control ? 8 : 0); + if (chan->mode & NGENE_IO_TSOUT) + com.cmd.StreamControl.Stream |= 0x07; + com.cmd.StreamControl.Control = control | + (flags & SFLAG_ORDER_LUMA_CHROMA); + com.cmd.StreamControl.Mode = mode; + com.in_len = sizeof(struct FW_STREAM_CONTROL); + com.out_len = 0; + + dprintk(KERN_INFO DEVICE_NAME + ": Stream=%02x, Control=%02x, Mode=%02x\n", + com.cmd.StreamControl.Stream, com.cmd.StreamControl.Control, + com.cmd.StreamControl.Mode); + + chan->Mode = mode; + + if (!(control & 0x80)) { + spin_lock_irq(&chan->state_lock); + if (chan->State == KSSTATE_RUN) { + chan->State = KSSTATE_ACQUIRE; + chan->HWState = HWSTATE_STOP; + spin_unlock_irq(&chan->state_lock); + if (ngene_command(dev, &com) < 0) { + up(&dev->stream_mutex); + return -1; + } + /* clear_buffers(chan); */ + flush_buffers(chan); + up(&dev->stream_mutex); + return 0; + } + spin_unlock_irq(&chan->state_lock); + up(&dev->stream_mutex); + return 0; + } + + if (mode & SMODE_AUDIO_CAPTURE) { + com.cmd.StreamControl.CaptureBlockCount = + chan->Capture1Length / AUDIO_BLOCK_SIZE; + com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead; + } else if (mode & SMODE_TRANSPORT_STREAM) { + com.cmd.StreamControl.CaptureBlockCount = + chan->Capture1Length / TS_BLOCK_SIZE; + com.cmd.StreamControl.MaxLinesPerField = + chan->Capture1Length / TS_BLOCK_SIZE; + com.cmd.StreamControl.Buffer_Address = + chan->TSRingBuffer.PAHead; + if (chan->mode & NGENE_IO_TSOUT) { + com.cmd.StreamControl.BytesPerVBILine = + chan->Capture1Length / TS_BLOCK_SIZE; + com.cmd.StreamControl.Stream |= 0x07; + } + } else { + com.cmd.StreamControl.BytesPerVideoLine = chan->nBytesPerLine; + com.cmd.StreamControl.MaxLinesPerField = chan->nLines; + com.cmd.StreamControl.MinLinesPerField = 100; + com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead; + + if (mode & SMODE_VBI_CAPTURE) { + com.cmd.StreamControl.MaxVBILinesPerField = + chan->nVBILines; + com.cmd.StreamControl.MinVBILinesPerField = 0; + com.cmd.StreamControl.BytesPerVBILine = + chan->nBytesPerVBILine; + } + if (flags & SFLAG_COLORBAR) + com.cmd.StreamControl.Stream |= 0x04; + } + + spin_lock_irq(&chan->state_lock); + if (mode & SMODE_AUDIO_CAPTURE) { + chan->nextBuffer = chan->RingBuffer.Head; + if (mode & SMODE_AUDIO_SPDIF) { + com.cmd.StreamControl.SetupDataLen = + sizeof(SPDIFConfiguration); + com.cmd.StreamControl.SetupDataAddr = BsSPI; + memcpy(com.cmd.StreamControl.SetupData, + SPDIFConfiguration, sizeof(SPDIFConfiguration)); + } else { + com.cmd.StreamControl.SetupDataLen = 4; + com.cmd.StreamControl.SetupDataAddr = BsSDI; + memcpy(com.cmd.StreamControl.SetupData, + I2SConfiguration + + 4 * dev->card_info->i2s[stream], 4); + } + } else if (mode & SMODE_TRANSPORT_STREAM) { + chan->nextBuffer = chan->TSRingBuffer.Head; + if (stream >= STREAM_AUDIOIN1) { + if (chan->mode & NGENE_IO_TSOUT) { + com.cmd.StreamControl.SetupDataLen = + sizeof(TS_I2SOutConfiguration); + com.cmd.StreamControl.SetupDataAddr = BsSDO; + memcpy(com.cmd.StreamControl.SetupData, + TS_I2SOutConfiguration, + sizeof(TS_I2SOutConfiguration)); + } else { + com.cmd.StreamControl.SetupDataLen = + sizeof(TS_I2SConfiguration); + com.cmd.StreamControl.SetupDataAddr = BsSDI; + memcpy(com.cmd.StreamControl.SetupData, + TS_I2SConfiguration, + sizeof(TS_I2SConfiguration)); + } + } else { + com.cmd.StreamControl.SetupDataLen = 8; + com.cmd.StreamControl.SetupDataAddr = BsUVI + 0x10; + memcpy(com.cmd.StreamControl.SetupData, + TSFeatureDecoderSetup + + 8 * dev->card_info->tsf[stream], 8); + } + } else { + chan->nextBuffer = chan->RingBuffer.Head; + com.cmd.StreamControl.SetupDataLen = + 16 + sizeof(ITUFeatureDecoderSetup); + com.cmd.StreamControl.SetupDataAddr = BsUVI; + memcpy(com.cmd.StreamControl.SetupData, + ITUDecoderSetup[chan->itumode], 16); + memcpy(com.cmd.StreamControl.SetupData + 16, + ITUFeatureDecoderSetup, sizeof(ITUFeatureDecoderSetup)); + } + clear_buffers(chan); + chan->State = KSSTATE_RUN; + if (mode & SMODE_TRANSPORT_STREAM) + chan->HWState = HWSTATE_RUN; + else + chan->HWState = HWSTATE_STARTUP; + spin_unlock_irq(&chan->state_lock); + + if (ngene_command(dev, &com) < 0) { + up(&dev->stream_mutex); + return -1; + } + up(&dev->stream_mutex); + return 0; +} + +void set_transfer(struct ngene_channel *chan, int state) +{ + u8 control = 0, mode = 0, flags = 0; + struct ngene *dev = chan->dev; + int ret; + + /* + printk(KERN_INFO DEVICE_NAME ": st %d\n", state); + msleep(100); + */ + + if (state) { + if (chan->running) { + printk(KERN_INFO DEVICE_NAME ": already running\n"); + return; + } + } else { + if (!chan->running) { + printk(KERN_INFO DEVICE_NAME ": already stopped\n"); + return; + } + } + + if (dev->card_info->switch_ctrl) + dev->card_info->switch_ctrl(chan, 1, state ^ 1); + + if (state) { + spin_lock_irq(&chan->state_lock); + + /* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", + ngreadl(0x9310)); */ + dvb_ringbuffer_flush(&dev->tsout_rbuf); + control = 0x80; + if (chan->mode & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { + chan->Capture1Length = 512 * 188; + mode = SMODE_TRANSPORT_STREAM; + } + if (chan->mode & NGENE_IO_TSOUT) { + chan->pBufferExchange = tsout_exchange; + /* 0x66666666 = 50MHz *2^33 /250MHz */ + chan->AudioDTOValue = 0x80000000; + chan->AudioDTOUpdated = 1; + } + if (chan->mode & NGENE_IO_TSIN) + chan->pBufferExchange = tsin_exchange; + spin_unlock_irq(&chan->state_lock); + } else + ;/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", + ngreadl(0x9310)); */ + + ret = ngene_command_stream_control(dev, chan->number, + control, mode, flags); + if (!ret) + chan->running = state; + else + printk(KERN_ERR DEVICE_NAME ": set_transfer %d failed\n", + state); + if (!state) { + spin_lock_irq(&chan->state_lock); + chan->pBufferExchange = NULL; + dvb_ringbuffer_flush(&dev->tsout_rbuf); + spin_unlock_irq(&chan->state_lock); + } +} + + +/****************************************************************************/ +/* nGene hardware init and release functions ********************************/ +/****************************************************************************/ + +static void free_ringbuffer(struct ngene *dev, struct SRingBufferDescriptor *rb) +{ + struct SBufferHeader *Cur = rb->Head; + u32 j; + + if (!Cur) + return; + + for (j = 0; j < rb->NumBuffers; j++, Cur = Cur->Next) { + if (Cur->Buffer1) + pci_free_consistent(dev->pci_dev, + rb->Buffer1Length, + Cur->Buffer1, + Cur->scList1->Address); + + if (Cur->Buffer2) + pci_free_consistent(dev->pci_dev, + rb->Buffer2Length, + Cur->Buffer2, + Cur->scList2->Address); + } + + if (rb->SCListMem) + pci_free_consistent(dev->pci_dev, rb->SCListMemSize, + rb->SCListMem, rb->PASCListMem); + + pci_free_consistent(dev->pci_dev, rb->MemSize, rb->Head, rb->PAHead); +} + +static void free_idlebuffer(struct ngene *dev, + struct SRingBufferDescriptor *rb, + struct SRingBufferDescriptor *tb) +{ + int j; + struct SBufferHeader *Cur = tb->Head; + + if (!rb->Head) + return; + free_ringbuffer(dev, rb); + for (j = 0; j < tb->NumBuffers; j++, Cur = Cur->Next) { + Cur->Buffer2 = NULL; + Cur->scList2 = NULL; + Cur->ngeneBuffer.Address_of_first_entry_2 = 0; + Cur->ngeneBuffer.Number_of_entries_2 = 0; + } +} + +static void free_common_buffers(struct ngene *dev) +{ + u32 i; + struct ngene_channel *chan; + + for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) { + chan = &dev->channel[i]; + free_idlebuffer(dev, &chan->TSIdleBuffer, &chan->TSRingBuffer); + free_ringbuffer(dev, &chan->RingBuffer); + free_ringbuffer(dev, &chan->TSRingBuffer); + } + + if (dev->OverflowBuffer) + pci_free_consistent(dev->pci_dev, + OVERFLOW_BUFFER_SIZE, + dev->OverflowBuffer, dev->PAOverflowBuffer); + + if (dev->FWInterfaceBuffer) + pci_free_consistent(dev->pci_dev, + 4096, + dev->FWInterfaceBuffer, + dev->PAFWInterfaceBuffer); +} + +/****************************************************************************/ +/* Ring buffer handling *****************************************************/ +/****************************************************************************/ + +static int create_ring_buffer(struct pci_dev *pci_dev, + struct SRingBufferDescriptor *descr, u32 NumBuffers) +{ + dma_addr_t tmp; + struct SBufferHeader *Head; + u32 i; + u32 MemSize = SIZEOF_SBufferHeader * NumBuffers; + u64 PARingBufferHead; + u64 PARingBufferCur; + u64 PARingBufferNext; + struct SBufferHeader *Cur, *Next; + + descr->Head = NULL; + descr->MemSize = 0; + descr->PAHead = 0; + descr->NumBuffers = 0; + + if (MemSize < 4096) + MemSize = 4096; + + Head = pci_alloc_consistent(pci_dev, MemSize, &tmp); + PARingBufferHead = tmp; + + if (!Head) + return -ENOMEM; + + memset(Head, 0, MemSize); + + PARingBufferCur = PARingBufferHead; + Cur = Head; + + for (i = 0; i < NumBuffers - 1; i++) { + Next = (struct SBufferHeader *) + (((u8 *) Cur) + SIZEOF_SBufferHeader); + PARingBufferNext = PARingBufferCur + SIZEOF_SBufferHeader; + Cur->Next = Next; + Cur->ngeneBuffer.Next = PARingBufferNext; + Cur = Next; + PARingBufferCur = PARingBufferNext; + } + /* Last Buffer points back to first one */ + Cur->Next = Head; + Cur->ngeneBuffer.Next = PARingBufferHead; + + descr->Head = Head; + descr->MemSize = MemSize; + descr->PAHead = PARingBufferHead; + descr->NumBuffers = NumBuffers; + + return 0; +} + +static int AllocateRingBuffers(struct pci_dev *pci_dev, + dma_addr_t of, + struct SRingBufferDescriptor *pRingBuffer, + u32 Buffer1Length, u32 Buffer2Length) +{ + dma_addr_t tmp; + u32 i, j; + int status = 0; + u32 SCListMemSize = pRingBuffer->NumBuffers + * ((Buffer2Length != 0) ? (NUM_SCATTER_GATHER_ENTRIES * 2) : + NUM_SCATTER_GATHER_ENTRIES) + * sizeof(struct HW_SCATTER_GATHER_ELEMENT); + + u64 PASCListMem; + struct HW_SCATTER_GATHER_ELEMENT *SCListEntry; + u64 PASCListEntry; + struct SBufferHeader *Cur; + void *SCListMem; + + if (SCListMemSize < 4096) + SCListMemSize = 4096; + + SCListMem = pci_alloc_consistent(pci_dev, SCListMemSize, &tmp); + + PASCListMem = tmp; + if (SCListMem == NULL) + return -ENOMEM; + + memset(SCListMem, 0, SCListMemSize); + + pRingBuffer->SCListMem = SCListMem; + pRingBuffer->PASCListMem = PASCListMem; + pRingBuffer->SCListMemSize = SCListMemSize; + pRingBuffer->Buffer1Length = Buffer1Length; + pRingBuffer->Buffer2Length = Buffer2Length; + + SCListEntry = SCListMem; + PASCListEntry = PASCListMem; + Cur = pRingBuffer->Head; + + for (i = 0; i < pRingBuffer->NumBuffers; i += 1, Cur = Cur->Next) { + u64 PABuffer; + + void *Buffer = pci_alloc_consistent(pci_dev, Buffer1Length, + &tmp); + PABuffer = tmp; + + if (Buffer == NULL) + return -ENOMEM; + + Cur->Buffer1 = Buffer; + + SCListEntry->Address = PABuffer; + SCListEntry->Length = Buffer1Length; + + Cur->scList1 = SCListEntry; + Cur->ngeneBuffer.Address_of_first_entry_1 = PASCListEntry; + Cur->ngeneBuffer.Number_of_entries_1 = + NUM_SCATTER_GATHER_ENTRIES; + + SCListEntry += 1; + PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT); + +#if NUM_SCATTER_GATHER_ENTRIES > 1 + for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j += 1) { + SCListEntry->Address = of; + SCListEntry->Length = OVERFLOW_BUFFER_SIZE; + SCListEntry += 1; + PASCListEntry += + sizeof(struct HW_SCATTER_GATHER_ELEMENT); + } +#endif + + if (!Buffer2Length) + continue; + + Buffer = pci_alloc_consistent(pci_dev, Buffer2Length, &tmp); + PABuffer = tmp; + + if (Buffer == NULL) + return -ENOMEM; + + Cur->Buffer2 = Buffer; + + SCListEntry->Address = PABuffer; + SCListEntry->Length = Buffer2Length; + + Cur->scList2 = SCListEntry; + Cur->ngeneBuffer.Address_of_first_entry_2 = PASCListEntry; + Cur->ngeneBuffer.Number_of_entries_2 = + NUM_SCATTER_GATHER_ENTRIES; + + SCListEntry += 1; + PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT); + +#if NUM_SCATTER_GATHER_ENTRIES > 1 + for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j++) { + SCListEntry->Address = of; + SCListEntry->Length = OVERFLOW_BUFFER_SIZE; + SCListEntry += 1; + PASCListEntry += + sizeof(struct HW_SCATTER_GATHER_ELEMENT); + } +#endif + + } + + return status; +} + +static int FillTSIdleBuffer(struct SRingBufferDescriptor *pIdleBuffer, + struct SRingBufferDescriptor *pRingBuffer) +{ + int status = 0; + + /* Copy pointer to scatter gather list in TSRingbuffer + structure for buffer 2 + Load number of buffer + */ + u32 n = pRingBuffer->NumBuffers; + + /* Point to first buffer entry */ + struct SBufferHeader *Cur = pRingBuffer->Head; + int i; + /* Loop thru all buffer and set Buffer 2 pointers to TSIdlebuffer */ + for (i = 0; i < n; i++) { + Cur->Buffer2 = pIdleBuffer->Head->Buffer1; + Cur->scList2 = pIdleBuffer->Head->scList1; + Cur->ngeneBuffer.Address_of_first_entry_2 = + pIdleBuffer->Head->ngeneBuffer. + Address_of_first_entry_1; + Cur->ngeneBuffer.Number_of_entries_2 = + pIdleBuffer->Head->ngeneBuffer.Number_of_entries_1; + Cur = Cur->Next; + } + return status; +} + +static u32 RingBufferSizes[MAX_STREAM] = { + RING_SIZE_VIDEO, + RING_SIZE_VIDEO, + RING_SIZE_AUDIO, + RING_SIZE_AUDIO, + RING_SIZE_AUDIO, +}; + +static u32 Buffer1Sizes[MAX_STREAM] = { + MAX_VIDEO_BUFFER_SIZE, + MAX_VIDEO_BUFFER_SIZE, + MAX_AUDIO_BUFFER_SIZE, + MAX_AUDIO_BUFFER_SIZE, + MAX_AUDIO_BUFFER_SIZE +}; + +static u32 Buffer2Sizes[MAX_STREAM] = { + MAX_VBI_BUFFER_SIZE, + MAX_VBI_BUFFER_SIZE, + 0, + 0, + 0 +}; + + +static int AllocCommonBuffers(struct ngene *dev) +{ + int status = 0, i; + + dev->FWInterfaceBuffer = pci_alloc_consistent(dev->pci_dev, 4096, + &dev->PAFWInterfaceBuffer); + if (!dev->FWInterfaceBuffer) + return -ENOMEM; + dev->hosttongene = dev->FWInterfaceBuffer; + dev->ngenetohost = dev->FWInterfaceBuffer + 256; + dev->EventBuffer = dev->FWInterfaceBuffer + 512; + + dev->OverflowBuffer = pci_alloc_consistent(dev->pci_dev, + OVERFLOW_BUFFER_SIZE, + &dev->PAOverflowBuffer); + if (!dev->OverflowBuffer) + return -ENOMEM; + memset(dev->OverflowBuffer, 0, OVERFLOW_BUFFER_SIZE); + + for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) { + int type = dev->card_info->io_type[i]; + + dev->channel[i].State = KSSTATE_STOP; + + if (type & (NGENE_IO_TV | NGENE_IO_HDTV | NGENE_IO_AIN)) { + status = create_ring_buffer(dev->pci_dev, + &dev->channel[i].RingBuffer, + RingBufferSizes[i]); + if (status < 0) + break; + + if (type & (NGENE_IO_TV | NGENE_IO_AIN)) { + status = AllocateRingBuffers(dev->pci_dev, + dev-> + PAOverflowBuffer, + &dev->channel[i]. + RingBuffer, + Buffer1Sizes[i], + Buffer2Sizes[i]); + if (status < 0) + break; + } else if (type & NGENE_IO_HDTV) { + status = AllocateRingBuffers(dev->pci_dev, + dev-> + PAOverflowBuffer, + &dev->channel[i]. + RingBuffer, + MAX_HDTV_BUFFER_SIZE, + 0); + if (status < 0) + break; + } + } + + if (type & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { + + status = create_ring_buffer(dev->pci_dev, + &dev->channel[i]. + TSRingBuffer, RING_SIZE_TS); + if (status < 0) + break; + + status = AllocateRingBuffers(dev->pci_dev, + dev->PAOverflowBuffer, + &dev->channel[i]. + TSRingBuffer, + MAX_TS_BUFFER_SIZE, 0); + if (status) + break; + } + + if (type & NGENE_IO_TSOUT) { + status = create_ring_buffer(dev->pci_dev, + &dev->channel[i]. + TSIdleBuffer, 1); + if (status < 0) + break; + status = AllocateRingBuffers(dev->pci_dev, + dev->PAOverflowBuffer, + &dev->channel[i]. + TSIdleBuffer, + MAX_TS_BUFFER_SIZE, 0); + if (status) + break; + FillTSIdleBuffer(&dev->channel[i].TSIdleBuffer, + &dev->channel[i].TSRingBuffer); + } + } + return status; +} + +static void ngene_release_buffers(struct ngene *dev) +{ + if (dev->iomem) + iounmap(dev->iomem); + free_common_buffers(dev); + vfree(dev->tsout_buf); + vfree(dev->tsin_buf); + vfree(dev->ain_buf); + vfree(dev->vin_buf); + vfree(dev); +} + +static int ngene_get_buffers(struct ngene *dev) +{ + if (AllocCommonBuffers(dev)) + return -ENOMEM; + if (dev->card_info->io_type[4] & NGENE_IO_TSOUT) { + dev->tsout_buf = vmalloc(TSOUT_BUF_SIZE); + if (!dev->tsout_buf) + return -ENOMEM; + dvb_ringbuffer_init(&dev->tsout_rbuf, + dev->tsout_buf, TSOUT_BUF_SIZE); + } + if (dev->card_info->io_type[2]&NGENE_IO_TSIN) { + dev->tsin_buf = vmalloc(TSIN_BUF_SIZE); + if (!dev->tsin_buf) + return -ENOMEM; + dvb_ringbuffer_init(&dev->tsin_rbuf, + dev->tsin_buf, TSIN_BUF_SIZE); + } + if (dev->card_info->io_type[2] & NGENE_IO_AIN) { + dev->ain_buf = vmalloc(AIN_BUF_SIZE); + if (!dev->ain_buf) + return -ENOMEM; + dvb_ringbuffer_init(&dev->ain_rbuf, dev->ain_buf, AIN_BUF_SIZE); + } + if (dev->card_info->io_type[0] & NGENE_IO_HDTV) { + dev->vin_buf = vmalloc(VIN_BUF_SIZE); + if (!dev->vin_buf) + return -ENOMEM; + dvb_ringbuffer_init(&dev->vin_rbuf, dev->vin_buf, VIN_BUF_SIZE); + } + dev->iomem = ioremap(pci_resource_start(dev->pci_dev, 0), + pci_resource_len(dev->pci_dev, 0)); + if (!dev->iomem) + return -ENOMEM; + + return 0; +} + +static void ngene_init(struct ngene *dev) +{ + int i; + + tasklet_init(&dev->event_tasklet, event_tasklet, (unsigned long)dev); + + memset_io(dev->iomem + 0xc000, 0x00, 0x220); + memset_io(dev->iomem + 0xc400, 0x00, 0x100); + + for (i = 0; i < MAX_STREAM; i++) { + dev->channel[i].dev = dev; + dev->channel[i].number = i; + } + + dev->fw_interface_version = 0; + + ngwritel(0, NGENE_INT_ENABLE); + + dev->icounts = ngreadl(NGENE_INT_COUNTS); + + dev->device_version = ngreadl(DEV_VER) & 0x0f; + printk(KERN_INFO DEVICE_NAME ": Device version %d\n", + dev->device_version); +} + +static int ngene_load_firm(struct ngene *dev) +{ + u32 size; + const struct firmware *fw = NULL; + u8 *ngene_fw; + char *fw_name; + int err, version; + + version = dev->card_info->fw_version; + + switch (version) { + default: + case 15: + version = 15; + size = 23466; + fw_name = "ngene_15.fw"; + dev->cmd_timeout_workaround = true; + break; + case 16: + size = 23498; + fw_name = "ngene_16.fw"; + dev->cmd_timeout_workaround = true; + break; + case 17: + size = 24446; + fw_name = "ngene_17.fw"; + dev->cmd_timeout_workaround = true; + break; + case 18: + size = 0; + fw_name = "ngene_18.fw"; + break; + } + + if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) { + printk(KERN_ERR DEVICE_NAME + ": Could not load firmware file %s.\n", fw_name); + printk(KERN_INFO DEVICE_NAME + ": Copy %s to your hotplug directory!\n", fw_name); + return -1; + } + if (size == 0) + size = fw->size; + if (size != fw->size) { + printk(KERN_ERR DEVICE_NAME + ": Firmware %s has invalid size!", fw_name); + err = -1; + } else { + printk(KERN_INFO DEVICE_NAME + ": Loading firmware file %s.\n", fw_name); + ngene_fw = (u8 *) fw->data; + err = ngene_command_load_firmware(dev, ngene_fw, size); + } + + release_firmware(fw); + + return err; +} + +static void ngene_stop(struct ngene *dev) +{ + down(&dev->cmd_mutex); + i2c_del_adapter(&(dev->channel[0].i2c_adapter)); + i2c_del_adapter(&(dev->channel[1].i2c_adapter)); + ngwritel(0, NGENE_INT_ENABLE); + ngwritel(0, NGENE_COMMAND); + ngwritel(0, NGENE_COMMAND_HI); + ngwritel(0, NGENE_STATUS); + ngwritel(0, NGENE_STATUS_HI); + ngwritel(0, NGENE_EVENT); + ngwritel(0, NGENE_EVENT_HI); + free_irq(dev->pci_dev->irq, dev); +#ifdef CONFIG_PCI_MSI + if (dev->msi_enabled) + pci_disable_msi(dev->pci_dev); +#endif +} + +static int ngene_buffer_config(struct ngene *dev) +{ + int stat; + + if (dev->card_info->fw_version >= 17) { + u8 tsin12_config[6] = { 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 }; + u8 tsin1234_config[6] = { 0x30, 0x30, 0x00, 0x30, 0x30, 0x00 }; + u8 tsio1235_config[6] = { 0x30, 0x30, 0x00, 0x28, 0x00, 0x38 }; + u8 *bconf = tsin12_config; + + if (dev->card_info->io_type[2]&NGENE_IO_TSIN && + dev->card_info->io_type[3]&NGENE_IO_TSIN) { + bconf = tsin1234_config; + if (dev->card_info->io_type[4]&NGENE_IO_TSOUT && + dev->ci.en) + bconf = tsio1235_config; + } + stat = ngene_command_config_free_buf(dev, bconf); + } else { + int bconf = BUFFER_CONFIG_4422; + + if (dev->card_info->io_type[3] == NGENE_IO_TSIN) + bconf = BUFFER_CONFIG_3333; + stat = ngene_command_config_buf(dev, bconf); + } + return stat; +} + + +static int ngene_start(struct ngene *dev) +{ + int stat; + int i; + + pci_set_master(dev->pci_dev); + ngene_init(dev); + + stat = request_irq(dev->pci_dev->irq, irq_handler, + IRQF_SHARED, "nGene", + (void *)dev); + if (stat < 0) + return stat; + + init_waitqueue_head(&dev->cmd_wq); + init_waitqueue_head(&dev->tx_wq); + init_waitqueue_head(&dev->rx_wq); + sema_init(&dev->cmd_mutex, 1); + sema_init(&dev->stream_mutex, 1); + sema_init(&dev->pll_mutex, 1); + sema_init(&dev->i2c_switch_mutex, 1); + spin_lock_init(&dev->cmd_lock); + for (i = 0; i < MAX_STREAM; i++) + spin_lock_init(&dev->channel[i].state_lock); + ngwritel(1, TIMESTAMPS); + + ngwritel(1, NGENE_INT_ENABLE); + + stat = ngene_load_firm(dev); + if (stat < 0) + goto fail; + +#ifdef CONFIG_PCI_MSI + /* enable MSI if kernel and card support it */ + if (pci_msi_enabled() && dev->card_info->msi_supported) { + unsigned long flags; + + ngwritel(0, NGENE_INT_ENABLE); + free_irq(dev->pci_dev->irq, dev); + stat = pci_enable_msi(dev->pci_dev); + if (stat) { + printk(KERN_INFO DEVICE_NAME + ": MSI not available\n"); + flags = IRQF_SHARED; + } else { + flags = 0; + dev->msi_enabled = true; + } + stat = request_irq(dev->pci_dev->irq, irq_handler, + flags, "nGene", dev); + if (stat < 0) + goto fail2; + ngwritel(1, NGENE_INT_ENABLE); + } +#endif + + stat = ngene_i2c_init(dev, 0); + if (stat < 0) + goto fail; + + stat = ngene_i2c_init(dev, 1); + if (stat < 0) + goto fail; + + return 0; + +fail: + ngwritel(0, NGENE_INT_ENABLE); + free_irq(dev->pci_dev->irq, dev); +#ifdef CONFIG_PCI_MSI +fail2: + if (dev->msi_enabled) + pci_disable_msi(dev->pci_dev); +#endif + return stat; +} + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static void release_channel(struct ngene_channel *chan) +{ + struct dvb_demux *dvbdemux = &chan->demux; + struct ngene *dev = chan->dev; + + if (chan->running) + set_transfer(chan, 0); + + tasklet_kill(&chan->demux_tasklet); + + if (chan->ci_dev) { + dvb_unregister_device(chan->ci_dev); + chan->ci_dev = NULL; + } + + if (chan->fe2) + dvb_unregister_frontend(chan->fe2); + + if (chan->fe) { + dvb_unregister_frontend(chan->fe); + dvb_frontend_detach(chan->fe); + chan->fe = NULL; + } + + if (chan->has_demux) { + dvb_net_release(&chan->dvbnet); + dvbdemux->dmx.close(&dvbdemux->dmx); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, + &chan->hw_frontend); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, + &chan->mem_frontend); + dvb_dmxdev_release(&chan->dmxdev); + dvb_dmx_release(&chan->demux); + chan->has_demux = false; + } + + if (chan->has_adapter) { + dvb_unregister_adapter(&dev->adapter[chan->number]); + chan->has_adapter = false; + } +} + +static int init_channel(struct ngene_channel *chan) +{ + int ret = 0, nr = chan->number; + struct dvb_adapter *adapter = NULL; + struct dvb_demux *dvbdemux = &chan->demux; + struct ngene *dev = chan->dev; + struct ngene_info *ni = dev->card_info; + int io = ni->io_type[nr]; + + tasklet_init(&chan->demux_tasklet, demux_tasklet, (unsigned long)chan); + chan->users = 0; + chan->type = io; + chan->mode = chan->type; /* for now only one mode */ + + if (io & NGENE_IO_TSIN) { + chan->fe = NULL; + if (ni->demod_attach[nr]) { + ret = ni->demod_attach[nr](chan); + if (ret < 0) + goto err; + } + if (chan->fe && ni->tuner_attach[nr]) { + ret = ni->tuner_attach[nr](chan); + if (ret < 0) + goto err; + } + } + + if (!dev->ci.en && (io & NGENE_IO_TSOUT)) + return 0; + + if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { + if (nr >= STREAM_AUDIOIN1) + chan->DataFormatFlags = DF_SWAP32; + + if (nr == 0 || !one_adapter || dev->first_adapter == NULL) { + adapter = &dev->adapter[nr]; + ret = dvb_register_adapter(adapter, "nGene", + THIS_MODULE, + &chan->dev->pci_dev->dev, + adapter_nr); + if (ret < 0) + goto err; + if (dev->first_adapter == NULL) + dev->first_adapter = adapter; + chan->has_adapter = true; + } else + adapter = dev->first_adapter; + } + + if (dev->ci.en && (io & NGENE_IO_TSOUT)) { + dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1); + set_transfer(chan, 1); + chan->dev->channel[2].DataFormatFlags = DF_SWAP32; + set_transfer(&chan->dev->channel[2], 1); + dvb_register_device(adapter, &chan->ci_dev, + &ngene_dvbdev_ci, (void *) chan, + DVB_DEVICE_SEC); + if (!chan->ci_dev) + goto err; + } + + if (chan->fe) { + if (dvb_register_frontend(adapter, chan->fe) < 0) + goto err; + chan->has_demux = true; + } + if (chan->fe2) { + if (dvb_register_frontend(adapter, chan->fe2) < 0) + goto err; + chan->fe2->tuner_priv = chan->fe->tuner_priv; + memcpy(&chan->fe2->ops.tuner_ops, + &chan->fe->ops.tuner_ops, + sizeof(struct dvb_tuner_ops)); + } + + if (chan->has_demux) { + ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", + ngene_start_feed, + ngene_stop_feed, chan); + ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux, + &chan->hw_frontend, + &chan->mem_frontend, adapter); + ret = dvb_net_init(adapter, &chan->dvbnet, &chan->demux.dmx); + } + + return ret; + +err: + if (chan->fe) { + dvb_frontend_detach(chan->fe); + chan->fe = NULL; + } + release_channel(chan); + return 0; +} + +static int init_channels(struct ngene *dev) +{ + int i, j; + + for (i = 0; i < MAX_STREAM; i++) { + dev->channel[i].number = i; + if (init_channel(&dev->channel[i]) < 0) { + for (j = i - 1; j >= 0; j--) + release_channel(&dev->channel[j]); + return -1; + } + } + return 0; +} + +static struct cxd2099_cfg cxd_cfg = { + .bitrate = 62000, + .adr = 0x40, + .polarity = 0, + .clock_mode = 0, +}; + +static void cxd_attach(struct ngene *dev) +{ + struct ngene_ci *ci = &dev->ci; + + ci->en = cxd2099_attach(&cxd_cfg, dev, &dev->channel[0].i2c_adapter); + ci->dev = dev; + return; +} + +static void cxd_detach(struct ngene *dev) +{ + struct ngene_ci *ci = &dev->ci; + + dvb_ca_en50221_release(ci->en); + kfree(ci->en); + ci->en = 0; +} + +/***********************************/ +/* workaround for shutdown failure */ +/***********************************/ + +static void ngene_unlink(struct ngene *dev) +{ + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_MEM_WRITE; + com.cmd.hdr.Length = 3; + com.cmd.MemoryWrite.address = 0x910c; + com.cmd.MemoryWrite.data = 0xff; + com.in_len = 3; + com.out_len = 1; + + down(&dev->cmd_mutex); + ngwritel(0, NGENE_INT_ENABLE); + ngene_command_mutex(dev, &com); + up(&dev->cmd_mutex); +} + +void ngene_shutdown(struct pci_dev *pdev) +{ + struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev); + + if (!dev || !shutdown_workaround) + return; + + printk(KERN_INFO DEVICE_NAME ": shutdown workaround...\n"); + ngene_unlink(dev); + pci_disable_device(pdev); +} + +/****************************************************************************/ +/* device probe/remove calls ************************************************/ +/****************************************************************************/ + +void __devexit ngene_remove(struct pci_dev *pdev) +{ + struct ngene *dev = pci_get_drvdata(pdev); + int i; + + tasklet_kill(&dev->event_tasklet); + for (i = MAX_STREAM - 1; i >= 0; i--) + release_channel(&dev->channel[i]); + if (dev->ci.en) + cxd_detach(dev); + ngene_stop(dev); + ngene_release_buffers(dev); + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); +} + +int __devinit ngene_probe(struct pci_dev *pci_dev, + const struct pci_device_id *id) +{ + struct ngene *dev; + int stat = 0; + + if (pci_enable_device(pci_dev) < 0) + return -ENODEV; + + dev = vzalloc(sizeof(struct ngene)); + if (dev == NULL) { + stat = -ENOMEM; + goto fail0; + } + + dev->pci_dev = pci_dev; + dev->card_info = (struct ngene_info *)id->driver_data; + printk(KERN_INFO DEVICE_NAME ": Found %s\n", dev->card_info->name); + + pci_set_drvdata(pci_dev, dev); + + /* Alloc buffers and start nGene */ + stat = ngene_get_buffers(dev); + if (stat < 0) + goto fail1; + stat = ngene_start(dev); + if (stat < 0) + goto fail1; + + cxd_attach(dev); + + stat = ngene_buffer_config(dev); + if (stat < 0) + goto fail1; + + + dev->i2c_current_bus = -1; + + /* Register DVB adapters and devices for both channels */ + if (init_channels(dev) < 0) + goto fail2; + + return 0; + +fail2: + ngene_stop(dev); +fail1: + ngene_release_buffers(dev); +fail0: + pci_disable_device(pci_dev); + pci_set_drvdata(pci_dev, NULL); + return stat; +} diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c new file mode 100644 index 000000000000..fcb16a615aab --- /dev/null +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -0,0 +1,261 @@ +/* + * ngene-dvb.c: nGene PCIe bridge driver - DVB functions + * + * Copyright (C) 2005-2007 Micronas + * + * Copyright (C) 2008-2009 Ralph Metzler + * Modifications for new nGene firmware, + * support for EEPROM-copying, + * support for new dual DVB-S2 card prototype + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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 + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ngene.h" + + +/****************************************************************************/ +/* COMMAND API interface ****************************************************/ +/****************************************************************************/ + +static ssize_t ts_write(struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct ngene_channel *chan = dvbdev->priv; + struct ngene *dev = chan->dev; + + if (wait_event_interruptible(dev->tsout_rbuf.queue, + dvb_ringbuffer_free + (&dev->tsout_rbuf) >= count) < 0) + return 0; + + dvb_ringbuffer_write(&dev->tsout_rbuf, buf, count); + + return count; +} + +static ssize_t ts_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct ngene_channel *chan = dvbdev->priv; + struct ngene *dev = chan->dev; + int left, avail; + + left = count; + while (left) { + if (wait_event_interruptible( + dev->tsin_rbuf.queue, + dvb_ringbuffer_avail(&dev->tsin_rbuf) > 0) < 0) + return -EAGAIN; + avail = dvb_ringbuffer_avail(&dev->tsin_rbuf); + if (avail > left) + avail = left; + dvb_ringbuffer_read_user(&dev->tsin_rbuf, buf, avail); + left -= avail; + buf += avail; + } + return count; +} + +static const struct file_operations ci_fops = { + .owner = THIS_MODULE, + .read = ts_read, + .write = ts_write, + .open = dvb_generic_open, + .release = dvb_generic_release, +}; + +struct dvb_device ngene_dvbdev_ci = { + .priv = 0, + .readers = -1, + .writers = -1, + .users = -1, + .fops = &ci_fops, +}; + + +/****************************************************************************/ +/* DVB functions and API interface ******************************************/ +/****************************************************************************/ + +static void swap_buffer(u32 *p, u32 len) +{ + while (len) { + *p = swab32(*p); + p++; + len -= 4; + } +} + +/* start of filler packet */ +static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER }; + +/* #define DEBUG_CI_XFER */ +#ifdef DEBUG_CI_XFER +static u32 ok; +static u32 overflow; +static u32 stripped; +#endif + +void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) +{ + struct ngene_channel *chan = priv; + struct ngene *dev = chan->dev; + + + if (flags & DF_SWAP32) + swap_buffer(buf, len); + + if (dev->ci.en && chan->number == 2) { + while (len >= 188) { + if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) { + if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) { + dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188); + wake_up(&dev->tsin_rbuf.queue); +#ifdef DEBUG_CI_XFER + ok++; +#endif + } +#ifdef DEBUG_CI_XFER + else + overflow++; +#endif + } +#ifdef DEBUG_CI_XFER + else + stripped++; + + if (ok % 100 == 0 && overflow) + printk(KERN_WARNING "%s: ok %u overflow %u dropped %u\n", __func__, ok, overflow, stripped); +#endif + buf += 188; + len -= 188; + } + return NULL; + } + + if (chan->users > 0) + dvb_dmx_swfilter(&chan->demux, buf, len); + + return NULL; +} + +void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) +{ + struct ngene_channel *chan = priv; + struct ngene *dev = chan->dev; + u32 alen; + + alen = dvb_ringbuffer_avail(&dev->tsout_rbuf); + alen -= alen % 188; + + if (alen < len) + FillTSBuffer(buf + alen, len - alen, flags); + else + alen = len; + dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen); + if (flags & DF_SWAP32) + swap_buffer((u32 *)buf, alen); + wake_up_interruptible(&dev->tsout_rbuf.queue); + return buf; +} + + + +int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct ngene_channel *chan = dvbdmx->priv; + + if (chan->users == 0) { + if (!chan->dev->cmd_timeout_workaround || !chan->running) + set_transfer(chan, 1); + } + + return ++chan->users; +} + +int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct ngene_channel *chan = dvbdmx->priv; + + if (--chan->users) + return chan->users; + + if (!chan->dev->cmd_timeout_workaround) + set_transfer(chan, 0); + + return 0; +} + +int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, + int (*start_feed)(struct dvb_demux_feed *), + int (*stop_feed)(struct dvb_demux_feed *), + void *priv) +{ + dvbdemux->priv = priv; + + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = start_feed; + dvbdemux->stop_feed = stop_feed; + dvbdemux->write_to_decoder = NULL; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | + DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING); + return dvb_dmx_init(dvbdemux); +} + +int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, + struct dvb_demux *dvbdemux, + struct dmx_frontend *hw_frontend, + struct dmx_frontend *mem_frontend, + struct dvb_adapter *dvb_adapter) +{ + int ret; + + dmxdev->filternum = 256; + dmxdev->demux = &dvbdemux->dmx; + dmxdev->capabilities = 0; + ret = dvb_dmxdev_init(dmxdev, dvb_adapter); + if (ret < 0) + return ret; + + hw_frontend->source = DMX_FRONTEND_0; + dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); + mem_frontend->source = DMX_MEMORY_FE; + dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); + return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); +} diff --git a/drivers/media/pci/ngene/ngene-i2c.c b/drivers/media/pci/ngene/ngene-i2c.c new file mode 100644 index 000000000000..d28554f8ce99 --- /dev/null +++ b/drivers/media/pci/ngene/ngene-i2c.c @@ -0,0 +1,176 @@ +/* + * ngene-i2c.c: nGene PCIe bridge driver i2c functions + * + * Copyright (C) 2005-2007 Micronas + * + * Copyright (C) 2008-2009 Ralph Metzler + * Modifications for new nGene firmware, + * support for EEPROM-copying, + * support for new dual DVB-S2 card prototype + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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 + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +/* FIXME - some of these can probably be removed */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ngene.h" + +/* Firmware command for i2c operations */ +static int ngene_command_i2c_read(struct ngene *dev, u8 adr, + u8 *out, u8 outlen, u8 *in, u8 inlen, int flag) +{ + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_I2C_READ; + com.cmd.hdr.Length = outlen + 3; + com.cmd.I2CRead.Device = adr << 1; + memcpy(com.cmd.I2CRead.Data, out, outlen); + com.cmd.I2CRead.Data[outlen] = inlen; + com.cmd.I2CRead.Data[outlen + 1] = 0; + com.in_len = outlen + 3; + com.out_len = inlen + 1; + + if (ngene_command(dev, &com) < 0) + return -EIO; + + if ((com.cmd.raw8[0] >> 1) != adr) + return -EIO; + + if (flag) + memcpy(in, com.cmd.raw8, inlen + 1); + else + memcpy(in, com.cmd.raw8 + 1, inlen); + return 0; +} + +static int ngene_command_i2c_write(struct ngene *dev, u8 adr, + u8 *out, u8 outlen) +{ + struct ngene_command com; + + + com.cmd.hdr.Opcode = CMD_I2C_WRITE; + com.cmd.hdr.Length = outlen + 1; + com.cmd.I2CRead.Device = adr << 1; + memcpy(com.cmd.I2CRead.Data, out, outlen); + com.in_len = outlen + 1; + com.out_len = 1; + + if (ngene_command(dev, &com) < 0) + return -EIO; + + if (com.cmd.raw8[0] == 1) + return -EIO; + + return 0; +} + +static void ngene_i2c_set_bus(struct ngene *dev, int bus) +{ + if (!(dev->card_info->i2c_access & 2)) + return; + if (dev->i2c_current_bus == bus) + return; + + switch (bus) { + case 0: + ngene_command_gpio_set(dev, 3, 0); + ngene_command_gpio_set(dev, 2, 1); + break; + + case 1: + ngene_command_gpio_set(dev, 2, 0); + ngene_command_gpio_set(dev, 3, 1); + break; + } + dev->i2c_current_bus = bus; +} + +static int ngene_i2c_master_xfer(struct i2c_adapter *adapter, + struct i2c_msg msg[], int num) +{ + struct ngene_channel *chan = + (struct ngene_channel *)i2c_get_adapdata(adapter); + struct ngene *dev = chan->dev; + + down(&dev->i2c_switch_mutex); + ngene_i2c_set_bus(dev, chan->number); + + if (num == 2 && msg[1].flags & I2C_M_RD && !(msg[0].flags & I2C_M_RD)) + if (!ngene_command_i2c_read(dev, msg[0].addr, + msg[0].buf, msg[0].len, + msg[1].buf, msg[1].len, 0)) + goto done; + + if (num == 1 && !(msg[0].flags & I2C_M_RD)) + if (!ngene_command_i2c_write(dev, msg[0].addr, + msg[0].buf, msg[0].len)) + goto done; + if (num == 1 && (msg[0].flags & I2C_M_RD)) + if (!ngene_command_i2c_read(dev, msg[0].addr, NULL, 0, + msg[0].buf, msg[0].len, 0)) + goto done; + + up(&dev->i2c_switch_mutex); + return -EIO; + +done: + up(&dev->i2c_switch_mutex); + return num; +} + + +static u32 ngene_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm ngene_i2c_algo = { + .master_xfer = ngene_i2c_master_xfer, + .functionality = ngene_i2c_functionality, +}; + +int ngene_i2c_init(struct ngene *dev, int dev_nr) +{ + struct i2c_adapter *adap = &(dev->channel[dev_nr].i2c_adapter); + + i2c_set_adapdata(adap, &(dev->channel[dev_nr])); + + strcpy(adap->name, "nGene"); + + adap->algo = &ngene_i2c_algo; + adap->algo_data = (void *)&(dev->channel[dev_nr]); + adap->dev.parent = &dev->pci_dev->dev; + + return i2c_add_adapter(adap); +} + diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h new file mode 100644 index 000000000000..5443dc0caea5 --- /dev/null +++ b/drivers/media/pci/ngene/ngene.h @@ -0,0 +1,921 @@ +/* + * ngene.h: nGene PCIe bridge driver + * + * Copyright (C) 2005-2007 Micronas + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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 + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef _NGENE_H_ +#define _NGENE_H_ + +#include +#include +#include +#include +#include +#include + +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_ca_en50221.h" +#include "dvb_frontend.h" +#include "dvb_ringbuffer.h" +#include "dvb_net.h" +#include "cxd2099.h" + +#define DEVICE_NAME "ngene" + +#define NGENE_VID 0x18c3 +#define NGENE_PID 0x0720 + +#ifndef VIDEO_CAP_VC1 +#define VIDEO_CAP_AVC 128 +#define VIDEO_CAP_H264 128 +#define VIDEO_CAP_VC1 256 +#define VIDEO_CAP_WMV9 256 +#define VIDEO_CAP_MPEG4 512 +#endif + +enum STREAM { + STREAM_VIDEOIN1 = 0, /* ITU656 or TS Input */ + STREAM_VIDEOIN2, + STREAM_AUDIOIN1, /* I2S or SPI Input */ + STREAM_AUDIOIN2, + STREAM_AUDIOOUT, + MAX_STREAM +}; + +enum SMODE_BITS { + SMODE_AUDIO_SPDIF = 0x20, + SMODE_AVSYNC = 0x10, + SMODE_TRANSPORT_STREAM = 0x08, + SMODE_AUDIO_CAPTURE = 0x04, + SMODE_VBI_CAPTURE = 0x02, + SMODE_VIDEO_CAPTURE = 0x01 +}; + +enum STREAM_FLAG_BITS { + SFLAG_CHROMA_FORMAT_2COMP = 0x01, /* Chroma Format : 2's complement */ + SFLAG_CHROMA_FORMAT_OFFSET = 0x00, /* Chroma Format : Binary offset */ + SFLAG_ORDER_LUMA_CHROMA = 0x02, /* Byte order: Y,Cb,Y,Cr */ + SFLAG_ORDER_CHROMA_LUMA = 0x00, /* Byte order: Cb,Y,Cr,Y */ + SFLAG_COLORBAR = 0x04, /* Select colorbar */ +}; + +#define PROGRAM_ROM 0x0000 +#define PROGRAM_SRAM 0x1000 +#define PERIPHERALS0 0x8000 +#define PERIPHERALS1 0x9000 +#define SHARED_BUFFER 0xC000 + +#define HOST_TO_NGENE (SHARED_BUFFER+0x0000) +#define NGENE_TO_HOST (SHARED_BUFFER+0x0100) +#define NGENE_COMMAND (SHARED_BUFFER+0x0200) +#define NGENE_COMMAND_HI (SHARED_BUFFER+0x0204) +#define NGENE_STATUS (SHARED_BUFFER+0x0208) +#define NGENE_STATUS_HI (SHARED_BUFFER+0x020C) +#define NGENE_EVENT (SHARED_BUFFER+0x0210) +#define NGENE_EVENT_HI (SHARED_BUFFER+0x0214) +#define VARIABLES (SHARED_BUFFER+0x0210) + +#define NGENE_INT_COUNTS (SHARED_BUFFER+0x0260) +#define NGENE_INT_ENABLE (SHARED_BUFFER+0x0264) +#define NGENE_VBI_LINE_COUNT (SHARED_BUFFER+0x0268) + +#define BUFFER_GP_XMIT (SHARED_BUFFER+0x0800) +#define BUFFER_GP_RECV (SHARED_BUFFER+0x0900) +#define EEPROM_AREA (SHARED_BUFFER+0x0A00) + +#define SG_V_IN_1 (SHARED_BUFFER+0x0A80) +#define SG_VBI_1 (SHARED_BUFFER+0x0B00) +#define SG_A_IN_1 (SHARED_BUFFER+0x0B80) +#define SG_V_IN_2 (SHARED_BUFFER+0x0C00) +#define SG_VBI_2 (SHARED_BUFFER+0x0C80) +#define SG_A_IN_2 (SHARED_BUFFER+0x0D00) +#define SG_V_OUT (SHARED_BUFFER+0x0D80) +#define SG_A_OUT2 (SHARED_BUFFER+0x0E00) + +#define DATA_A_IN_1 (SHARED_BUFFER+0x0E80) +#define DATA_A_IN_2 (SHARED_BUFFER+0x0F00) +#define DATA_A_OUT (SHARED_BUFFER+0x0F80) +#define DATA_V_IN_1 (SHARED_BUFFER+0x1000) +#define DATA_V_IN_2 (SHARED_BUFFER+0x2000) +#define DATA_V_OUT (SHARED_BUFFER+0x3000) + +#define DATA_FIFO_AREA (SHARED_BUFFER+0x1000) + +#define TIMESTAMPS 0xA000 +#define SCRATCHPAD 0xA080 +#define FORCE_INT 0xA088 +#define FORCE_NMI 0xA090 +#define INT_STATUS 0xA0A0 + +#define DEV_VER 0x9004 + +#define FW_DEBUG_DEFAULT (PROGRAM_SRAM+0x00FF) + +struct SG_ADDR { + u64 start; + u64 curr; + u16 curr_ptr; + u16 elements; + u32 pad[3]; +} __attribute__ ((__packed__)); + +struct SHARED_MEMORY { + /* C000 */ + u32 HostToNgene[64]; + + /* C100 */ + u32 NgeneToHost[64]; + + /* C200 */ + u64 NgeneCommand; + u64 NgeneStatus; + u64 NgeneEvent; + + /* C210 */ + u8 pad1[0xc260 - 0xc218]; + + /* C260 */ + u32 IntCounts; + u32 IntEnable; + + /* C268 */ + u8 pad2[0xd000 - 0xc268]; + +} __attribute__ ((__packed__)); + +struct BUFFER_STREAM_RESULTS { + u32 Clock; /* Stream time in 100ns units */ + u16 RemainingLines; /* Remaining lines in this field. + 0 for complete field */ + u8 FieldCount; /* Video field number */ + u8 Flags; /* Bit 7 = Done, Bit 6 = seen, Bit 5 = overflow, + Bit 0 = FieldID */ + u16 BlockCount; /* Audio block count (unused) */ + u8 Reserved[2]; + u32 DTOUpdate; +} __attribute__ ((__packed__)); + +struct HW_SCATTER_GATHER_ELEMENT { + u64 Address; + u32 Length; + u32 Reserved; +} __attribute__ ((__packed__)); + +struct BUFFER_HEADER { + u64 Next; + struct BUFFER_STREAM_RESULTS SR; + + u32 Number_of_entries_1; + u32 Reserved5; + u64 Address_of_first_entry_1; + + u32 Number_of_entries_2; + u32 Reserved7; + u64 Address_of_first_entry_2; +} __attribute__ ((__packed__)); + +struct EVENT_BUFFER { + u32 TimeStamp; + u8 GPIOStatus; + u8 UARTStatus; + u8 RXCharacter; + u8 EventStatus; + u32 Reserved[2]; +} __attribute__ ((__packed__)); + +/* Firmware commands. */ + +enum OPCODES { + CMD_NOP = 0, + CMD_FWLOAD_PREPARE = 0x01, + CMD_FWLOAD_FINISH = 0x02, + CMD_I2C_READ = 0x03, + CMD_I2C_WRITE = 0x04, + + CMD_I2C_WRITE_NOSTOP = 0x05, + CMD_I2C_CONTINUE_WRITE = 0x06, + CMD_I2C_CONTINUE_WRITE_NOSTOP = 0x07, + + CMD_DEBUG_OUTPUT = 0x09, + + CMD_CONTROL = 0x10, + CMD_CONFIGURE_BUFFER = 0x11, + CMD_CONFIGURE_FREE_BUFFER = 0x12, + + CMD_SPI_READ = 0x13, + CMD_SPI_WRITE = 0x14, + + CMD_MEM_READ = 0x20, + CMD_MEM_WRITE = 0x21, + CMD_SFR_READ = 0x22, + CMD_SFR_WRITE = 0x23, + CMD_IRAM_READ = 0x24, + CMD_IRAM_WRITE = 0x25, + CMD_SET_GPIO_PIN = 0x26, + CMD_SET_GPIO_INT = 0x27, + CMD_CONFIGURE_UART = 0x28, + CMD_WRITE_UART = 0x29, + MAX_CMD +}; + +enum RESPONSES { + OK = 0, + ERROR = 1 +}; + +struct FW_HEADER { + u8 Opcode; + u8 Length; +} __attribute__ ((__packed__)); + +struct FW_I2C_WRITE { + struct FW_HEADER hdr; + u8 Device; + u8 Data[250]; +} __attribute__ ((__packed__)); + +struct FW_I2C_CONTINUE_WRITE { + struct FW_HEADER hdr; + u8 Data[250]; +} __attribute__ ((__packed__)); + +struct FW_I2C_READ { + struct FW_HEADER hdr; + u8 Device; + u8 Data[252]; /* followed by two bytes of read data count */ +} __attribute__ ((__packed__)); + +struct FW_SPI_WRITE { + struct FW_HEADER hdr; + u8 ModeSelect; + u8 Data[250]; +} __attribute__ ((__packed__)); + +struct FW_SPI_READ { + struct FW_HEADER hdr; + u8 ModeSelect; + u8 Data[252]; /* followed by two bytes of read data count */ +} __attribute__ ((__packed__)); + +struct FW_FWLOAD_PREPARE { + struct FW_HEADER hdr; +} __attribute__ ((__packed__)); + +struct FW_FWLOAD_FINISH { + struct FW_HEADER hdr; + u16 Address; /* address of final block */ + u16 Length; +} __attribute__ ((__packed__)); + +/* + * Meaning of FW_STREAM_CONTROL::Mode bits: + * Bit 7: Loopback PEXin to PEXout using TVOut channel + * Bit 6: AVLOOP + * Bit 5: Audio select; 0=I2S, 1=SPDIF + * Bit 4: AVSYNC + * Bit 3: Enable transport stream + * Bit 2: Enable audio capture + * Bit 1: Enable ITU-Video VBI capture + * Bit 0: Enable ITU-Video capture + * + * Meaning of FW_STREAM_CONTROL::Control bits (see UVI1_CTL) + * Bit 7: continuous capture + * Bit 6: capture one field + * Bit 5: capture one frame + * Bit 4: unused + * Bit 3: starting field; 0=odd, 1=even + * Bit 2: sample size; 0=8-bit, 1=10-bit + * Bit 1: data format; 0=UYVY, 1=YUY2 + * Bit 0: resets buffer pointers +*/ + +enum FSC_MODE_BITS { + SMODE_LOOPBACK = 0x80, + SMODE_AVLOOP = 0x40, + _SMODE_AUDIO_SPDIF = 0x20, + _SMODE_AVSYNC = 0x10, + _SMODE_TRANSPORT_STREAM = 0x08, + _SMODE_AUDIO_CAPTURE = 0x04, + _SMODE_VBI_CAPTURE = 0x02, + _SMODE_VIDEO_CAPTURE = 0x01 +}; + + +/* Meaning of FW_STREAM_CONTROL::Stream bits: + * Bit 3: Audio sample count: 0 = relative, 1 = absolute + * Bit 2: color bar select; 1=color bars, 0=CV3 decoder + * Bits 1-0: stream select, UVI1, UVI2, TVOUT + */ + +struct FW_STREAM_CONTROL { + struct FW_HEADER hdr; + u8 Stream; /* Stream number (UVI1, UVI2, TVOUT) */ + u8 Control; /* Value written to UVI1_CTL */ + u8 Mode; /* Controls clock source */ + u8 SetupDataLen; /* Length of setup data, MSB=1 write + backwards */ + u16 CaptureBlockCount; /* Blocks (a 256 Bytes) to capture per buffer + for TS and Audio */ + u64 Buffer_Address; /* Address of first buffer header */ + u16 BytesPerVideoLine; + u16 MaxLinesPerField; + u16 MinLinesPerField; + u16 Reserved_1; + u16 BytesPerVBILine; + u16 MaxVBILinesPerField; + u16 MinVBILinesPerField; + u16 SetupDataAddr; /* ngene relative address of setup data */ + u8 SetupData[32]; /* setup data */ +} __attribute__((__packed__)); + +#define AUDIO_BLOCK_SIZE 256 +#define TS_BLOCK_SIZE 256 + +struct FW_MEM_READ { + struct FW_HEADER hdr; + u16 address; +} __attribute__ ((__packed__)); + +struct FW_MEM_WRITE { + struct FW_HEADER hdr; + u16 address; + u8 data; +} __attribute__ ((__packed__)); + +struct FW_SFR_IRAM_READ { + struct FW_HEADER hdr; + u8 address; +} __attribute__ ((__packed__)); + +struct FW_SFR_IRAM_WRITE { + struct FW_HEADER hdr; + u8 address; + u8 data; +} __attribute__ ((__packed__)); + +struct FW_SET_GPIO_PIN { + struct FW_HEADER hdr; + u8 select; +} __attribute__ ((__packed__)); + +struct FW_SET_GPIO_INT { + struct FW_HEADER hdr; + u8 select; +} __attribute__ ((__packed__)); + +struct FW_SET_DEBUGMODE { + struct FW_HEADER hdr; + u8 debug_flags; +} __attribute__ ((__packed__)); + +struct FW_CONFIGURE_BUFFERS { + struct FW_HEADER hdr; + u8 config; +} __attribute__ ((__packed__)); + +enum _BUFFER_CONFIGS { + /* 4k UVI1, 4k UVI2, 2k AUD1, 2k AUD2 (standard usage) */ + BUFFER_CONFIG_4422 = 0, + /* 3k UVI1, 3k UVI2, 3k AUD1, 3k AUD2 (4x TS input usage) */ + BUFFER_CONFIG_3333 = 1, + /* 8k UVI1, 0k UVI2, 2k AUD1, 2k I2SOut (HDTV decoder usage) */ + BUFFER_CONFIG_8022 = 2, + BUFFER_CONFIG_FW17 = 255, /* Use new FW 17 command */ +}; + +struct FW_CONFIGURE_FREE_BUFFERS { + struct FW_HEADER hdr; + u8 UVI1_BufferLength; + u8 UVI2_BufferLength; + u8 TVO_BufferLength; + u8 AUD1_BufferLength; + u8 AUD2_BufferLength; + u8 TVA_BufferLength; +} __attribute__ ((__packed__)); + +struct FW_CONFIGURE_UART { + struct FW_HEADER hdr; + u8 UartControl; +} __attribute__ ((__packed__)); + +enum _UART_CONFIG { + _UART_BAUDRATE_19200 = 0, + _UART_BAUDRATE_9600 = 1, + _UART_BAUDRATE_4800 = 2, + _UART_BAUDRATE_2400 = 3, + _UART_RX_ENABLE = 0x40, + _UART_TX_ENABLE = 0x80, +}; + +struct FW_WRITE_UART { + struct FW_HEADER hdr; + u8 Data[252]; +} __attribute__ ((__packed__)); + + +struct ngene_command { + u32 in_len; + u32 out_len; + union { + u32 raw[64]; + u8 raw8[256]; + struct FW_HEADER hdr; + struct FW_I2C_WRITE I2CWrite; + struct FW_I2C_CONTINUE_WRITE I2CContinueWrite; + struct FW_I2C_READ I2CRead; + struct FW_STREAM_CONTROL StreamControl; + struct FW_FWLOAD_PREPARE FWLoadPrepare; + struct FW_FWLOAD_FINISH FWLoadFinish; + struct FW_MEM_READ MemoryRead; + struct FW_MEM_WRITE MemoryWrite; + struct FW_SFR_IRAM_READ SfrIramRead; + struct FW_SFR_IRAM_WRITE SfrIramWrite; + struct FW_SPI_WRITE SPIWrite; + struct FW_SPI_READ SPIRead; + struct FW_SET_GPIO_PIN SetGpioPin; + struct FW_SET_GPIO_INT SetGpioInt; + struct FW_SET_DEBUGMODE SetDebugMode; + struct FW_CONFIGURE_BUFFERS ConfigureBuffers; + struct FW_CONFIGURE_FREE_BUFFERS ConfigureFreeBuffers; + struct FW_CONFIGURE_UART ConfigureUart; + struct FW_WRITE_UART WriteUart; + } cmd; +} __attribute__ ((__packed__)); + +#define NGENE_INTERFACE_VERSION 0x103 +#define MAX_VIDEO_BUFFER_SIZE (417792) /* 288*1440 rounded up to next page */ +#define MAX_AUDIO_BUFFER_SIZE (8192) /* Gives room for about 23msec@48KHz */ +#define MAX_VBI_BUFFER_SIZE (28672) /* 1144*18 rounded up to next page */ +#define MAX_TS_BUFFER_SIZE (98304) /* 512*188 rounded up to next page */ +#define MAX_HDTV_BUFFER_SIZE (2080768) /* 541*1920*2 rounded up to next page + Max: (1920x1080i60) */ + +#define OVERFLOW_BUFFER_SIZE (8192) + +#define RING_SIZE_VIDEO 4 +#define RING_SIZE_AUDIO 8 +#define RING_SIZE_TS 8 + +#define NUM_SCATTER_GATHER_ENTRIES 8 + +#define MAX_DMA_LENGTH (((MAX_VIDEO_BUFFER_SIZE + MAX_VBI_BUFFER_SIZE) * \ + RING_SIZE_VIDEO * 2) + \ + (MAX_AUDIO_BUFFER_SIZE * RING_SIZE_AUDIO * 2) + \ + (MAX_TS_BUFFER_SIZE * RING_SIZE_TS * 4) + \ + (RING_SIZE_VIDEO * PAGE_SIZE * 2) + \ + (RING_SIZE_AUDIO * PAGE_SIZE * 2) + \ + (RING_SIZE_TS * PAGE_SIZE * 4) + \ + 8 * PAGE_SIZE + OVERFLOW_BUFFER_SIZE + PAGE_SIZE) + +#define EVENT_QUEUE_SIZE 16 + +/* Gathers the current state of a single channel. */ + +struct SBufferHeader { + struct BUFFER_HEADER ngeneBuffer; /* Physical descriptor */ + struct SBufferHeader *Next; + void *Buffer1; + struct HW_SCATTER_GATHER_ELEMENT *scList1; + void *Buffer2; + struct HW_SCATTER_GATHER_ELEMENT *scList2; +}; + +/* Sizeof SBufferHeader aligned to next 64 Bit boundary (hw restriction) */ +#define SIZEOF_SBufferHeader ((sizeof(struct SBufferHeader) + 63) & ~63) + +enum HWSTATE { + HWSTATE_STOP, + HWSTATE_STARTUP, + HWSTATE_RUN, + HWSTATE_PAUSE, +}; + +enum KSSTATE { + KSSTATE_STOP, + KSSTATE_ACQUIRE, + KSSTATE_PAUSE, + KSSTATE_RUN, +}; + +struct SRingBufferDescriptor { + struct SBufferHeader *Head; /* Points to first buffer in ring buffer + structure*/ + u64 PAHead; /* Physical address of first buffer */ + u32 MemSize; /* Memory size of allocated ring buffers + (needed for freeing) */ + u32 NumBuffers; /* Number of buffers in the ring */ + u32 Buffer1Length; /* Allocated length of Buffer 1 */ + u32 Buffer2Length; /* Allocated length of Buffer 2 */ + void *SCListMem; /* Memory to hold scatter gather lists for this + ring */ + u64 PASCListMem; /* Physical address .. */ + u32 SCListMemSize; /* Size of this memory */ +}; + +enum STREAMMODEFLAGS { + StreamMode_NONE = 0, /* Stream not used */ + StreamMode_ANALOG = 1, /* Analog: Stream 0,1 = Video, 2,3 = Audio */ + StreamMode_TSIN = 2, /* Transport stream input (all) */ + StreamMode_HDTV = 4, /* HDTV: Maximum 1920x1080p30,1920x1080i60 + (only stream 0) */ + StreamMode_TSOUT = 8, /* Transport stream output (only stream 3) */ +}; + + +enum BufferExchangeFlags { + BEF_EVEN_FIELD = 0x00000001, + BEF_CONTINUATION = 0x00000002, + BEF_MORE_DATA = 0x00000004, + BEF_OVERFLOW = 0x00000008, + DF_SWAP32 = 0x00010000, +}; + +typedef void *(IBufferExchange)(void *, void *, u32, u32, u32); + +struct MICI_STREAMINFO { + IBufferExchange *pExchange; + IBufferExchange *pExchangeVBI; /* Secondary (VBI, ancillary) */ + u8 Stream; + u8 Flags; + u8 Mode; + u8 Reserved; + u16 nLinesVideo; + u16 nBytesPerLineVideo; + u16 nLinesVBI; + u16 nBytesPerLineVBI; + u32 CaptureLength; /* Used for audio and transport stream */ +}; + +/****************************************************************************/ +/* STRUCTS ******************************************************************/ +/****************************************************************************/ + +/* sound hardware definition */ +#define MIXER_ADDR_TVTUNER 0 +#define MIXER_ADDR_LAST 0 + +struct ngene_channel; + +/*struct sound chip*/ + +struct mychip { + struct ngene_channel *chan; + struct snd_card *card; + struct pci_dev *pci; + struct snd_pcm_substream *substream; + struct snd_pcm *pcm; + unsigned long port; + int irq; + spinlock_t mixer_lock; + spinlock_t lock; + int mixer_volume[MIXER_ADDR_LAST + 1][2]; + int capture_source[MIXER_ADDR_LAST + 1][2]; +}; + +#ifdef NGENE_V4L +struct ngene_overlay { + int tvnorm; + struct v4l2_rect w; + enum v4l2_field field; + struct v4l2_clip *clips; + int nclips; + int setup_ok; +}; + +struct ngene_tvnorm { + int v4l2_id; + char *name; + u16 swidth, sheight; /* scaled standard width, height */ + int tuner_norm; + int soundstd; +}; + +struct ngene_vopen { + struct ngene_channel *ch; + enum v4l2_priority prio; + int width; + int height; + int depth; + struct videobuf_queue vbuf_q; + struct videobuf_queue vbi; + int fourcc; + int picxcount; + int resources; + enum v4l2_buf_type type; + const struct ngene_format *fmt; + + const struct ngene_format *ovfmt; + struct ngene_overlay ov; +}; +#endif + +struct ngene_channel { + struct device device; + struct i2c_adapter i2c_adapter; + + struct ngene *dev; + int number; + int type; + int mode; + bool has_adapter; + bool has_demux; + int demod_type; + int (*gate_ctrl)(struct dvb_frontend *, int); + + struct dvb_frontend *fe; + struct dvb_frontend *fe2; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dvb_net dvbnet; + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + int users; + struct video_device *v4l_dev; + struct dvb_device *ci_dev; + struct tasklet_struct demux_tasklet; + + struct SBufferHeader *nextBuffer; + enum KSSTATE State; + enum HWSTATE HWState; + u8 Stream; + u8 Flags; + u8 Mode; + IBufferExchange *pBufferExchange; + IBufferExchange *pBufferExchange2; + + spinlock_t state_lock; + u16 nLines; + u16 nBytesPerLine; + u16 nVBILines; + u16 nBytesPerVBILine; + u16 itumode; + u32 Capture1Length; + u32 Capture2Length; + struct SRingBufferDescriptor RingBuffer; + struct SRingBufferDescriptor TSRingBuffer; + struct SRingBufferDescriptor TSIdleBuffer; + + u32 DataFormatFlags; + + int AudioDTOUpdated; + u32 AudioDTOValue; + + int (*set_tone)(struct dvb_frontend *, fe_sec_tone_mode_t); + u8 lnbh; + + /* stuff from analog driver */ + + int minor; + struct mychip *mychip; + struct snd_card *soundcard; + u8 *evenbuffer; + u8 dma_on; + int soundstreamon; + int audiomute; + int soundbuffisallocated; + int sndbuffflag; + int tun_rdy; + int dec_rdy; + int tun_dec_rdy; + int lastbufferflag; + + struct ngene_tvnorm *tvnorms; + int tvnorm_num; + int tvnorm; + +#ifdef NGENE_V4L + int videousers; + struct v4l2_prio_state prio; + struct ngene_vopen init; + int resources; + struct v4l2_framebuffer fbuf; + struct ngene_buffer *screen; /* overlay */ + struct list_head capture; /* video capture queue */ + spinlock_t s_lock; + struct semaphore reslock; +#endif + + int running; +}; + + +struct ngene_ci { + struct device device; + struct i2c_adapter i2c_adapter; + + struct ngene *dev; + struct dvb_ca_en50221 *en; +}; + +struct ngene; + +typedef void (rx_cb_t)(struct ngene *, u32, u8); +typedef void (tx_cb_t)(struct ngene *, u32); + +struct ngene { + int nr; + struct pci_dev *pci_dev; + unsigned char *iomem; + + /*struct i2c_adapter i2c_adapter;*/ + + u32 device_version; + u32 fw_interface_version; + u32 icounts; + bool msi_enabled; + bool cmd_timeout_workaround; + + u8 *CmdDoneByte; + int BootFirmware; + void *OverflowBuffer; + dma_addr_t PAOverflowBuffer; + void *FWInterfaceBuffer; + dma_addr_t PAFWInterfaceBuffer; + u8 *ngenetohost; + u8 *hosttongene; + + struct EVENT_BUFFER EventQueue[EVENT_QUEUE_SIZE]; + int EventQueueOverflowCount; + int EventQueueOverflowFlag; + struct tasklet_struct event_tasklet; + struct EVENT_BUFFER *EventBuffer; + int EventQueueWriteIndex; + int EventQueueReadIndex; + + wait_queue_head_t cmd_wq; + int cmd_done; + struct semaphore cmd_mutex; + struct semaphore stream_mutex; + struct semaphore pll_mutex; + struct semaphore i2c_switch_mutex; + int i2c_current_channel; + int i2c_current_bus; + spinlock_t cmd_lock; + + struct dvb_adapter adapter[MAX_STREAM]; + struct dvb_adapter *first_adapter; /* "one_adapter" modprobe opt */ + struct ngene_channel channel[MAX_STREAM]; + + struct ngene_info *card_info; + + tx_cb_t *TxEventNotify; + rx_cb_t *RxEventNotify; + int tx_busy; + wait_queue_head_t tx_wq; + wait_queue_head_t rx_wq; +#define UART_RBUF_LEN 4096 + u8 uart_rbuf[UART_RBUF_LEN]; + int uart_rp, uart_wp; + +#define TS_FILLER 0x6f + + u8 *tsout_buf; +#define TSOUT_BUF_SIZE (512*188*8) + struct dvb_ringbuffer tsout_rbuf; + + u8 *tsin_buf; +#define TSIN_BUF_SIZE (512*188*8) + struct dvb_ringbuffer tsin_rbuf; + + u8 *ain_buf; +#define AIN_BUF_SIZE (128*1024) + struct dvb_ringbuffer ain_rbuf; + + + u8 *vin_buf; +#define VIN_BUF_SIZE (4*1920*1080) + struct dvb_ringbuffer vin_rbuf; + + unsigned long exp_val; + int prev_cmd; + + struct ngene_ci ci; +}; + +struct ngene_info { + int type; +#define NGENE_APP 0 +#define NGENE_TERRATEC 1 +#define NGENE_SIDEWINDER 2 +#define NGENE_RACER 3 +#define NGENE_VIPER 4 +#define NGENE_PYTHON 5 +#define NGENE_VBOX_V1 6 +#define NGENE_VBOX_V2 7 + + int fw_version; + bool msi_supported; + char *name; + + int io_type[MAX_STREAM]; +#define NGENE_IO_NONE 0 +#define NGENE_IO_TV 1 +#define NGENE_IO_HDTV 2 +#define NGENE_IO_TSIN 4 +#define NGENE_IO_TSOUT 8 +#define NGENE_IO_AIN 16 + + void *fe_config[4]; + void *tuner_config[4]; + + int (*demod_attach[4])(struct ngene_channel *); + int (*tuner_attach[4])(struct ngene_channel *); + + u8 avf[4]; + u8 msp[4]; + u8 demoda[4]; + u8 lnb[4]; + int i2c_access; + u8 ntsc; + u8 tsf[4]; + u8 i2s[4]; + + int (*gate_ctrl)(struct dvb_frontend *, int); + int (*switch_ctrl)(struct ngene_channel *, int, int); +}; + +#ifdef NGENE_V4L +struct ngene_format { + char *name; + int fourcc; /* video4linux 2 */ + int btformat; /* BT848_COLOR_FMT_* */ + int format; + int btswap; /* BT848_COLOR_CTL_* */ + int depth; /* bit/pixel */ + int flags; + int hshift, vshift; /* for planar modes */ + int palette; +}; + +#define RESOURCE_OVERLAY 1 +#define RESOURCE_VIDEO 2 +#define RESOURCE_VBI 4 + +struct ngene_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* ngene specific */ + const struct ngene_format *fmt; + int tvnorm; + int btformat; + int btswap; +}; +#endif + + +/* Provided by ngene-core.c */ +int __devinit ngene_probe(struct pci_dev *pci_dev, + const struct pci_device_id *id); +void __devexit ngene_remove(struct pci_dev *pdev); +void ngene_shutdown(struct pci_dev *pdev); +int ngene_command(struct ngene *dev, struct ngene_command *com); +int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level); +void set_transfer(struct ngene_channel *chan, int state); +void FillTSBuffer(void *Buffer, int Length, u32 Flags); + +/* Provided by ngene-i2c.c */ +int ngene_i2c_init(struct ngene *dev, int dev_nr); + +/* Provided by ngene-dvb.c */ +extern struct dvb_device ngene_dvbdev_ci; +void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags); +void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags); +int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed); +int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed); +int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, + int (*start_feed)(struct dvb_demux_feed *), + int (*stop_feed)(struct dvb_demux_feed *), + void *priv); +int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, + struct dvb_demux *dvbdemux, + struct dmx_frontend *hw_frontend, + struct dmx_frontend *mem_frontend, + struct dvb_adapter *dvb_adapter); + +#endif + +/* LocalWords: Endif + */ -- cgit 1.4.1 From ccae7af2bf07dfef69cc2eb6ebc9e1ff15addfbd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 14 Jun 2012 16:35:59 -0300 Subject: [media] common: move media/common/tuners to media/tuners Move the tuners one level up, as the "common" directory will be used by drivers that are shared between more than one driver. Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 4 +- drivers/media/Kconfig | 2 +- drivers/media/Makefile | 2 +- drivers/media/common/Makefile | 2 +- drivers/media/common/b2c2/Makefile | 2 +- drivers/media/common/tuners/Kconfig | 243 -- drivers/media/common/tuners/Makefile | 37 - drivers/media/common/tuners/fc0011.c | 524 --- drivers/media/common/tuners/fc0011.h | 41 - drivers/media/common/tuners/fc0012-priv.h | 43 - drivers/media/common/tuners/fc0012.c | 467 --- drivers/media/common/tuners/fc0012.h | 44 - drivers/media/common/tuners/fc0013-priv.h | 44 - drivers/media/common/tuners/fc0013.c | 634 ---- drivers/media/common/tuners/fc0013.h | 57 - drivers/media/common/tuners/fc001x-common.h | 39 - drivers/media/common/tuners/max2165.c | 433 --- drivers/media/common/tuners/max2165.h | 48 - drivers/media/common/tuners/max2165_priv.h | 60 - drivers/media/common/tuners/mc44s803.c | 372 -- drivers/media/common/tuners/mc44s803.h | 46 - drivers/media/common/tuners/mc44s803_priv.h | 208 -- drivers/media/common/tuners/mt2060.c | 403 --- drivers/media/common/tuners/mt2060.h | 43 - drivers/media/common/tuners/mt2060_priv.h | 104 - drivers/media/common/tuners/mt2063.c | 2307 ------------ drivers/media/common/tuners/mt2063.h | 32 - drivers/media/common/tuners/mt20xx.c | 670 ---- drivers/media/common/tuners/mt20xx.h | 37 - drivers/media/common/tuners/mt2131.c | 301 -- drivers/media/common/tuners/mt2131.h | 54 - drivers/media/common/tuners/mt2131_priv.h | 48 - drivers/media/common/tuners/mt2266.c | 353 -- drivers/media/common/tuners/mt2266.h | 37 - drivers/media/common/tuners/mxl5005s.c | 4109 ---------------------- drivers/media/common/tuners/mxl5005s.h | 135 - drivers/media/common/tuners/mxl5007t.c | 928 ----- drivers/media/common/tuners/mxl5007t.h | 104 - drivers/media/common/tuners/qt1010.c | 480 --- drivers/media/common/tuners/qt1010.h | 53 - drivers/media/common/tuners/qt1010_priv.h | 104 - drivers/media/common/tuners/tda18212.c | 319 -- drivers/media/common/tuners/tda18212.h | 52 - drivers/media/common/tuners/tda18218.c | 342 -- drivers/media/common/tuners/tda18218.h | 45 - drivers/media/common/tuners/tda18218_priv.h | 108 - drivers/media/common/tuners/tda18271-common.c | 703 ---- drivers/media/common/tuners/tda18271-fe.c | 1345 ------- drivers/media/common/tuners/tda18271-maps.c | 1317 ------- drivers/media/common/tuners/tda18271-priv.h | 236 -- drivers/media/common/tuners/tda18271.h | 134 - drivers/media/common/tuners/tda827x.c | 917 ----- drivers/media/common/tuners/tda827x.h | 68 - drivers/media/common/tuners/tda8290.c | 874 ----- drivers/media/common/tuners/tda8290.h | 56 - drivers/media/common/tuners/tda9887.c | 717 ---- drivers/media/common/tuners/tda9887.h | 38 - drivers/media/common/tuners/tea5761.c | 348 -- drivers/media/common/tuners/tea5761.h | 47 - drivers/media/common/tuners/tea5767.c | 475 --- drivers/media/common/tuners/tea5767.h | 66 - drivers/media/common/tuners/tua9001.c | 215 -- drivers/media/common/tuners/tua9001.h | 46 - drivers/media/common/tuners/tua9001_priv.h | 34 - drivers/media/common/tuners/tuner-i2c.h | 182 - drivers/media/common/tuners/tuner-simple.c | 1155 ------ drivers/media/common/tuners/tuner-simple.h | 39 - drivers/media/common/tuners/tuner-types.c | 1883 ---------- drivers/media/common/tuners/tuner-xc2028-types.h | 141 - drivers/media/common/tuners/tuner-xc2028.c | 1509 -------- drivers/media/common/tuners/tuner-xc2028.h | 72 - drivers/media/common/tuners/xc4000.c | 1757 --------- drivers/media/common/tuners/xc4000.h | 67 - drivers/media/common/tuners/xc5000.c | 1366 ------- drivers/media/common/tuners/xc5000.h | 74 - drivers/media/dvb-frontends/Makefile | 2 +- drivers/media/pci/bt8xx/Makefile | 2 +- drivers/media/pci/ddbridge/Makefile | 2 +- drivers/media/pci/ngene/Makefile | 2 +- drivers/media/pci/ttpci/Makefile | 2 +- drivers/media/tuners/Kconfig | 243 ++ drivers/media/tuners/Makefile | 37 + drivers/media/tuners/fc0011.c | 524 +++ drivers/media/tuners/fc0011.h | 41 + drivers/media/tuners/fc0012-priv.h | 43 + drivers/media/tuners/fc0012.c | 467 +++ drivers/media/tuners/fc0012.h | 44 + drivers/media/tuners/fc0013-priv.h | 44 + drivers/media/tuners/fc0013.c | 634 ++++ drivers/media/tuners/fc0013.h | 57 + drivers/media/tuners/fc001x-common.h | 39 + drivers/media/tuners/max2165.c | 433 +++ drivers/media/tuners/max2165.h | 48 + drivers/media/tuners/max2165_priv.h | 60 + drivers/media/tuners/mc44s803.c | 372 ++ drivers/media/tuners/mc44s803.h | 46 + drivers/media/tuners/mc44s803_priv.h | 208 ++ drivers/media/tuners/mt2060.c | 403 +++ drivers/media/tuners/mt2060.h | 43 + drivers/media/tuners/mt2060_priv.h | 104 + drivers/media/tuners/mt2063.c | 2307 ++++++++++++ drivers/media/tuners/mt2063.h | 32 + drivers/media/tuners/mt20xx.c | 670 ++++ drivers/media/tuners/mt20xx.h | 37 + drivers/media/tuners/mt2131.c | 301 ++ drivers/media/tuners/mt2131.h | 54 + drivers/media/tuners/mt2131_priv.h | 48 + drivers/media/tuners/mt2266.c | 353 ++ drivers/media/tuners/mt2266.h | 37 + drivers/media/tuners/mxl5005s.c | 4109 ++++++++++++++++++++++ drivers/media/tuners/mxl5005s.h | 135 + drivers/media/tuners/mxl5007t.c | 928 +++++ drivers/media/tuners/mxl5007t.h | 104 + drivers/media/tuners/qt1010.c | 480 +++ drivers/media/tuners/qt1010.h | 53 + drivers/media/tuners/qt1010_priv.h | 104 + drivers/media/tuners/tda18212.c | 319 ++ drivers/media/tuners/tda18212.h | 52 + drivers/media/tuners/tda18218.c | 342 ++ drivers/media/tuners/tda18218.h | 45 + drivers/media/tuners/tda18218_priv.h | 108 + drivers/media/tuners/tda18271-common.c | 703 ++++ drivers/media/tuners/tda18271-fe.c | 1345 +++++++ drivers/media/tuners/tda18271-maps.c | 1317 +++++++ drivers/media/tuners/tda18271-priv.h | 236 ++ drivers/media/tuners/tda18271.h | 134 + drivers/media/tuners/tda827x.c | 917 +++++ drivers/media/tuners/tda827x.h | 68 + drivers/media/tuners/tda8290.c | 874 +++++ drivers/media/tuners/tda8290.h | 56 + drivers/media/tuners/tda9887.c | 717 ++++ drivers/media/tuners/tda9887.h | 38 + drivers/media/tuners/tea5761.c | 348 ++ drivers/media/tuners/tea5761.h | 47 + drivers/media/tuners/tea5767.c | 475 +++ drivers/media/tuners/tea5767.h | 66 + drivers/media/tuners/tua9001.c | 215 ++ drivers/media/tuners/tua9001.h | 46 + drivers/media/tuners/tua9001_priv.h | 34 + drivers/media/tuners/tuner-i2c.h | 182 + drivers/media/tuners/tuner-simple.c | 1155 ++++++ drivers/media/tuners/tuner-simple.h | 39 + drivers/media/tuners/tuner-types.c | 1883 ++++++++++ drivers/media/tuners/tuner-xc2028-types.h | 141 + drivers/media/tuners/tuner-xc2028.c | 1509 ++++++++ drivers/media/tuners/tuner-xc2028.h | 72 + drivers/media/tuners/xc4000.c | 1757 +++++++++ drivers/media/tuners/xc4000.h | 67 + drivers/media/tuners/xc5000.c | 1366 +++++++ drivers/media/tuners/xc5000.h | 74 + drivers/media/usb/b2c2/Makefile | 2 +- drivers/media/usb/dvb-usb-v2/Makefile | 2 +- drivers/media/usb/dvb-usb/Makefile | 2 +- drivers/media/v4l2-core/Makefile | 2 +- drivers/media/video/Makefile | 2 +- drivers/media/video/au0828/Makefile | 2 +- drivers/media/video/bt8xx/Makefile | 2 +- drivers/media/video/cx18/Makefile | 2 +- drivers/media/video/cx231xx/Makefile | 2 +- drivers/media/video/cx23885/Makefile | 2 +- drivers/media/video/cx25821/Makefile | 2 +- drivers/media/video/cx88/Makefile | 2 +- drivers/media/video/em28xx/Makefile | 2 +- drivers/media/video/ivtv/Makefile | 2 +- drivers/media/video/pvrusb2/Makefile | 2 +- drivers/media/video/saa7134/Makefile | 2 +- drivers/media/video/saa7164/Makefile | 2 +- drivers/media/video/tlg2300/Makefile | 2 +- drivers/media/video/tm6000/Makefile | 2 +- drivers/media/video/usbvision/Makefile | 2 +- drivers/staging/media/cxd2099/Makefile | 2 +- 171 files changed, 30421 insertions(+), 30421 deletions(-) delete mode 100644 drivers/media/common/tuners/Kconfig delete mode 100644 drivers/media/common/tuners/Makefile delete mode 100644 drivers/media/common/tuners/fc0011.c delete mode 100644 drivers/media/common/tuners/fc0011.h delete mode 100644 drivers/media/common/tuners/fc0012-priv.h delete mode 100644 drivers/media/common/tuners/fc0012.c delete mode 100644 drivers/media/common/tuners/fc0012.h delete mode 100644 drivers/media/common/tuners/fc0013-priv.h delete mode 100644 drivers/media/common/tuners/fc0013.c delete mode 100644 drivers/media/common/tuners/fc0013.h delete mode 100644 drivers/media/common/tuners/fc001x-common.h delete mode 100644 drivers/media/common/tuners/max2165.c delete mode 100644 drivers/media/common/tuners/max2165.h delete mode 100644 drivers/media/common/tuners/max2165_priv.h delete mode 100644 drivers/media/common/tuners/mc44s803.c delete mode 100644 drivers/media/common/tuners/mc44s803.h delete mode 100644 drivers/media/common/tuners/mc44s803_priv.h delete mode 100644 drivers/media/common/tuners/mt2060.c delete mode 100644 drivers/media/common/tuners/mt2060.h delete mode 100644 drivers/media/common/tuners/mt2060_priv.h delete mode 100644 drivers/media/common/tuners/mt2063.c delete mode 100644 drivers/media/common/tuners/mt2063.h delete mode 100644 drivers/media/common/tuners/mt20xx.c delete mode 100644 drivers/media/common/tuners/mt20xx.h delete mode 100644 drivers/media/common/tuners/mt2131.c delete mode 100644 drivers/media/common/tuners/mt2131.h delete mode 100644 drivers/media/common/tuners/mt2131_priv.h delete mode 100644 drivers/media/common/tuners/mt2266.c delete mode 100644 drivers/media/common/tuners/mt2266.h delete mode 100644 drivers/media/common/tuners/mxl5005s.c delete mode 100644 drivers/media/common/tuners/mxl5005s.h delete mode 100644 drivers/media/common/tuners/mxl5007t.c delete mode 100644 drivers/media/common/tuners/mxl5007t.h delete mode 100644 drivers/media/common/tuners/qt1010.c delete mode 100644 drivers/media/common/tuners/qt1010.h delete mode 100644 drivers/media/common/tuners/qt1010_priv.h delete mode 100644 drivers/media/common/tuners/tda18212.c delete mode 100644 drivers/media/common/tuners/tda18212.h delete mode 100644 drivers/media/common/tuners/tda18218.c delete mode 100644 drivers/media/common/tuners/tda18218.h delete mode 100644 drivers/media/common/tuners/tda18218_priv.h delete mode 100644 drivers/media/common/tuners/tda18271-common.c delete mode 100644 drivers/media/common/tuners/tda18271-fe.c delete mode 100644 drivers/media/common/tuners/tda18271-maps.c delete mode 100644 drivers/media/common/tuners/tda18271-priv.h delete mode 100644 drivers/media/common/tuners/tda18271.h delete mode 100644 drivers/media/common/tuners/tda827x.c delete mode 100644 drivers/media/common/tuners/tda827x.h delete mode 100644 drivers/media/common/tuners/tda8290.c delete mode 100644 drivers/media/common/tuners/tda8290.h delete mode 100644 drivers/media/common/tuners/tda9887.c delete mode 100644 drivers/media/common/tuners/tda9887.h delete mode 100644 drivers/media/common/tuners/tea5761.c delete mode 100644 drivers/media/common/tuners/tea5761.h delete mode 100644 drivers/media/common/tuners/tea5767.c delete mode 100644 drivers/media/common/tuners/tea5767.h delete mode 100644 drivers/media/common/tuners/tua9001.c delete mode 100644 drivers/media/common/tuners/tua9001.h delete mode 100644 drivers/media/common/tuners/tua9001_priv.h delete mode 100644 drivers/media/common/tuners/tuner-i2c.h delete mode 100644 drivers/media/common/tuners/tuner-simple.c delete mode 100644 drivers/media/common/tuners/tuner-simple.h delete mode 100644 drivers/media/common/tuners/tuner-types.c delete mode 100644 drivers/media/common/tuners/tuner-xc2028-types.h delete mode 100644 drivers/media/common/tuners/tuner-xc2028.c delete mode 100644 drivers/media/common/tuners/tuner-xc2028.h delete mode 100644 drivers/media/common/tuners/xc4000.c delete mode 100644 drivers/media/common/tuners/xc4000.h delete mode 100644 drivers/media/common/tuners/xc5000.c delete mode 100644 drivers/media/common/tuners/xc5000.h create mode 100644 drivers/media/tuners/Kconfig create mode 100644 drivers/media/tuners/Makefile create mode 100644 drivers/media/tuners/fc0011.c create mode 100644 drivers/media/tuners/fc0011.h create mode 100644 drivers/media/tuners/fc0012-priv.h create mode 100644 drivers/media/tuners/fc0012.c create mode 100644 drivers/media/tuners/fc0012.h create mode 100644 drivers/media/tuners/fc0013-priv.h create mode 100644 drivers/media/tuners/fc0013.c create mode 100644 drivers/media/tuners/fc0013.h create mode 100644 drivers/media/tuners/fc001x-common.h create mode 100644 drivers/media/tuners/max2165.c create mode 100644 drivers/media/tuners/max2165.h create mode 100644 drivers/media/tuners/max2165_priv.h create mode 100644 drivers/media/tuners/mc44s803.c create mode 100644 drivers/media/tuners/mc44s803.h create mode 100644 drivers/media/tuners/mc44s803_priv.h create mode 100644 drivers/media/tuners/mt2060.c create mode 100644 drivers/media/tuners/mt2060.h create mode 100644 drivers/media/tuners/mt2060_priv.h create mode 100644 drivers/media/tuners/mt2063.c create mode 100644 drivers/media/tuners/mt2063.h create mode 100644 drivers/media/tuners/mt20xx.c create mode 100644 drivers/media/tuners/mt20xx.h create mode 100644 drivers/media/tuners/mt2131.c create mode 100644 drivers/media/tuners/mt2131.h create mode 100644 drivers/media/tuners/mt2131_priv.h create mode 100644 drivers/media/tuners/mt2266.c create mode 100644 drivers/media/tuners/mt2266.h create mode 100644 drivers/media/tuners/mxl5005s.c create mode 100644 drivers/media/tuners/mxl5005s.h create mode 100644 drivers/media/tuners/mxl5007t.c create mode 100644 drivers/media/tuners/mxl5007t.h create mode 100644 drivers/media/tuners/qt1010.c create mode 100644 drivers/media/tuners/qt1010.h create mode 100644 drivers/media/tuners/qt1010_priv.h create mode 100644 drivers/media/tuners/tda18212.c create mode 100644 drivers/media/tuners/tda18212.h create mode 100644 drivers/media/tuners/tda18218.c create mode 100644 drivers/media/tuners/tda18218.h create mode 100644 drivers/media/tuners/tda18218_priv.h create mode 100644 drivers/media/tuners/tda18271-common.c create mode 100644 drivers/media/tuners/tda18271-fe.c create mode 100644 drivers/media/tuners/tda18271-maps.c create mode 100644 drivers/media/tuners/tda18271-priv.h create mode 100644 drivers/media/tuners/tda18271.h create mode 100644 drivers/media/tuners/tda827x.c create mode 100644 drivers/media/tuners/tda827x.h create mode 100644 drivers/media/tuners/tda8290.c create mode 100644 drivers/media/tuners/tda8290.h create mode 100644 drivers/media/tuners/tda9887.c create mode 100644 drivers/media/tuners/tda9887.h create mode 100644 drivers/media/tuners/tea5761.c create mode 100644 drivers/media/tuners/tea5761.h create mode 100644 drivers/media/tuners/tea5767.c create mode 100644 drivers/media/tuners/tea5767.h create mode 100644 drivers/media/tuners/tua9001.c create mode 100644 drivers/media/tuners/tua9001.h create mode 100644 drivers/media/tuners/tua9001_priv.h create mode 100644 drivers/media/tuners/tuner-i2c.h create mode 100644 drivers/media/tuners/tuner-simple.c create mode 100644 drivers/media/tuners/tuner-simple.h create mode 100644 drivers/media/tuners/tuner-types.c create mode 100644 drivers/media/tuners/tuner-xc2028-types.h create mode 100644 drivers/media/tuners/tuner-xc2028.c create mode 100644 drivers/media/tuners/tuner-xc2028.h create mode 100644 drivers/media/tuners/xc4000.c create mode 100644 drivers/media/tuners/xc4000.h create mode 100644 drivers/media/tuners/xc5000.c create mode 100644 drivers/media/tuners/xc5000.h (limited to 'drivers/media/pci/ngene') diff --git a/MAINTAINERS b/MAINTAINERS index 94b823f71e94..ceb5b55b2af8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2773,8 +2773,8 @@ FC0011 TUNER DRIVER M: Michael Buesch L: linux-media@vger.kernel.org S: Maintained -F: drivers/media/common/tuners/fc0011.h -F: drivers/media/common/tuners/fc0011.c +F: drivers/media/tuners/fc0011.h +F: drivers/media/tuners/fc0011.c FANOTIFY M: Eric Paris diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 6343e84b361a..aae6fec3b9e1 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -145,7 +145,7 @@ source "drivers/media/rc/Kconfig" # Tuner drivers for DVB and V4L # -source "drivers/media/common/tuners/Kconfig" +source "drivers/media/tuners/Kconfig" # # Video/Radio/Hybrid adapters diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 90ec998a8e6a..f89ccace746f 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -8,7 +8,7 @@ ifeq ($(CONFIG_MEDIA_CONTROLLER),y) obj-$(CONFIG_MEDIA_SUPPORT) += media.o endif -obj-y += v4l2-core/ common/ rc/ video/ +obj-y += v4l2-core/ tuners/ common/ rc/ video/ obj-$(CONFIG_VIDEO_DEV) += radio/ obj-$(CONFIG_DVB_CORE) += dvb-core/ pci/ dvb-frontends/ usb/ diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile index d0512d7e5555..a471242c46a7 100644 --- a/drivers/media/common/Makefile +++ b/drivers/media/common/Makefile @@ -1,6 +1,6 @@ saa7146-objs := saa7146_i2c.o saa7146_core.o saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o -obj-y += tuners/ b2c2/ +obj-y += b2c2/ obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o diff --git a/drivers/media/common/b2c2/Makefile b/drivers/media/common/b2c2/Makefile index 377d051548a9..48a4c906a173 100644 --- a/drivers/media/common/b2c2/Makefile +++ b/drivers/media/common/b2c2/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o ccflags-y += -Idrivers/media/dvb-core/ ccflags-y += -Idrivers/media/dvb-frontends/ -ccflags-y += -Idrivers/media/common/tuners/ +ccflags-y += -Idrivers/media/tuners/ diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig deleted file mode 100644 index 94c6ff7a5da3..000000000000 --- a/drivers/media/common/tuners/Kconfig +++ /dev/null @@ -1,243 +0,0 @@ -config MEDIA_ATTACH - bool "Load and attach frontend and tuner driver modules as needed" - depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT - depends on MODULES - default y if !EXPERT - help - Remove the static dependency of DVB card drivers on all - frontend modules for all possible card variants. Instead, - allow the card drivers to only load the frontend modules - they require. - - Also, tuner module will automatically load a tuner driver - when needed, for analog mode. - - This saves several KBytes of memory. - - Note: You will need module-init-tools v3.2 or later for this feature. - - If unsure say Y. - -config MEDIA_TUNER - tristate - depends on (MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT) && I2C - default y - select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT && EXPERIMENTAL - select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE - -config MEDIA_TUNER_CUSTOMISE - bool "Customize analog and hybrid tuner modules to build" - depends on MEDIA_TUNER - default y if EXPERT - help - This allows the user to deselect tuner drivers unnecessary - for their hardware from the build. Use this option with care - as deselecting tuner drivers which are in fact necessary will - result in V4L/DVB devices which cannot be tuned due to lack of - driver support - - If unsure say N. - -menu "Customize TV tuners" - visible if MEDIA_TUNER_CUSTOMISE - depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT - -config MEDIA_TUNER_SIMPLE - tristate "Simple tuner support" - depends on MEDIA_SUPPORT && I2C - select MEDIA_TUNER_TDA9887 - default m if MEDIA_TUNER_CUSTOMISE - help - Say Y here to include support for various simple tuners. - -config MEDIA_TUNER_TDA8290 - tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" - depends on MEDIA_SUPPORT && I2C - select MEDIA_TUNER_TDA827X - select MEDIA_TUNER_TDA18271 - default m if MEDIA_TUNER_CUSTOMISE - help - Say Y here to include support for Philips TDA8290+8275(a) tuner. - -config MEDIA_TUNER_TDA827X - tristate "Philips TDA827X silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A DVB-T silicon tuner module. Say Y when you want to support this tuner. - -config MEDIA_TUNER_TDA18271 - tristate "NXP TDA18271 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A silicon tuner module. Say Y when you want to support this tuner. - -config MEDIA_TUNER_TDA9887 - tristate "TDA 9885/6/7 analog IF demodulator" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - Say Y here to include support for Philips TDA9885/6/7 - analog IF demodulator. - -config MEDIA_TUNER_TEA5761 - tristate "TEA 5761 radio tuner (EXPERIMENTAL)" - depends on MEDIA_SUPPORT && I2C - depends on EXPERIMENTAL - default m if MEDIA_TUNER_CUSTOMISE - help - Say Y here to include support for the Philips TEA5761 radio tuner. - -config MEDIA_TUNER_TEA5767 - tristate "TEA 5767 radio tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - Say Y here to include support for the Philips TEA5767 radio tuner. - -config MEDIA_TUNER_MT20XX - tristate "Microtune 2032 / 2050 tuners" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - Say Y here to include support for the MT2032 / MT2050 tuner. - -config MEDIA_TUNER_MT2060 - tristate "Microtune MT2060 silicon IF tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon IF tuner MT2060 from Microtune. - -config MEDIA_TUNER_MT2063 - tristate "Microtune MT2063 silicon IF tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon IF tuner MT2063 from Microtune. - -config MEDIA_TUNER_MT2266 - tristate "Microtune MT2266 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon baseband tuner MT2266 from Microtune. - -config MEDIA_TUNER_MT2131 - tristate "Microtune MT2131 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon baseband tuner MT2131 from Microtune. - -config MEDIA_TUNER_QT1010 - tristate "Quantek QT1010 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon tuner QT1010 from Quantek. - -config MEDIA_TUNER_XC2028 - tristate "XCeive xc2028/xc3028 tuners" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - Say Y here to include support for the xc2028/xc3028 tuners. - -config MEDIA_TUNER_XC5000 - tristate "Xceive XC5000 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon tuner XC5000 from Xceive. - This device is only used inside a SiP called together with a - demodulator for now. - -config MEDIA_TUNER_XC4000 - tristate "Xceive XC4000 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon tuner XC4000 from Xceive. - This device is only used inside a SiP called together with a - demodulator for now. - -config MEDIA_TUNER_MXL5005S - tristate "MaxLinear MSL5005S silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon tuner MXL5005S from MaxLinear. - -config MEDIA_TUNER_MXL5007T - tristate "MaxLinear MxL5007T silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon tuner MxL5007T from MaxLinear. - -config MEDIA_TUNER_MC44S803 - tristate "Freescale MC44S803 Low Power CMOS Broadband tuners" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Freescale MC44S803 based tuners - -config MEDIA_TUNER_MAX2165 - tristate "Maxim MAX2165 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon tuner MAX2165 from Maxim. - -config MEDIA_TUNER_TDA18218 - tristate "NXP TDA18218 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - NXP TDA18218 silicon tuner driver. - -config MEDIA_TUNER_FC0011 - tristate "Fitipower FC0011 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - Fitipower FC0011 silicon tuner driver. - -config MEDIA_TUNER_FC0012 - tristate "Fitipower FC0012 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - Fitipower FC0012 silicon tuner driver. - -config MEDIA_TUNER_FC0013 - tristate "Fitipower FC0013 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - Fitipower FC0013 silicon tuner driver. - -config MEDIA_TUNER_TDA18212 - tristate "NXP TDA18212 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - NXP TDA18212 silicon tuner driver. - -config MEDIA_TUNER_TUA9001 - tristate "Infineon TUA 9001 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - Infineon TUA 9001 silicon tuner driver. -endmenu diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile deleted file mode 100644 index 112aeee90202..000000000000 --- a/drivers/media/common/tuners/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -# -# Makefile for common V4L/DVB tuners -# - -tda18271-objs := tda18271-maps.o tda18271-common.o tda18271-fe.o - -obj-$(CONFIG_MEDIA_TUNER_XC2028) += tuner-xc2028.o -obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-simple.o -# tuner-types will be merged into tuner-simple, in the future -obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-types.o -obj-$(CONFIG_MEDIA_TUNER_MT20XX) += mt20xx.o -obj-$(CONFIG_MEDIA_TUNER_TDA8290) += tda8290.o -obj-$(CONFIG_MEDIA_TUNER_TEA5767) += tea5767.o -obj-$(CONFIG_MEDIA_TUNER_TEA5761) += tea5761.o -obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o -obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o -obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o -obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o -obj-$(CONFIG_MEDIA_TUNER_XC4000) += xc4000.o -obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o -obj-$(CONFIG_MEDIA_TUNER_MT2063) += mt2063.o -obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o -obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o -obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o -obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o -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 -obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o -obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o -obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o -obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o -obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o - -ccflags-y += -I$(srctree)/drivers/media/dvb-core -ccflags-y += -I$(srctree)/drivers/media/dvb-frontends diff --git a/drivers/media/common/tuners/fc0011.c b/drivers/media/common/tuners/fc0011.c deleted file mode 100644 index e4882546c283..000000000000 --- a/drivers/media/common/tuners/fc0011.c +++ /dev/null @@ -1,524 +0,0 @@ -/* - * Fitipower FC0011 tuner driver - * - * Copyright (C) 2012 Michael Buesch - * - * Derived from FC0012 tuner driver: - * Copyright (C) 2012 Hans-Frieder Vogt - * - * 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 "fc0011.h" - - -/* Tuner registers */ -enum { - FC11_REG_0, - FC11_REG_FA, /* FA */ - FC11_REG_FP, /* FP */ - FC11_REG_XINHI, /* XIN high 8 bit */ - FC11_REG_XINLO, /* XIN low 8 bit */ - FC11_REG_VCO, /* VCO */ - FC11_REG_VCOSEL, /* VCO select */ - FC11_REG_7, /* Unknown tuner reg 7 */ - FC11_REG_8, /* Unknown tuner reg 8 */ - FC11_REG_9, - FC11_REG_10, /* Unknown tuner reg 10 */ - FC11_REG_11, /* Unknown tuner reg 11 */ - FC11_REG_12, - FC11_REG_RCCAL, /* RC calibrate */ - FC11_REG_VCOCAL, /* VCO calibrate */ - FC11_REG_15, - FC11_REG_16, /* Unknown tuner reg 16 */ - FC11_REG_17, - - FC11_NR_REGS, /* Number of registers */ -}; - -enum FC11_REG_VCOSEL_bits { - FC11_VCOSEL_2 = 0x08, /* VCO select 2 */ - FC11_VCOSEL_1 = 0x10, /* VCO select 1 */ - FC11_VCOSEL_CLKOUT = 0x20, /* Fix clock out */ - FC11_VCOSEL_BW7M = 0x40, /* 7MHz bw */ - FC11_VCOSEL_BW6M = 0x80, /* 6MHz bw */ -}; - -enum FC11_REG_RCCAL_bits { - FC11_RCCAL_FORCE = 0x10, /* force */ -}; - -enum FC11_REG_VCOCAL_bits { - FC11_VCOCAL_RUN = 0, /* VCO calibration run */ - FC11_VCOCAL_VALUEMASK = 0x3F, /* VCO calibration value mask */ - FC11_VCOCAL_OK = 0x40, /* VCO calibration Ok */ - FC11_VCOCAL_RESET = 0x80, /* VCO calibration reset */ -}; - - -struct fc0011_priv { - struct i2c_adapter *i2c; - u8 addr; - - u32 frequency; - u32 bandwidth; -}; - - -static int fc0011_writereg(struct fc0011_priv *priv, u8 reg, u8 val) -{ - u8 buf[2] = { reg, val }; - struct i2c_msg msg = { .addr = priv->addr, - .flags = 0, .buf = buf, .len = 2 }; - - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - dev_err(&priv->i2c->dev, - "I2C write reg failed, reg: %02x, val: %02x\n", - reg, val); - return -EIO; - } - - return 0; -} - -static int fc0011_readreg(struct fc0011_priv *priv, u8 reg, u8 *val) -{ - u8 dummy; - struct i2c_msg msg[2] = { - { .addr = priv->addr, - .flags = 0, .buf = ®, .len = 1 }, - { .addr = priv->addr, - .flags = I2C_M_RD, .buf = val ? : &dummy, .len = 1 }, - }; - - if (i2c_transfer(priv->i2c, msg, 2) != 2) { - dev_err(&priv->i2c->dev, - "I2C read failed, reg: %02x\n", reg); - return -EIO; - } - - return 0; -} - -static int fc0011_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - - return 0; -} - -static int fc0011_init(struct dvb_frontend *fe) -{ - struct fc0011_priv *priv = fe->tuner_priv; - int err; - - if (WARN_ON(!fe->callback)) - return -EINVAL; - - err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, - FC0011_FE_CALLBACK_POWER, priv->addr); - if (err) { - dev_err(&priv->i2c->dev, "Power-on callback failed\n"); - return err; - } - err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, - FC0011_FE_CALLBACK_RESET, priv->addr); - if (err) { - dev_err(&priv->i2c->dev, "Reset callback failed\n"); - return err; - } - - return 0; -} - -/* Initiate VCO calibration */ -static int fc0011_vcocal_trigger(struct fc0011_priv *priv) -{ - int err; - - err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RESET); - if (err) - return err; - err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN); - if (err) - return err; - - return 0; -} - -/* Read VCO calibration value */ -static int fc0011_vcocal_read(struct fc0011_priv *priv, u8 *value) -{ - int err; - - err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN); - if (err) - return err; - usleep_range(10000, 20000); - err = fc0011_readreg(priv, FC11_REG_VCOCAL, value); - if (err) - return err; - - return 0; -} - -static int fc0011_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct fc0011_priv *priv = fe->tuner_priv; - int err; - unsigned int i, vco_retries; - u32 freq = p->frequency / 1000; - u32 bandwidth = p->bandwidth_hz / 1000; - u32 fvco, xin, xdiv, xdivr; - u16 frac; - u8 fa, fp, vco_sel, vco_cal; - u8 regs[FC11_NR_REGS] = { }; - - regs[FC11_REG_7] = 0x0F; - regs[FC11_REG_8] = 0x3E; - regs[FC11_REG_10] = 0xB8; - regs[FC11_REG_11] = 0x80; - regs[FC11_REG_RCCAL] = 0x04; - err = fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]); - err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]); - err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]); - err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]); - err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); - if (err) - return -EIO; - - /* Set VCO freq and VCO div */ - if (freq < 54000) { - fvco = freq * 64; - regs[FC11_REG_VCO] = 0x82; - } else if (freq < 108000) { - fvco = freq * 32; - regs[FC11_REG_VCO] = 0x42; - } else if (freq < 216000) { - fvco = freq * 16; - regs[FC11_REG_VCO] = 0x22; - } else if (freq < 432000) { - fvco = freq * 8; - regs[FC11_REG_VCO] = 0x12; - } else { - fvco = freq * 4; - regs[FC11_REG_VCO] = 0x0A; - } - - /* Calc XIN. The PLL reference frequency is 18 MHz. */ - xdiv = fvco / 18000; - frac = fvco - xdiv * 18000; - frac = (frac << 15) / 18000; - if (frac >= 16384) - frac += 32786; - if (!frac) - xin = 0; - else if (frac < 511) - xin = 512; - else if (frac < 65026) - xin = frac; - else - xin = 65024; - regs[FC11_REG_XINHI] = xin >> 8; - regs[FC11_REG_XINLO] = xin; - - /* Calc FP and FA */ - xdivr = xdiv; - if (fvco - xdiv * 18000 >= 9000) - xdivr += 1; /* round */ - fp = xdivr / 8; - fa = xdivr - fp * 8; - if (fa < 2) { - fp -= 1; - fa += 8; - } - if (fp > 0x1F) { - fp &= 0x1F; - fa &= 0xF; - } - if (fa >= fp) { - dev_warn(&priv->i2c->dev, - "fa %02X >= fp %02X, but trying to continue\n", - (unsigned int)(u8)fa, (unsigned int)(u8)fp); - } - regs[FC11_REG_FA] = fa; - regs[FC11_REG_FP] = fp; - - /* Select bandwidth */ - switch (bandwidth) { - case 8000: - break; - case 7000: - regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW7M; - break; - default: - dev_warn(&priv->i2c->dev, "Unsupported bandwidth %u kHz. " - "Using 6000 kHz.\n", - bandwidth); - bandwidth = 6000; - /* fallthrough */ - case 6000: - regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW6M; - break; - } - - /* Pre VCO select */ - if (fvco < 2320000) { - vco_sel = 0; - regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); - } else if (fvco < 3080000) { - vco_sel = 1; - regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); - regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; - } else { - vco_sel = 2; - regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); - regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; - } - - /* Fix for low freqs */ - if (freq < 45000) { - regs[FC11_REG_FA] = 0x6; - regs[FC11_REG_FP] = 0x11; - } - - /* Clock out fix */ - regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_CLKOUT; - - /* Write the cached registers */ - for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) { - err = fc0011_writereg(priv, i, regs[i]); - if (err) - return err; - } - - /* VCO calibration */ - err = fc0011_vcocal_trigger(priv); - if (err) - return err; - err = fc0011_vcocal_read(priv, &vco_cal); - if (err) - return err; - vco_retries = 0; - while (!(vco_cal & FC11_VCOCAL_OK) && vco_retries < 3) { - /* Reset the tuner and try again */ - err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, - FC0011_FE_CALLBACK_RESET, priv->addr); - if (err) { - dev_err(&priv->i2c->dev, "Failed to reset tuner\n"); - return err; - } - /* Reinit tuner config */ - err = 0; - for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) - err |= fc0011_writereg(priv, i, regs[i]); - err |= fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]); - err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]); - err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]); - err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]); - err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); - if (err) - return -EIO; - /* VCO calibration */ - err = fc0011_vcocal_trigger(priv); - if (err) - return err; - err = fc0011_vcocal_read(priv, &vco_cal); - if (err) - return err; - vco_retries++; - } - if (!(vco_cal & FC11_VCOCAL_OK)) { - dev_err(&priv->i2c->dev, - "Failed to read VCO calibration value (got %02X)\n", - (unsigned int)vco_cal); - return -EIO; - } - vco_cal &= FC11_VCOCAL_VALUEMASK; - - switch (vco_sel) { - case 0: - if (vco_cal < 8) { - regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); - regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; - err = fc0011_writereg(priv, FC11_REG_VCOSEL, - regs[FC11_REG_VCOSEL]); - if (err) - return err; - err = fc0011_vcocal_trigger(priv); - if (err) - return err; - } else { - regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); - err = fc0011_writereg(priv, FC11_REG_VCOSEL, - regs[FC11_REG_VCOSEL]); - if (err) - return err; - } - break; - case 1: - if (vco_cal < 5) { - regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); - regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; - err = fc0011_writereg(priv, FC11_REG_VCOSEL, - regs[FC11_REG_VCOSEL]); - if (err) - return err; - err = fc0011_vcocal_trigger(priv); - if (err) - return err; - } else if (vco_cal <= 48) { - regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); - regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; - err = fc0011_writereg(priv, FC11_REG_VCOSEL, - regs[FC11_REG_VCOSEL]); - if (err) - return err; - } else { - regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); - err = fc0011_writereg(priv, FC11_REG_VCOSEL, - regs[FC11_REG_VCOSEL]); - if (err) - return err; - err = fc0011_vcocal_trigger(priv); - if (err) - return err; - } - break; - case 2: - if (vco_cal > 53) { - regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); - regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; - err = fc0011_writereg(priv, FC11_REG_VCOSEL, - regs[FC11_REG_VCOSEL]); - if (err) - return err; - err = fc0011_vcocal_trigger(priv); - if (err) - return err; - } else { - regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); - regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; - err = fc0011_writereg(priv, FC11_REG_VCOSEL, - regs[FC11_REG_VCOSEL]); - if (err) - return err; - } - break; - } - err = fc0011_vcocal_read(priv, NULL); - if (err) - return err; - usleep_range(10000, 50000); - - err = fc0011_readreg(priv, FC11_REG_RCCAL, ®s[FC11_REG_RCCAL]); - if (err) - return err; - regs[FC11_REG_RCCAL] |= FC11_RCCAL_FORCE; - err = fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); - if (err) - return err; - err = fc0011_writereg(priv, FC11_REG_16, 0xB); - if (err) - return err; - - dev_dbg(&priv->i2c->dev, "Tuned to " - "fa=%02X fp=%02X xin=%02X%02X vco=%02X vcosel=%02X " - "vcocal=%02X(%u) bw=%u\n", - (unsigned int)regs[FC11_REG_FA], - (unsigned int)regs[FC11_REG_FP], - (unsigned int)regs[FC11_REG_XINHI], - (unsigned int)regs[FC11_REG_XINLO], - (unsigned int)regs[FC11_REG_VCO], - (unsigned int)regs[FC11_REG_VCOSEL], - (unsigned int)vco_cal, vco_retries, - (unsigned int)bandwidth); - - priv->frequency = p->frequency; - priv->bandwidth = p->bandwidth_hz; - - return 0; -} - -static int fc0011_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct fc0011_priv *priv = fe->tuner_priv; - - *frequency = priv->frequency; - - return 0; -} - -static int fc0011_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - *frequency = 0; - - return 0; -} - -static int fc0011_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct fc0011_priv *priv = fe->tuner_priv; - - *bandwidth = priv->bandwidth; - - return 0; -} - -static const struct dvb_tuner_ops fc0011_tuner_ops = { - .info = { - .name = "Fitipower FC0011", - - .frequency_min = 45000000, - .frequency_max = 1000000000, - }, - - .release = fc0011_release, - .init = fc0011_init, - - .set_params = fc0011_set_params, - - .get_frequency = fc0011_get_frequency, - .get_if_frequency = fc0011_get_if_frequency, - .get_bandwidth = fc0011_get_bandwidth, -}; - -struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - const struct fc0011_config *config) -{ - struct fc0011_priv *priv; - - priv = kzalloc(sizeof(struct fc0011_priv), GFP_KERNEL); - if (!priv) - return NULL; - - priv->i2c = i2c; - priv->addr = config->i2c_address; - - fe->tuner_priv = priv; - fe->ops.tuner_ops = fc0011_tuner_ops; - - dev_info(&priv->i2c->dev, "Fitipower FC0011 tuner attached\n"); - - return fe; -} -EXPORT_SYMBOL(fc0011_attach); - -MODULE_DESCRIPTION("Fitipower FC0011 silicon tuner driver"); -MODULE_AUTHOR("Michael Buesch "); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/fc0011.h b/drivers/media/common/tuners/fc0011.h deleted file mode 100644 index 0ee581f122d2..000000000000 --- a/drivers/media/common/tuners/fc0011.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef LINUX_FC0011_H_ -#define LINUX_FC0011_H_ - -#include "dvb_frontend.h" - - -/** struct fc0011_config - fc0011 hardware config - * - * @i2c_address: I2C bus address. - */ -struct fc0011_config { - u8 i2c_address; -}; - -/** enum fc0011_fe_callback_commands - Frontend callbacks - * - * @FC0011_FE_CALLBACK_POWER: Power on tuner hardware. - * @FC0011_FE_CALLBACK_RESET: Request a tuner reset. - */ -enum fc0011_fe_callback_commands { - FC0011_FE_CALLBACK_POWER, - FC0011_FE_CALLBACK_RESET, -}; - -#if defined(CONFIG_MEDIA_TUNER_FC0011) ||\ - defined(CONFIG_MEDIA_TUNER_FC0011_MODULE) -struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - const struct fc0011_config *config); -#else -static inline -struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - const struct fc0011_config *config) -{ - dev_err(&i2c->dev, "fc0011 driver disabled in Kconfig\n"); - return NULL; -} -#endif - -#endif /* LINUX_FC0011_H_ */ diff --git a/drivers/media/common/tuners/fc0012-priv.h b/drivers/media/common/tuners/fc0012-priv.h deleted file mode 100644 index 4577c917e616..000000000000 --- a/drivers/media/common/tuners/fc0012-priv.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Fitipower FC0012 tuner driver - private includes - * - * Copyright (C) 2012 Hans-Frieder Vogt - * - * 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 _FC0012_PRIV_H_ -#define _FC0012_PRIV_H_ - -#define LOG_PREFIX "fc0012" - -#undef err -#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) -#undef info -#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) -#undef warn -#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) - -struct fc0012_priv { - struct i2c_adapter *i2c; - u8 addr; - u8 dual_master; - u8 xtal_freq; - - u32 frequency; - u32 bandwidth; -}; - -#endif diff --git a/drivers/media/common/tuners/fc0012.c b/drivers/media/common/tuners/fc0012.c deleted file mode 100644 index 308135abd54c..000000000000 --- a/drivers/media/common/tuners/fc0012.c +++ /dev/null @@ -1,467 +0,0 @@ -/* - * Fitipower FC0012 tuner driver - * - * Copyright (C) 2012 Hans-Frieder Vogt - * - * 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 "fc0012.h" -#include "fc0012-priv.h" - -static int fc0012_writereg(struct fc0012_priv *priv, u8 reg, u8 val) -{ - u8 buf[2] = {reg, val}; - struct i2c_msg msg = { - .addr = priv->addr, .flags = 0, .buf = buf, .len = 2 - }; - - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - err("I2C write reg failed, reg: %02x, val: %02x", reg, val); - return -EREMOTEIO; - } - return 0; -} - -static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val) -{ - struct i2c_msg msg[2] = { - { .addr = priv->addr, .flags = 0, .buf = ®, .len = 1 }, - { .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 }, - }; - - if (i2c_transfer(priv->i2c, msg, 2) != 2) { - err("I2C read reg failed, reg: %02x", reg); - return -EREMOTEIO; - } - return 0; -} - -static int fc0012_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static int fc0012_init(struct dvb_frontend *fe) -{ - struct fc0012_priv *priv = fe->tuner_priv; - int i, ret = 0; - unsigned char reg[] = { - 0x00, /* dummy reg. 0 */ - 0x05, /* reg. 0x01 */ - 0x10, /* reg. 0x02 */ - 0x00, /* reg. 0x03 */ - 0x00, /* reg. 0x04 */ - 0x0f, /* reg. 0x05: may also be 0x0a */ - 0x00, /* reg. 0x06: divider 2, VCO slow */ - 0x00, /* reg. 0x07: may also be 0x0f */ - 0xff, /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256, - Loop Bw 1/8 */ - 0x6e, /* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */ - 0xb8, /* reg. 0x0a: Disable LO Test Buffer */ - 0x82, /* reg. 0x0b: Output Clock is same as clock frequency, - may also be 0x83 */ - 0xfc, /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */ - 0x02, /* reg. 0x0d: AGC Not Forcing & LNA Forcing, 0x02 for DVB-T */ - 0x00, /* reg. 0x0e */ - 0x00, /* reg. 0x0f */ - 0x00, /* reg. 0x10: may also be 0x0d */ - 0x00, /* reg. 0x11 */ - 0x1f, /* reg. 0x12: Set to maximum gain */ - 0x08, /* reg. 0x13: Set to Middle Gain: 0x08, - Low Gain: 0x00, High Gain: 0x10, enable IX2: 0x80 */ - 0x00, /* reg. 0x14 */ - 0x04, /* reg. 0x15: Enable LNA COMPS */ - }; - - switch (priv->xtal_freq) { - case FC_XTAL_27_MHZ: - case FC_XTAL_28_8_MHZ: - reg[0x07] |= 0x20; - break; - case FC_XTAL_36_MHZ: - default: - break; - } - - if (priv->dual_master) - reg[0x0c] |= 0x02; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - for (i = 1; i < sizeof(reg); i++) { - ret = fc0012_writereg(priv, i, reg[i]); - if (ret) - break; - } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - - if (ret) - err("fc0012_writereg failed: %d", ret); - - return ret; -} - -static int fc0012_sleep(struct dvb_frontend *fe) -{ - /* nothing to do here */ - return 0; -} - -static int fc0012_set_params(struct dvb_frontend *fe) -{ - struct fc0012_priv *priv = fe->tuner_priv; - int i, ret = 0; - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - u32 freq = p->frequency / 1000; - u32 delsys = p->delivery_system; - unsigned char reg[7], am, pm, multi, tmp; - unsigned long f_vco; - unsigned short xtal_freq_khz_2, xin, xdiv; - int vco_select = false; - - if (fe->callback) { - ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, - FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1)); - if (ret) - goto exit; - } - - switch (priv->xtal_freq) { - case FC_XTAL_27_MHZ: - xtal_freq_khz_2 = 27000 / 2; - break; - case FC_XTAL_36_MHZ: - xtal_freq_khz_2 = 36000 / 2; - break; - case FC_XTAL_28_8_MHZ: - default: - xtal_freq_khz_2 = 28800 / 2; - break; - } - - /* select frequency divider and the frequency of VCO */ - if (freq < 37084) { /* freq * 96 < 3560000 */ - multi = 96; - reg[5] = 0x82; - reg[6] = 0x00; - } else if (freq < 55625) { /* freq * 64 < 3560000 */ - multi = 64; - reg[5] = 0x82; - reg[6] = 0x02; - } else if (freq < 74167) { /* freq * 48 < 3560000 */ - multi = 48; - reg[5] = 0x42; - reg[6] = 0x00; - } else if (freq < 111250) { /* freq * 32 < 3560000 */ - multi = 32; - reg[5] = 0x42; - reg[6] = 0x02; - } else if (freq < 148334) { /* freq * 24 < 3560000 */ - multi = 24; - reg[5] = 0x22; - reg[6] = 0x00; - } else if (freq < 222500) { /* freq * 16 < 3560000 */ - multi = 16; - reg[5] = 0x22; - reg[6] = 0x02; - } else if (freq < 296667) { /* freq * 12 < 3560000 */ - multi = 12; - reg[5] = 0x12; - reg[6] = 0x00; - } else if (freq < 445000) { /* freq * 8 < 3560000 */ - multi = 8; - reg[5] = 0x12; - reg[6] = 0x02; - } else if (freq < 593334) { /* freq * 6 < 3560000 */ - multi = 6; - reg[5] = 0x0a; - reg[6] = 0x00; - } else { - multi = 4; - reg[5] = 0x0a; - reg[6] = 0x02; - } - - f_vco = freq * multi; - - if (f_vco >= 3060000) { - reg[6] |= 0x08; - vco_select = true; - } - - if (freq >= 45000) { - /* From divided value (XDIV) determined the FA and FP value */ - xdiv = (unsigned short)(f_vco / xtal_freq_khz_2); - if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2)) - xdiv++; - - pm = (unsigned char)(xdiv / 8); - am = (unsigned char)(xdiv - (8 * pm)); - - if (am < 2) { - reg[1] = am + 8; - reg[2] = pm - 1; - } else { - reg[1] = am; - reg[2] = pm; - } - } else { - /* fix for frequency less than 45 MHz */ - reg[1] = 0x06; - reg[2] = 0x11; - } - - /* fix clock out */ - reg[6] |= 0x20; - - /* From VCO frequency determines the XIN ( fractional part of Delta - Sigma PLL) and divided value (XDIV) */ - xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2); - xin = (xin << 15) / xtal_freq_khz_2; - if (xin >= 16384) - xin += 32768; - - reg[3] = xin >> 8; /* xin with 9 bit resolution */ - reg[4] = xin & 0xff; - - if (delsys == SYS_DVBT) { - reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */ - switch (p->bandwidth_hz) { - case 6000000: - reg[6] |= 0x80; - break; - case 7000000: - reg[6] |= 0x40; - break; - case 8000000: - default: - break; - } - } else { - err("%s: modulation type not supported!", __func__); - return -EINVAL; - } - - /* modified for Realtek demod */ - reg[5] |= 0x07; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - for (i = 1; i <= 6; i++) { - ret = fc0012_writereg(priv, i, reg[i]); - if (ret) - goto exit; - } - - /* VCO Calibration */ - ret = fc0012_writereg(priv, 0x0e, 0x80); - if (!ret) - ret = fc0012_writereg(priv, 0x0e, 0x00); - - /* VCO Re-Calibration if needed */ - if (!ret) - ret = fc0012_writereg(priv, 0x0e, 0x00); - - if (!ret) { - msleep(10); - ret = fc0012_readreg(priv, 0x0e, &tmp); - } - if (ret) - goto exit; - - /* vco selection */ - tmp &= 0x3f; - - if (vco_select) { - if (tmp > 0x3c) { - reg[6] &= ~0x08; - ret = fc0012_writereg(priv, 0x06, reg[6]); - if (!ret) - ret = fc0012_writereg(priv, 0x0e, 0x80); - if (!ret) - ret = fc0012_writereg(priv, 0x0e, 0x00); - } - } else { - if (tmp < 0x02) { - reg[6] |= 0x08; - ret = fc0012_writereg(priv, 0x06, reg[6]); - if (!ret) - ret = fc0012_writereg(priv, 0x0e, 0x80); - if (!ret) - ret = fc0012_writereg(priv, 0x0e, 0x00); - } - } - - priv->frequency = p->frequency; - priv->bandwidth = p->bandwidth_hz; - -exit: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - if (ret) - warn("%s: failed: %d", __func__, ret); - return ret; -} - -static int fc0012_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct fc0012_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int fc0012_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - /* CHECK: always ? */ - *frequency = 0; - return 0; -} - -static int fc0012_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct fc0012_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; - return 0; -} - -#define INPUT_ADC_LEVEL -8 - -static int fc0012_get_rf_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct fc0012_priv *priv = fe->tuner_priv; - int ret; - unsigned char tmp; - int int_temp, lna_gain, int_lna, tot_agc_gain, power; - const int fc0012_lna_gain_table[] = { - /* low gain */ - -63, -58, -99, -73, - -63, -65, -54, -60, - /* middle gain */ - 71, 70, 68, 67, - 65, 63, 61, 58, - /* high gain */ - 197, 191, 188, 186, - 184, 182, 181, 179, - }; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - ret = fc0012_writereg(priv, 0x12, 0x00); - if (ret) - goto err; - - ret = fc0012_readreg(priv, 0x12, &tmp); - if (ret) - goto err; - int_temp = tmp; - - ret = fc0012_readreg(priv, 0x13, &tmp); - if (ret) - goto err; - lna_gain = tmp & 0x1f; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - - if (lna_gain < ARRAY_SIZE(fc0012_lna_gain_table)) { - int_lna = fc0012_lna_gain_table[lna_gain]; - tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 + - (int_temp & 0x1f)) * 2; - power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10; - - if (power >= 45) - *strength = 255; /* 100% */ - else if (power < -95) - *strength = 0; - else - *strength = (power + 95) * 255 / 140; - - *strength |= *strength << 8; - } else { - ret = -1; - } - - goto exit; - -err: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ -exit: - if (ret) - warn("%s: failed: %d", __func__, ret); - return ret; -} - -static const struct dvb_tuner_ops fc0012_tuner_ops = { - .info = { - .name = "Fitipower FC0012", - - .frequency_min = 37000000, /* estimate */ - .frequency_max = 862000000, /* estimate */ - .frequency_step = 0, - }, - - .release = fc0012_release, - - .init = fc0012_init, - .sleep = fc0012_sleep, - - .set_params = fc0012_set_params, - - .get_frequency = fc0012_get_frequency, - .get_if_frequency = fc0012_get_if_frequency, - .get_bandwidth = fc0012_get_bandwidth, - - .get_rf_strength = fc0012_get_rf_strength, -}; - -struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, u8 i2c_address, int dual_master, - enum fc001x_xtal_freq xtal_freq) -{ - struct fc0012_priv *priv = NULL; - - priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->i2c = i2c; - priv->dual_master = dual_master; - priv->addr = i2c_address; - priv->xtal_freq = xtal_freq; - - info("Fitipower FC0012 successfully attached."); - - fe->tuner_priv = priv; - - memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - return fe; -} -EXPORT_SYMBOL(fc0012_attach); - -MODULE_DESCRIPTION("Fitipower FC0012 silicon tuner driver"); -MODULE_AUTHOR("Hans-Frieder Vogt "); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.6"); diff --git a/drivers/media/common/tuners/fc0012.h b/drivers/media/common/tuners/fc0012.h deleted file mode 100644 index 4dbd5efe8845..000000000000 --- a/drivers/media/common/tuners/fc0012.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Fitipower FC0012 tuner driver - include - * - * Copyright (C) 2012 Hans-Frieder Vogt - * - * 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 _FC0012_H_ -#define _FC0012_H_ - -#include "dvb_frontend.h" -#include "fc001x-common.h" - -#if defined(CONFIG_MEDIA_TUNER_FC0012) || \ - (defined(CONFIG_MEDIA_TUNER_FC0012_MODULE) && defined(MODULE)) -extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - u8 i2c_address, int dual_master, - enum fc001x_xtal_freq xtal_freq); -#else -static inline struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - u8 i2c_address, int dual_master, - enum fc001x_xtal_freq xtal_freq) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff --git a/drivers/media/common/tuners/fc0013-priv.h b/drivers/media/common/tuners/fc0013-priv.h deleted file mode 100644 index bfd49dedea22..000000000000 --- a/drivers/media/common/tuners/fc0013-priv.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Fitipower FC0013 tuner driver - * - * Copyright (C) 2012 Hans-Frieder Vogt - * - * 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 _FC0013_PRIV_H_ -#define _FC0013_PRIV_H_ - -#define LOG_PREFIX "fc0013" - -#undef err -#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) -#undef info -#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) -#undef warn -#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) - -struct fc0013_priv { - struct i2c_adapter *i2c; - u8 addr; - u8 dual_master; - u8 xtal_freq; - - u32 frequency; - u32 bandwidth; -}; - -#endif diff --git a/drivers/media/common/tuners/fc0013.c b/drivers/media/common/tuners/fc0013.c deleted file mode 100644 index bd8f0f1e8f3b..000000000000 --- a/drivers/media/common/tuners/fc0013.c +++ /dev/null @@ -1,634 +0,0 @@ -/* - * Fitipower FC0013 tuner driver - * - * Copyright (C) 2012 Hans-Frieder Vogt - * partially based on driver code from Fitipower - * Copyright (C) 2010 Fitipower Integrated Technology Inc - * - * 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 "fc0013.h" -#include "fc0013-priv.h" - -static int fc0013_writereg(struct fc0013_priv *priv, u8 reg, u8 val) -{ - u8 buf[2] = {reg, val}; - struct i2c_msg msg = { - .addr = priv->addr, .flags = 0, .buf = buf, .len = 2 - }; - - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - err("I2C write reg failed, reg: %02x, val: %02x", reg, val); - return -EREMOTEIO; - } - return 0; -} - -static int fc0013_readreg(struct fc0013_priv *priv, u8 reg, u8 *val) -{ - struct i2c_msg msg[2] = { - { .addr = priv->addr, .flags = 0, .buf = ®, .len = 1 }, - { .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 }, - }; - - if (i2c_transfer(priv->i2c, msg, 2) != 2) { - err("I2C read reg failed, reg: %02x", reg); - return -EREMOTEIO; - } - return 0; -} - -static int fc0013_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static int fc0013_init(struct dvb_frontend *fe) -{ - struct fc0013_priv *priv = fe->tuner_priv; - int i, ret = 0; - unsigned char reg[] = { - 0x00, /* reg. 0x00: dummy */ - 0x09, /* reg. 0x01 */ - 0x16, /* reg. 0x02 */ - 0x00, /* reg. 0x03 */ - 0x00, /* reg. 0x04 */ - 0x17, /* reg. 0x05 */ - 0x02, /* reg. 0x06 */ - 0x0a, /* reg. 0x07: CHECK */ - 0xff, /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256, - Loop Bw 1/8 */ - 0x6f, /* reg. 0x09: enable LoopThrough */ - 0xb8, /* reg. 0x0a: Disable LO Test Buffer */ - 0x82, /* reg. 0x0b: CHECK */ - 0xfc, /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */ - 0x01, /* reg. 0x0d: AGC Not Forcing & LNA Forcing, may need 0x02 */ - 0x00, /* reg. 0x0e */ - 0x00, /* reg. 0x0f */ - 0x00, /* reg. 0x10 */ - 0x00, /* reg. 0x11 */ - 0x00, /* reg. 0x12 */ - 0x00, /* reg. 0x13 */ - 0x50, /* reg. 0x14: DVB-t High Gain, UHF. - Middle Gain: 0x48, Low Gain: 0x40 */ - 0x01, /* reg. 0x15 */ - }; - - switch (priv->xtal_freq) { - case FC_XTAL_27_MHZ: - case FC_XTAL_28_8_MHZ: - reg[0x07] |= 0x20; - break; - case FC_XTAL_36_MHZ: - default: - break; - } - - if (priv->dual_master) - reg[0x0c] |= 0x02; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - for (i = 1; i < sizeof(reg); i++) { - ret = fc0013_writereg(priv, i, reg[i]); - if (ret) - break; - } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - - if (ret) - err("fc0013_writereg failed: %d", ret); - - return ret; -} - -static int fc0013_sleep(struct dvb_frontend *fe) -{ - /* nothing to do here */ - return 0; -} - -int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val) -{ - struct fc0013_priv *priv = fe->tuner_priv; - int ret; - u8 rc_cal; - int val; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - /* push rc_cal value, get rc_cal value */ - ret = fc0013_writereg(priv, 0x10, 0x00); - if (ret) - goto error_out; - - /* get rc_cal value */ - ret = fc0013_readreg(priv, 0x10, &rc_cal); - if (ret) - goto error_out; - - rc_cal &= 0x0f; - - val = (int)rc_cal + rc_val; - - /* forcing rc_cal */ - ret = fc0013_writereg(priv, 0x0d, 0x11); - if (ret) - goto error_out; - - /* modify rc_cal value */ - if (val > 15) - ret = fc0013_writereg(priv, 0x10, 0x0f); - else if (val < 0) - ret = fc0013_writereg(priv, 0x10, 0x00); - else - ret = fc0013_writereg(priv, 0x10, (u8)val); - -error_out: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - - return ret; -} -EXPORT_SYMBOL(fc0013_rc_cal_add); - -int fc0013_rc_cal_reset(struct dvb_frontend *fe) -{ - struct fc0013_priv *priv = fe->tuner_priv; - int ret; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - ret = fc0013_writereg(priv, 0x0d, 0x01); - if (!ret) - ret = fc0013_writereg(priv, 0x10, 0x00); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - - return ret; -} -EXPORT_SYMBOL(fc0013_rc_cal_reset); - -static int fc0013_set_vhf_track(struct fc0013_priv *priv, u32 freq) -{ - int ret; - u8 tmp; - - ret = fc0013_readreg(priv, 0x1d, &tmp); - if (ret) - goto error_out; - tmp &= 0xe3; - if (freq <= 177500) { /* VHF Track: 7 */ - ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c); - } else if (freq <= 184500) { /* VHF Track: 6 */ - ret = fc0013_writereg(priv, 0x1d, tmp | 0x18); - } else if (freq <= 191500) { /* VHF Track: 5 */ - ret = fc0013_writereg(priv, 0x1d, tmp | 0x14); - } else if (freq <= 198500) { /* VHF Track: 4 */ - ret = fc0013_writereg(priv, 0x1d, tmp | 0x10); - } else if (freq <= 205500) { /* VHF Track: 3 */ - ret = fc0013_writereg(priv, 0x1d, tmp | 0x0c); - } else if (freq <= 219500) { /* VHF Track: 2 */ - ret = fc0013_writereg(priv, 0x1d, tmp | 0x08); - } else if (freq < 300000) { /* VHF Track: 1 */ - ret = fc0013_writereg(priv, 0x1d, tmp | 0x04); - } else { /* UHF and GPS */ - ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c); - } - if (ret) - goto error_out; -error_out: - return ret; -} - -static int fc0013_set_params(struct dvb_frontend *fe) -{ - struct fc0013_priv *priv = fe->tuner_priv; - int i, ret = 0; - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - u32 freq = p->frequency / 1000; - u32 delsys = p->delivery_system; - unsigned char reg[7], am, pm, multi, tmp; - unsigned long f_vco; - unsigned short xtal_freq_khz_2, xin, xdiv; - int vco_select = false; - - if (fe->callback) { - ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, - FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1)); - if (ret) - goto exit; - } - - switch (priv->xtal_freq) { - case FC_XTAL_27_MHZ: - xtal_freq_khz_2 = 27000 / 2; - break; - case FC_XTAL_36_MHZ: - xtal_freq_khz_2 = 36000 / 2; - break; - case FC_XTAL_28_8_MHZ: - default: - xtal_freq_khz_2 = 28800 / 2; - break; - } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - /* set VHF track */ - ret = fc0013_set_vhf_track(priv, freq); - if (ret) - goto exit; - - if (freq < 300000) { - /* enable VHF filter */ - ret = fc0013_readreg(priv, 0x07, &tmp); - if (ret) - goto exit; - ret = fc0013_writereg(priv, 0x07, tmp | 0x10); - if (ret) - goto exit; - - /* disable UHF & disable GPS */ - ret = fc0013_readreg(priv, 0x14, &tmp); - if (ret) - goto exit; - ret = fc0013_writereg(priv, 0x14, tmp & 0x1f); - if (ret) - goto exit; - } else if (freq <= 862000) { - /* disable VHF filter */ - ret = fc0013_readreg(priv, 0x07, &tmp); - if (ret) - goto exit; - ret = fc0013_writereg(priv, 0x07, tmp & 0xef); - if (ret) - goto exit; - - /* enable UHF & disable GPS */ - ret = fc0013_readreg(priv, 0x14, &tmp); - if (ret) - goto exit; - ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x40); - if (ret) - goto exit; - } else { - /* disable VHF filter */ - ret = fc0013_readreg(priv, 0x07, &tmp); - if (ret) - goto exit; - ret = fc0013_writereg(priv, 0x07, tmp & 0xef); - if (ret) - goto exit; - - /* disable UHF & enable GPS */ - ret = fc0013_readreg(priv, 0x14, &tmp); - if (ret) - goto exit; - ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x20); - if (ret) - goto exit; - } - - /* select frequency divider and the frequency of VCO */ - if (freq < 37084) { /* freq * 96 < 3560000 */ - multi = 96; - reg[5] = 0x82; - reg[6] = 0x00; - } else if (freq < 55625) { /* freq * 64 < 3560000 */ - multi = 64; - reg[5] = 0x02; - reg[6] = 0x02; - } else if (freq < 74167) { /* freq * 48 < 3560000 */ - multi = 48; - reg[5] = 0x42; - reg[6] = 0x00; - } else if (freq < 111250) { /* freq * 32 < 3560000 */ - multi = 32; - reg[5] = 0x82; - reg[6] = 0x02; - } else if (freq < 148334) { /* freq * 24 < 3560000 */ - multi = 24; - reg[5] = 0x22; - reg[6] = 0x00; - } else if (freq < 222500) { /* freq * 16 < 3560000 */ - multi = 16; - reg[5] = 0x42; - reg[6] = 0x02; - } else if (freq < 296667) { /* freq * 12 < 3560000 */ - multi = 12; - reg[5] = 0x12; - reg[6] = 0x00; - } else if (freq < 445000) { /* freq * 8 < 3560000 */ - multi = 8; - reg[5] = 0x22; - reg[6] = 0x02; - } else if (freq < 593334) { /* freq * 6 < 3560000 */ - multi = 6; - reg[5] = 0x0a; - reg[6] = 0x00; - } else if (freq < 950000) { /* freq * 4 < 3800000 */ - multi = 4; - reg[5] = 0x12; - reg[6] = 0x02; - } else { - multi = 2; - reg[5] = 0x0a; - reg[6] = 0x02; - } - - f_vco = freq * multi; - - if (f_vco >= 3060000) { - reg[6] |= 0x08; - vco_select = true; - } - - if (freq >= 45000) { - /* From divided value (XDIV) determined the FA and FP value */ - xdiv = (unsigned short)(f_vco / xtal_freq_khz_2); - if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2)) - xdiv++; - - pm = (unsigned char)(xdiv / 8); - am = (unsigned char)(xdiv - (8 * pm)); - - if (am < 2) { - reg[1] = am + 8; - reg[2] = pm - 1; - } else { - reg[1] = am; - reg[2] = pm; - } - } else { - /* fix for frequency less than 45 MHz */ - reg[1] = 0x06; - reg[2] = 0x11; - } - - /* fix clock out */ - reg[6] |= 0x20; - - /* From VCO frequency determines the XIN ( fractional part of Delta - Sigma PLL) and divided value (XDIV) */ - xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2); - xin = (xin << 15) / xtal_freq_khz_2; - if (xin >= 16384) - xin += 32768; - - reg[3] = xin >> 8; - reg[4] = xin & 0xff; - - if (delsys == SYS_DVBT) { - reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */ - switch (p->bandwidth_hz) { - case 6000000: - reg[6] |= 0x80; - break; - case 7000000: - reg[6] |= 0x40; - break; - case 8000000: - default: - break; - } - } else { - err("%s: modulation type not supported!", __func__); - return -EINVAL; - } - - /* modified for Realtek demod */ - reg[5] |= 0x07; - - for (i = 1; i <= 6; i++) { - ret = fc0013_writereg(priv, i, reg[i]); - if (ret) - goto exit; - } - - ret = fc0013_readreg(priv, 0x11, &tmp); - if (ret) - goto exit; - if (multi == 64) - ret = fc0013_writereg(priv, 0x11, tmp | 0x04); - else - ret = fc0013_writereg(priv, 0x11, tmp & 0xfb); - if (ret) - goto exit; - - /* VCO Calibration */ - ret = fc0013_writereg(priv, 0x0e, 0x80); - if (!ret) - ret = fc0013_writereg(priv, 0x0e, 0x00); - - /* VCO Re-Calibration if needed */ - if (!ret) - ret = fc0013_writereg(priv, 0x0e, 0x00); - - if (!ret) { - msleep(10); - ret = fc0013_readreg(priv, 0x0e, &tmp); - } - if (ret) - goto exit; - - /* vco selection */ - tmp &= 0x3f; - - if (vco_select) { - if (tmp > 0x3c) { - reg[6] &= ~0x08; - ret = fc0013_writereg(priv, 0x06, reg[6]); - if (!ret) - ret = fc0013_writereg(priv, 0x0e, 0x80); - if (!ret) - ret = fc0013_writereg(priv, 0x0e, 0x00); - } - } else { - if (tmp < 0x02) { - reg[6] |= 0x08; - ret = fc0013_writereg(priv, 0x06, reg[6]); - if (!ret) - ret = fc0013_writereg(priv, 0x0e, 0x80); - if (!ret) - ret = fc0013_writereg(priv, 0x0e, 0x00); - } - } - - priv->frequency = p->frequency; - priv->bandwidth = p->bandwidth_hz; - -exit: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - if (ret) - warn("%s: failed: %d", __func__, ret); - return ret; -} - -static int fc0013_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct fc0013_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int fc0013_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - /* always ? */ - *frequency = 0; - return 0; -} - -static int fc0013_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct fc0013_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; - return 0; -} - -#define INPUT_ADC_LEVEL -8 - -static int fc0013_get_rf_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct fc0013_priv *priv = fe->tuner_priv; - int ret; - unsigned char tmp; - int int_temp, lna_gain, int_lna, tot_agc_gain, power; - const int fc0013_lna_gain_table[] = { - /* low gain */ - -63, -58, -99, -73, - -63, -65, -54, -60, - /* middle gain */ - 71, 70, 68, 67, - 65, 63, 61, 58, - /* high gain */ - 197, 191, 188, 186, - 184, 182, 181, 179, - }; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - ret = fc0013_writereg(priv, 0x13, 0x00); - if (ret) - goto err; - - ret = fc0013_readreg(priv, 0x13, &tmp); - if (ret) - goto err; - int_temp = tmp; - - ret = fc0013_readreg(priv, 0x14, &tmp); - if (ret) - goto err; - lna_gain = tmp & 0x1f; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - - if (lna_gain < ARRAY_SIZE(fc0013_lna_gain_table)) { - int_lna = fc0013_lna_gain_table[lna_gain]; - tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 + - (int_temp & 0x1f)) * 2; - power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10; - - if (power >= 45) - *strength = 255; /* 100% */ - else if (power < -95) - *strength = 0; - else - *strength = (power + 95) * 255 / 140; - - *strength |= *strength << 8; - } else { - ret = -1; - } - - goto exit; - -err: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ -exit: - if (ret) - warn("%s: failed: %d", __func__, ret); - return ret; -} - -static const struct dvb_tuner_ops fc0013_tuner_ops = { - .info = { - .name = "Fitipower FC0013", - - .frequency_min = 37000000, /* estimate */ - .frequency_max = 1680000000, /* CHECK */ - .frequency_step = 0, - }, - - .release = fc0013_release, - - .init = fc0013_init, - .sleep = fc0013_sleep, - - .set_params = fc0013_set_params, - - .get_frequency = fc0013_get_frequency, - .get_if_frequency = fc0013_get_if_frequency, - .get_bandwidth = fc0013_get_bandwidth, - - .get_rf_strength = fc0013_get_rf_strength, -}; - -struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, u8 i2c_address, int dual_master, - enum fc001x_xtal_freq xtal_freq) -{ - struct fc0013_priv *priv = NULL; - - priv = kzalloc(sizeof(struct fc0013_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->i2c = i2c; - priv->dual_master = dual_master; - priv->addr = i2c_address; - priv->xtal_freq = xtal_freq; - - info("Fitipower FC0013 successfully attached."); - - fe->tuner_priv = priv; - - memcpy(&fe->ops.tuner_ops, &fc0013_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - return fe; -} -EXPORT_SYMBOL(fc0013_attach); - -MODULE_DESCRIPTION("Fitipower FC0013 silicon tuner driver"); -MODULE_AUTHOR("Hans-Frieder Vogt "); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.2"); diff --git a/drivers/media/common/tuners/fc0013.h b/drivers/media/common/tuners/fc0013.h deleted file mode 100644 index 594efd64aeec..000000000000 --- a/drivers/media/common/tuners/fc0013.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Fitipower FC0013 tuner driver - * - * Copyright (C) 2012 Hans-Frieder Vogt - * - * 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 _FC0013_H_ -#define _FC0013_H_ - -#include "dvb_frontend.h" -#include "fc001x-common.h" - -#if defined(CONFIG_MEDIA_TUNER_FC0013) || \ - (defined(CONFIG_MEDIA_TUNER_FC0013_MODULE) && defined(MODULE)) -extern struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - u8 i2c_address, int dual_master, - enum fc001x_xtal_freq xtal_freq); -extern int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val); -extern int fc0013_rc_cal_reset(struct dvb_frontend *fe); -#else -static inline struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - u8 i2c_address, int dual_master, - enum fc001x_xtal_freq xtal_freq) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val) -{ - return 0; -} - -static inline int fc0013_rc_cal_reset(struct dvb_frontend *fe) -{ - return 0; -} -#endif - -#endif diff --git a/drivers/media/common/tuners/fc001x-common.h b/drivers/media/common/tuners/fc001x-common.h deleted file mode 100644 index 718818156934..000000000000 --- a/drivers/media/common/tuners/fc001x-common.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Fitipower FC0012 & FC0013 tuner driver - common defines - * - * Copyright (C) 2012 Hans-Frieder Vogt - * - * 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 _FC001X_COMMON_H_ -#define _FC001X_COMMON_H_ - -enum fc001x_xtal_freq { - FC_XTAL_27_MHZ, /* 27000000 */ - FC_XTAL_28_8_MHZ, /* 28800000 */ - FC_XTAL_36_MHZ, /* 36000000 */ -}; - -/* - * enum fc001x_fe_callback_commands - Frontend callbacks - * - * @FC_FE_CALLBACK_VHF_ENABLE: enable VHF or UHF - */ -enum fc001x_fe_callback_commands { - FC_FE_CALLBACK_VHF_ENABLE, -}; - -#endif diff --git a/drivers/media/common/tuners/max2165.c b/drivers/media/common/tuners/max2165.c deleted file mode 100644 index ba84936aafd6..000000000000 --- a/drivers/media/common/tuners/max2165.c +++ /dev/null @@ -1,433 +0,0 @@ -/* - * Driver for Maxim MAX2165 silicon tuner - * - * Copyright (c) 2009 David T. L. Wong - * - * 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 -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" - -#include "max2165.h" -#include "max2165_priv.h" -#include "tuner-i2c.h" - -#define dprintk(args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG "max2165: " args); \ - } while (0) - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -static int max2165_write_reg(struct max2165_priv *priv, u8 reg, u8 data) -{ - int ret; - u8 buf[] = { reg, data }; - struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 }; - - msg.addr = priv->config->i2c_address; - - if (debug >= 2) - dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data); - - ret = i2c_transfer(priv->i2c, &msg, 1); - - if (ret != 1) - dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n", - __func__, reg, data, ret); - - return (ret != 1) ? -EIO : 0; -} - -static int max2165_read_reg(struct max2165_priv *priv, u8 reg, u8 *p_data) -{ - int ret; - u8 dev_addr = priv->config->i2c_address; - - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - struct i2c_msg msg[] = { - { .addr = dev_addr, .flags = 0, .buf = b0, .len = 1 }, - { .addr = dev_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }, - }; - - ret = i2c_transfer(priv->i2c, msg, 2); - if (ret != 2) { - dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret); - return -EIO; - } - - *p_data = b1[0]; - if (debug >= 2) - dprintk("%s: reg=0x%02X, data=0x%02X\n", - __func__, reg, b1[0]); - return 0; -} - -static int max2165_mask_write_reg(struct max2165_priv *priv, u8 reg, - u8 mask, u8 data) -{ - int ret; - u8 v; - - data &= mask; - ret = max2165_read_reg(priv, reg, &v); - if (ret != 0) - return ret; - v &= ~mask; - v |= data; - ret = max2165_write_reg(priv, reg, v); - - return ret; -} - -static int max2165_read_rom_table(struct max2165_priv *priv) -{ - u8 dat[3]; - int i; - - for (i = 0; i < 3; i++) { - max2165_write_reg(priv, REG_ROM_TABLE_ADDR, i + 1); - max2165_read_reg(priv, REG_ROM_TABLE_DATA, &dat[i]); - } - - priv->tf_ntch_low_cfg = dat[0] >> 4; - priv->tf_ntch_hi_cfg = dat[0] & 0x0F; - priv->tf_balun_low_ref = dat[1] & 0x0F; - priv->tf_balun_hi_ref = dat[1] >> 4; - priv->bb_filter_7mhz_cfg = dat[2] & 0x0F; - priv->bb_filter_8mhz_cfg = dat[2] >> 4; - - dprintk("tf_ntch_low_cfg = 0x%X\n", priv->tf_ntch_low_cfg); - dprintk("tf_ntch_hi_cfg = 0x%X\n", priv->tf_ntch_hi_cfg); - dprintk("tf_balun_low_ref = 0x%X\n", priv->tf_balun_low_ref); - dprintk("tf_balun_hi_ref = 0x%X\n", priv->tf_balun_hi_ref); - dprintk("bb_filter_7mhz_cfg = 0x%X\n", priv->bb_filter_7mhz_cfg); - dprintk("bb_filter_8mhz_cfg = 0x%X\n", priv->bb_filter_8mhz_cfg); - - return 0; -} - -static int max2165_set_osc(struct max2165_priv *priv, u8 osc /*MHz*/) -{ - u8 v; - - v = (osc / 2); - if (v == 2) - v = 0x7; - else - v -= 8; - - max2165_mask_write_reg(priv, REG_PLL_CFG, 0x07, v); - - return 0; -} - -static int max2165_set_bandwidth(struct max2165_priv *priv, u32 bw) -{ - u8 val; - - if (bw == 8000000) - val = priv->bb_filter_8mhz_cfg; - else - val = priv->bb_filter_7mhz_cfg; - - max2165_mask_write_reg(priv, REG_BASEBAND_CTRL, 0xF0, val << 4); - - return 0; -} - -int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction) -{ - u32 remainder; - u32 q, f = 0; - int i; - - if (0 == divisor) - return -EINVAL; - - q = dividend / divisor; - remainder = dividend - q * divisor; - - for (i = 0; i < 31; i++) { - remainder <<= 1; - if (remainder >= divisor) { - f += 1; - remainder -= divisor; - } - f <<= 1; - } - - *quotient = q; - *fraction = f; - - return 0; -} - -static int max2165_set_rf(struct max2165_priv *priv, u32 freq) -{ - u8 tf; - u8 tf_ntch; - u32 t; - u32 quotient, fraction; - int ret; - - /* Set PLL divider according to RF frequency */ - ret = fixpt_div32(freq / 1000, priv->config->osc_clk * 1000, - "ient, &fraction); - if (ret != 0) - return ret; - - /* 20-bit fraction */ - fraction >>= 12; - - max2165_write_reg(priv, REG_NDIV_INT, quotient); - max2165_mask_write_reg(priv, REG_NDIV_FRAC2, 0x0F, fraction >> 16); - max2165_write_reg(priv, REG_NDIV_FRAC1, fraction >> 8); - max2165_write_reg(priv, REG_NDIV_FRAC0, fraction); - - /* Norch Filter */ - tf_ntch = (freq < 725000000) ? - priv->tf_ntch_low_cfg : priv->tf_ntch_hi_cfg; - - /* Tracking filter balun */ - t = priv->tf_balun_low_ref; - t += (priv->tf_balun_hi_ref - priv->tf_balun_low_ref) - * (freq / 1000 - 470000) / (780000 - 470000); - - tf = t; - dprintk("tf = %X\n", tf); - tf |= tf_ntch << 4; - - max2165_write_reg(priv, REG_TRACK_FILTER, tf); - - return 0; -} - -static void max2165_debug_status(struct max2165_priv *priv) -{ - u8 status, autotune; - u8 auto_vco_success, auto_vco_active; - u8 pll_locked; - u8 dc_offset_low, dc_offset_hi; - u8 signal_lv_over_threshold; - u8 vco, vco_sub_band, adc; - - max2165_read_reg(priv, REG_STATUS, &status); - max2165_read_reg(priv, REG_AUTOTUNE, &autotune); - - auto_vco_success = (status >> 6) & 0x01; - auto_vco_active = (status >> 5) & 0x01; - pll_locked = (status >> 4) & 0x01; - dc_offset_low = (status >> 3) & 0x01; - dc_offset_hi = (status >> 2) & 0x01; - signal_lv_over_threshold = status & 0x01; - - vco = autotune >> 6; - vco_sub_band = (autotune >> 3) & 0x7; - adc = autotune & 0x7; - - dprintk("auto VCO active: %d, auto VCO success: %d\n", - auto_vco_active, auto_vco_success); - dprintk("PLL locked: %d\n", pll_locked); - dprintk("DC offset low: %d, DC offset high: %d\n", - dc_offset_low, dc_offset_hi); - dprintk("Signal lvl over threshold: %d\n", signal_lv_over_threshold); - dprintk("VCO: %d, VCO Sub-band: %d, ADC: %d\n", vco, vco_sub_band, adc); -} - -static int max2165_set_params(struct dvb_frontend *fe) -{ - struct max2165_priv *priv = fe->tuner_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret; - - switch (c->bandwidth_hz) { - case 7000000: - case 8000000: - priv->frequency = c->frequency; - break; - default: - printk(KERN_INFO "MAX2165: bandwidth %d Hz not supported.\n", - c->bandwidth_hz); - return -EINVAL; - } - - dprintk("%s() frequency=%d\n", __func__, c->frequency); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - max2165_set_bandwidth(priv, c->bandwidth_hz); - ret = max2165_set_rf(priv, priv->frequency); - mdelay(50); - max2165_debug_status(priv); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - if (ret != 0) - return -EREMOTEIO; - - return 0; -} - -static int max2165_get_frequency(struct dvb_frontend *fe, u32 *freq) -{ - struct max2165_priv *priv = fe->tuner_priv; - dprintk("%s()\n", __func__); - *freq = priv->frequency; - return 0; -} - -static int max2165_get_bandwidth(struct dvb_frontend *fe, u32 *bw) -{ - struct max2165_priv *priv = fe->tuner_priv; - dprintk("%s()\n", __func__); - - *bw = priv->bandwidth; - return 0; -} - -static int max2165_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct max2165_priv *priv = fe->tuner_priv; - u16 lock_status = 0; - - dprintk("%s()\n", __func__); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - max2165_debug_status(priv); - *status = lock_status; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return 0; -} - -static int max2165_sleep(struct dvb_frontend *fe) -{ - dprintk("%s()\n", __func__); - return 0; -} - -static int max2165_init(struct dvb_frontend *fe) -{ - struct max2165_priv *priv = fe->tuner_priv; - dprintk("%s()\n", __func__); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - /* Setup initial values */ - /* Fractional Mode on */ - max2165_write_reg(priv, REG_NDIV_FRAC2, 0x18); - /* LNA on */ - max2165_write_reg(priv, REG_LNA, 0x01); - max2165_write_reg(priv, REG_PLL_CFG, 0x7A); - max2165_write_reg(priv, REG_TEST, 0x08); - max2165_write_reg(priv, REG_SHUTDOWN, 0x40); - max2165_write_reg(priv, REG_VCO_CTRL, 0x84); - max2165_write_reg(priv, REG_BASEBAND_CTRL, 0xC3); - max2165_write_reg(priv, REG_DC_OFFSET_CTRL, 0x75); - max2165_write_reg(priv, REG_DC_OFFSET_DAC, 0x00); - max2165_write_reg(priv, REG_ROM_TABLE_ADDR, 0x00); - - max2165_set_osc(priv, priv->config->osc_clk); - - max2165_read_rom_table(priv); - - max2165_set_bandwidth(priv, 8000000); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return 0; -} - -static int max2165_release(struct dvb_frontend *fe) -{ - struct max2165_priv *priv = fe->tuner_priv; - dprintk("%s()\n", __func__); - - kfree(priv); - fe->tuner_priv = NULL; - - return 0; -} - -static const struct dvb_tuner_ops max2165_tuner_ops = { - .info = { - .name = "Maxim MAX2165", - .frequency_min = 470000000, - .frequency_max = 780000000, - .frequency_step = 50000, - }, - - .release = max2165_release, - .init = max2165_init, - .sleep = max2165_sleep, - - .set_params = max2165_set_params, - .set_analog_params = NULL, - .get_frequency = max2165_get_frequency, - .get_bandwidth = max2165_get_bandwidth, - .get_status = max2165_get_status -}; - -struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct max2165_config *cfg) -{ - struct max2165_priv *priv = NULL; - - dprintk("%s(%d-%04x)\n", __func__, - i2c ? i2c_adapter_id(i2c) : -1, - cfg ? cfg->i2c_address : -1); - - priv = kzalloc(sizeof(struct max2165_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - memcpy(&fe->ops.tuner_ops, &max2165_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - priv->config = cfg; - priv->i2c = i2c; - fe->tuner_priv = priv; - - max2165_init(fe); - max2165_debug_status(priv); - - return fe; -} -EXPORT_SYMBOL(max2165_attach); - -MODULE_AUTHOR("David T. L. Wong "); -MODULE_DESCRIPTION("Maxim MAX2165 silicon tuner driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/max2165.h b/drivers/media/common/tuners/max2165.h deleted file mode 100644 index c063c36a93d3..000000000000 --- a/drivers/media/common/tuners/max2165.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Driver for Maxim MAX2165 silicon tuner - * - * Copyright (c) 2009 David T. L. Wong - * - * 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 __MAX2165_H__ -#define __MAX2165_H__ - -struct dvb_frontend; -struct i2c_adapter; - -struct max2165_config { - u8 i2c_address; - u8 osc_clk; /* in MHz, selectable values: 4,16,18,20,22,24,26,28 */ -}; - -#if defined(CONFIG_MEDIA_TUNER_MAX2165) || \ - (defined(CONFIG_MEDIA_TUNER_MAX2165_MODULE) && defined(MODULE)) -extern struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct max2165_config *cfg); -#else -static inline struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct max2165_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff --git a/drivers/media/common/tuners/max2165_priv.h b/drivers/media/common/tuners/max2165_priv.h deleted file mode 100644 index 91bbe021a08d..000000000000 --- a/drivers/media/common/tuners/max2165_priv.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Driver for Maxim MAX2165 silicon tuner - * - * Copyright (c) 2009 David T. L. Wong - * - * 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 __MAX2165_PRIV_H__ -#define __MAX2165_PRIV_H__ - -#define REG_NDIV_INT 0x00 -#define REG_NDIV_FRAC2 0x01 -#define REG_NDIV_FRAC1 0x02 -#define REG_NDIV_FRAC0 0x03 -#define REG_TRACK_FILTER 0x04 -#define REG_LNA 0x05 -#define REG_PLL_CFG 0x06 -#define REG_TEST 0x07 -#define REG_SHUTDOWN 0x08 -#define REG_VCO_CTRL 0x09 -#define REG_BASEBAND_CTRL 0x0A -#define REG_DC_OFFSET_CTRL 0x0B -#define REG_DC_OFFSET_DAC 0x0C -#define REG_ROM_TABLE_ADDR 0x0D - -/* Read Only Registers */ -#define REG_ROM_TABLE_DATA 0x10 -#define REG_STATUS 0x11 -#define REG_AUTOTUNE 0x12 - -struct max2165_priv { - struct max2165_config *config; - struct i2c_adapter *i2c; - - u32 frequency; - u32 bandwidth; - - u8 tf_ntch_low_cfg; - u8 tf_ntch_hi_cfg; - u8 tf_balun_low_ref; - u8 tf_balun_hi_ref; - u8 bb_filter_7mhz_cfg; - u8 bb_filter_8mhz_cfg; -}; - -#endif diff --git a/drivers/media/common/tuners/mc44s803.c b/drivers/media/common/tuners/mc44s803.c deleted file mode 100644 index 5ddce7e326f7..000000000000 --- a/drivers/media/common/tuners/mc44s803.c +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner - * - * Copyright (c) 2009 Jochen Friedrich - * - * 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 -#include -#include -#include -#include - -#include "dvb_frontend.h" - -#include "mc44s803.h" -#include "mc44s803_priv.h" - -#define mc_printk(level, format, arg...) \ - printk(level "mc44s803: " format , ## arg) - -/* Writes a single register */ -static int mc44s803_writereg(struct mc44s803_priv *priv, u32 val) -{ - u8 buf[3]; - struct i2c_msg msg = { - .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 3 - }; - - buf[0] = (val & 0xff0000) >> 16; - buf[1] = (val & 0xff00) >> 8; - buf[2] = (val & 0xff); - - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - mc_printk(KERN_WARNING, "I2C write failed\n"); - return -EREMOTEIO; - } - return 0; -} - -/* Reads a single register */ -static int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val) -{ - u32 wval; - u8 buf[3]; - int ret; - struct i2c_msg msg[] = { - { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, - .buf = buf, .len = 3 }, - }; - - wval = MC44S803_REG_SM(MC44S803_REG_DATAREG, MC44S803_ADDR) | - MC44S803_REG_SM(reg, MC44S803_D); - - ret = mc44s803_writereg(priv, wval); - if (ret) - return ret; - - if (i2c_transfer(priv->i2c, msg, 1) != 1) { - mc_printk(KERN_WARNING, "I2C read failed\n"); - return -EREMOTEIO; - } - - *val = (buf[0] << 16) | (buf[1] << 8) | buf[2]; - - return 0; -} - -static int mc44s803_release(struct dvb_frontend *fe) -{ - struct mc44s803_priv *priv = fe->tuner_priv; - - fe->tuner_priv = NULL; - kfree(priv); - - return 0; -} - -static int mc44s803_init(struct dvb_frontend *fe) -{ - struct mc44s803_priv *priv = fe->tuner_priv; - u32 val; - int err; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - -/* Reset chip */ - val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR) | - MC44S803_REG_SM(1, MC44S803_RS); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - -/* Power Up and Start Osc */ - - val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) | - MC44S803_REG_SM(0xC0, MC44S803_REFOSC) | - MC44S803_REG_SM(1, MC44S803_OSCSEL); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - val = MC44S803_REG_SM(MC44S803_REG_POWER, MC44S803_ADDR) | - MC44S803_REG_SM(0x200, MC44S803_POWER); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - msleep(10); - - val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) | - MC44S803_REG_SM(0x40, MC44S803_REFOSC) | - MC44S803_REG_SM(1, MC44S803_OSCSEL); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - msleep(20); - -/* Setup Mixer */ - - val = MC44S803_REG_SM(MC44S803_REG_MIXER, MC44S803_ADDR) | - MC44S803_REG_SM(1, MC44S803_TRI_STATE) | - MC44S803_REG_SM(0x7F, MC44S803_MIXER_RES); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - -/* Setup Cirquit Adjust */ - - val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) | - MC44S803_REG_SM(1, MC44S803_G1) | - MC44S803_REG_SM(1, MC44S803_G3) | - MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) | - MC44S803_REG_SM(1, MC44S803_G6) | - MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) | - MC44S803_REG_SM(0x3, MC44S803_LP) | - MC44S803_REG_SM(1, MC44S803_CLRF) | - MC44S803_REG_SM(1, MC44S803_CLIF); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) | - MC44S803_REG_SM(1, MC44S803_G1) | - MC44S803_REG_SM(1, MC44S803_G3) | - MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) | - MC44S803_REG_SM(1, MC44S803_G6) | - MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) | - MC44S803_REG_SM(0x3, MC44S803_LP); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - -/* Setup Digtune */ - - val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | - MC44S803_REG_SM(3, MC44S803_XOD); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - -/* Setup AGC */ - - val = MC44S803_REG_SM(MC44S803_REG_LNAAGC, MC44S803_ADDR) | - MC44S803_REG_SM(1, MC44S803_AT1) | - MC44S803_REG_SM(1, MC44S803_AT2) | - MC44S803_REG_SM(1, MC44S803_AGC_AN_DIG) | - MC44S803_REG_SM(1, MC44S803_AGC_READ_EN) | - MC44S803_REG_SM(1, MC44S803_LNA0); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - return 0; - -exit: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - mc_printk(KERN_WARNING, "I/O Error\n"); - return err; -} - -static int mc44s803_set_params(struct dvb_frontend *fe) -{ - struct mc44s803_priv *priv = fe->tuner_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u32 r1, r2, n1, n2, lo1, lo2, freq, val; - int err; - - priv->frequency = c->frequency; - - r1 = MC44S803_OSC / 1000000; - r2 = MC44S803_OSC / 100000; - - n1 = (c->frequency + MC44S803_IF1 + 500000) / 1000000; - freq = MC44S803_OSC / r1 * n1; - lo1 = ((60 * n1) + (r1 / 2)) / r1; - freq = freq - c->frequency; - - n2 = (freq - MC44S803_IF2 + 50000) / 100000; - lo2 = ((60 * n2) + (r2 / 2)) / r2; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - val = MC44S803_REG_SM(MC44S803_REG_REFDIV, MC44S803_ADDR) | - MC44S803_REG_SM(r1-1, MC44S803_R1) | - MC44S803_REG_SM(r2-1, MC44S803_R2) | - MC44S803_REG_SM(1, MC44S803_REFBUF_EN); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - val = MC44S803_REG_SM(MC44S803_REG_LO1, MC44S803_ADDR) | - MC44S803_REG_SM(n1-2, MC44S803_LO1); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - val = MC44S803_REG_SM(MC44S803_REG_LO2, MC44S803_ADDR) | - MC44S803_REG_SM(n2-2, MC44S803_LO2); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | - MC44S803_REG_SM(1, MC44S803_DA) | - MC44S803_REG_SM(lo1, MC44S803_LO_REF) | - MC44S803_REG_SM(1, MC44S803_AT); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | - MC44S803_REG_SM(2, MC44S803_DA) | - MC44S803_REG_SM(lo2, MC44S803_LO_REF) | - MC44S803_REG_SM(1, MC44S803_AT); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return 0; - -exit: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - mc_printk(KERN_WARNING, "I/O Error\n"); - return err; -} - -static int mc44s803_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct mc44s803_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static const struct dvb_tuner_ops mc44s803_tuner_ops = { - .info = { - .name = "Freescale MC44S803", - .frequency_min = 48000000, - .frequency_max = 1000000000, - .frequency_step = 100000, - }, - - .release = mc44s803_release, - .init = mc44s803_init, - .set_params = mc44s803_set_params, - .get_frequency = mc44s803_get_frequency -}; - -/* This functions tries to identify a MC44S803 tuner by reading the ID - register. This is hasty. */ -struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct mc44s803_config *cfg) -{ - struct mc44s803_priv *priv; - u32 reg; - u8 id; - int ret; - - reg = 0; - - priv = kzalloc(sizeof(struct mc44s803_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->cfg = cfg; - priv->i2c = i2c; - priv->fe = fe; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - ret = mc44s803_readreg(priv, MC44S803_REG_ID, ®); - if (ret) - goto error; - - id = MC44S803_REG_MS(reg, MC44S803_ID); - - if (id != 0x14) { - mc_printk(KERN_ERR, "unsupported ID " - "(%x should be 0x14)\n", id); - goto error; - } - - mc_printk(KERN_INFO, "successfully identified (ID = %x)\n", id); - memcpy(&fe->ops.tuner_ops, &mc44s803_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = priv; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - return fe; - -error: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - kfree(priv); - return NULL; -} -EXPORT_SYMBOL(mc44s803_attach); - -MODULE_AUTHOR("Jochen Friedrich"); -MODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/mc44s803.h b/drivers/media/common/tuners/mc44s803.h deleted file mode 100644 index 34f3892d3f6d..000000000000 --- a/drivers/media/common/tuners/mc44s803.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner - * - * Copyright (c) 2009 Jochen Friedrich - * - * 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 MC44S803_H -#define MC44S803_H - -struct dvb_frontend; -struct i2c_adapter; - -struct mc44s803_config { - u8 i2c_address; - u8 dig_out; -}; - -#if defined(CONFIG_MEDIA_TUNER_MC44S803) || \ - (defined(CONFIG_MEDIA_TUNER_MC44S803_MODULE) && defined(MODULE)) -extern struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct mc44s803_config *cfg); -#else -static inline struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct mc44s803_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_MEDIA_TUNER_MC44S803 */ - -#endif diff --git a/drivers/media/common/tuners/mc44s803_priv.h b/drivers/media/common/tuners/mc44s803_priv.h deleted file mode 100644 index 14a92780906d..000000000000 --- a/drivers/media/common/tuners/mc44s803_priv.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner - * - * Copyright (c) 2009 Jochen Friedrich - * - * 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 MC44S803_PRIV_H -#define MC44S803_PRIV_H - -/* This driver is based on the information available in the datasheet - http://www.freescale.com/files/rf_if/doc/data_sheet/MC44S803.pdf - - SPI or I2C Address : 0xc0-0xc6 - - Reg.No | Function - ------------------------------------------- - 00 | Power Down - 01 | Reference Oszillator - 02 | Reference Dividers - 03 | Mixer and Reference Buffer - 04 | Reset/Serial Out - 05 | LO 1 - 06 | LO 2 - 07 | Circuit Adjust - 08 | Test - 09 | Digital Tune - 0A | LNA AGC - 0B | Data Register Address - 0C | Regulator Test - 0D | VCO Test - 0E | LNA Gain/Input Power - 0F | ID Bits - -*/ - -#define MC44S803_OSC 26000000 /* 26 MHz */ -#define MC44S803_IF1 1086000000 /* 1086 MHz */ -#define MC44S803_IF2 36125000 /* 36.125 MHz */ - -#define MC44S803_REG_POWER 0 -#define MC44S803_REG_REFOSC 1 -#define MC44S803_REG_REFDIV 2 -#define MC44S803_REG_MIXER 3 -#define MC44S803_REG_RESET 4 -#define MC44S803_REG_LO1 5 -#define MC44S803_REG_LO2 6 -#define MC44S803_REG_CIRCADJ 7 -#define MC44S803_REG_TEST 8 -#define MC44S803_REG_DIGTUNE 9 -#define MC44S803_REG_LNAAGC 0x0A -#define MC44S803_REG_DATAREG 0x0B -#define MC44S803_REG_REGTEST 0x0C -#define MC44S803_REG_VCOTEST 0x0D -#define MC44S803_REG_LNAGAIN 0x0E -#define MC44S803_REG_ID 0x0F - -/* Register definitions */ -#define MC44S803_ADDR 0x0F -#define MC44S803_ADDR_S 0 -/* REG_POWER */ -#define MC44S803_POWER 0xFFFFF0 -#define MC44S803_POWER_S 4 -/* REG_REFOSC */ -#define MC44S803_REFOSC 0x1FF0 -#define MC44S803_REFOSC_S 4 -#define MC44S803_OSCSEL 0x2000 -#define MC44S803_OSCSEL_S 13 -/* REG_REFDIV */ -#define MC44S803_R2 0x1FF0 -#define MC44S803_R2_S 4 -#define MC44S803_REFBUF_EN 0x2000 -#define MC44S803_REFBUF_EN_S 13 -#define MC44S803_R1 0x7C000 -#define MC44S803_R1_S 14 -/* REG_MIXER */ -#define MC44S803_R3 0x70 -#define MC44S803_R3_S 4 -#define MC44S803_MUX3 0x80 -#define MC44S803_MUX3_S 7 -#define MC44S803_MUX4 0x100 -#define MC44S803_MUX4_S 8 -#define MC44S803_OSC_SCR 0x200 -#define MC44S803_OSC_SCR_S 9 -#define MC44S803_TRI_STATE 0x400 -#define MC44S803_TRI_STATE_S 10 -#define MC44S803_BUF_GAIN 0x800 -#define MC44S803_BUF_GAIN_S 11 -#define MC44S803_BUF_IO 0x1000 -#define MC44S803_BUF_IO_S 12 -#define MC44S803_MIXER_RES 0xFE000 -#define MC44S803_MIXER_RES_S 13 -/* REG_RESET */ -#define MC44S803_RS 0x10 -#define MC44S803_RS_S 4 -#define MC44S803_SO 0x20 -#define MC44S803_SO_S 5 -/* REG_LO1 */ -#define MC44S803_LO1 0xFFF0 -#define MC44S803_LO1_S 4 -/* REG_LO2 */ -#define MC44S803_LO2 0x7FFF0 -#define MC44S803_LO2_S 4 -/* REG_CIRCADJ */ -#define MC44S803_G1 0x20 -#define MC44S803_G1_S 5 -#define MC44S803_G3 0x80 -#define MC44S803_G3_S 7 -#define MC44S803_CIRCADJ_RES 0x300 -#define MC44S803_CIRCADJ_RES_S 8 -#define MC44S803_G6 0x400 -#define MC44S803_G6_S 10 -#define MC44S803_G7 0x800 -#define MC44S803_G7_S 11 -#define MC44S803_S1 0x1000 -#define MC44S803_S1_S 12 -#define MC44S803_LP 0x7E000 -#define MC44S803_LP_S 13 -#define MC44S803_CLRF 0x80000 -#define MC44S803_CLRF_S 19 -#define MC44S803_CLIF 0x100000 -#define MC44S803_CLIF_S 20 -/* REG_TEST */ -/* REG_DIGTUNE */ -#define MC44S803_DA 0xF0 -#define MC44S803_DA_S 4 -#define MC44S803_XOD 0x300 -#define MC44S803_XOD_S 8 -#define MC44S803_RST 0x10000 -#define MC44S803_RST_S 16 -#define MC44S803_LO_REF 0x1FFF00 -#define MC44S803_LO_REF_S 8 -#define MC44S803_AT 0x200000 -#define MC44S803_AT_S 21 -#define MC44S803_MT 0x400000 -#define MC44S803_MT_S 22 -/* REG_LNAAGC */ -#define MC44S803_G 0x3F0 -#define MC44S803_G_S 4 -#define MC44S803_AT1 0x400 -#define MC44S803_AT1_S 10 -#define MC44S803_AT2 0x800 -#define MC44S803_AT2_S 11 -#define MC44S803_HL_GR_EN 0x8000 -#define MC44S803_HL_GR_EN_S 15 -#define MC44S803_AGC_AN_DIG 0x10000 -#define MC44S803_AGC_AN_DIG_S 16 -#define MC44S803_ATTEN_EN 0x20000 -#define MC44S803_ATTEN_EN_S 17 -#define MC44S803_AGC_READ_EN 0x40000 -#define MC44S803_AGC_READ_EN_S 18 -#define MC44S803_LNA0 0x80000 -#define MC44S803_LNA0_S 19 -#define MC44S803_AGC_SEL 0x100000 -#define MC44S803_AGC_SEL_S 20 -#define MC44S803_AT0 0x200000 -#define MC44S803_AT0_S 21 -#define MC44S803_B 0xC00000 -#define MC44S803_B_S 22 -/* REG_DATAREG */ -#define MC44S803_D 0xF0 -#define MC44S803_D_S 4 -/* REG_REGTEST */ -/* REG_VCOTEST */ -/* REG_LNAGAIN */ -#define MC44S803_IF_PWR 0x700 -#define MC44S803_IF_PWR_S 8 -#define MC44S803_RF_PWR 0x3800 -#define MC44S803_RF_PWR_S 11 -#define MC44S803_LNA_GAIN 0xFC000 -#define MC44S803_LNA_GAIN_S 14 -/* REG_ID */ -#define MC44S803_ID 0x3E00 -#define MC44S803_ID_S 9 - -/* Some macros to read/write fields */ - -/* First shift, then mask */ -#define MC44S803_REG_SM(_val, _reg) \ - (((_val) << _reg##_S) & (_reg)) - -/* First mask, then shift */ -#define MC44S803_REG_MS(_val, _reg) \ - (((_val) & (_reg)) >> _reg##_S) - -struct mc44s803_priv { - struct mc44s803_config *cfg; - struct i2c_adapter *i2c; - struct dvb_frontend *fe; - - u32 frequency; -}; - -#endif diff --git a/drivers/media/common/tuners/mt2060.c b/drivers/media/common/tuners/mt2060.c deleted file mode 100644 index 13381de58a84..000000000000 --- a/drivers/media/common/tuners/mt2060.c +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" - * - * Copyright (c) 2006 Olivier DANET - * - * 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.= - */ - -/* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ - -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" - -#include "mt2060.h" -#include "mt2060_priv.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2060: " args); printk("\n"); }} while (0) - -// Reads a single register -static int mt2060_readreg(struct mt2060_priv *priv, u8 reg, u8 *val) -{ - struct i2c_msg msg[2] = { - { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, - { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, - }; - - if (i2c_transfer(priv->i2c, msg, 2) != 2) { - printk(KERN_WARNING "mt2060 I2C read failed\n"); - return -EREMOTEIO; - } - return 0; -} - -// Writes a single register -static int mt2060_writereg(struct mt2060_priv *priv, u8 reg, u8 val) -{ - u8 buf[2] = { reg, val }; - struct i2c_msg msg = { - .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 - }; - - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "mt2060 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; -} - -// Writes a set of consecutive registers -static int mt2060_writeregs(struct mt2060_priv *priv,u8 *buf, u8 len) -{ - struct i2c_msg msg = { - .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len - }; - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n",(int)len); - return -EREMOTEIO; - } - return 0; -} - -// Initialisation sequences -// LNABAND=3, NUM1=0x3C, DIV1=0x74, NUM2=0x1080, DIV2=0x49 -static u8 mt2060_config1[] = { - REG_LO1C1, - 0x3F, 0x74, 0x00, 0x08, 0x93 -}; - -// FMCG=2, GP2=0, GP1=0 -static u8 mt2060_config2[] = { - REG_MISC_CTRL, - 0x20, 0x1E, 0x30, 0xff, 0x80, 0xff, 0x00, 0x2c, 0x42 -}; - -// VGAG=3, V1CSE=1 - -#ifdef MT2060_SPURCHECK -/* The function below calculates the frequency offset between the output frequency if2 - and the closer cross modulation subcarrier between lo1 and lo2 up to the tenth harmonic */ -static int mt2060_spurcalc(u32 lo1,u32 lo2,u32 if2) -{ - int I,J; - int dia,diamin,diff; - diamin=1000000; - for (I = 1; I < 10; I++) { - J = ((2*I*lo1)/lo2+1)/2; - diff = I*(int)lo1-J*(int)lo2; - if (diff < 0) diff=-diff; - dia = (diff-(int)if2); - if (dia < 0) dia=-dia; - if (diamin > dia) diamin=dia; - } - return diamin; -} - -#define BANDWIDTH 4000 // kHz - -/* Calculates the frequency offset to add to avoid spurs. Returns 0 if no offset is needed */ -static int mt2060_spurcheck(u32 lo1,u32 lo2,u32 if2) -{ - u32 Spur,Sp1,Sp2; - int I,J; - I=0; - J=1000; - - Spur=mt2060_spurcalc(lo1,lo2,if2); - if (Spur < BANDWIDTH) { - /* Potential spurs detected */ - dprintk("Spurs before : f_lo1: %d f_lo2: %d (kHz)", - (int)lo1,(int)lo2); - I=1000; - Sp1 = mt2060_spurcalc(lo1+I,lo2+I,if2); - Sp2 = mt2060_spurcalc(lo1-I,lo2-I,if2); - - if (Sp1 < Sp2) { - J=-J; I=-I; Spur=Sp2; - } else - Spur=Sp1; - - while (Spur < BANDWIDTH) { - I += J; - Spur = mt2060_spurcalc(lo1+I,lo2+I,if2); - } - dprintk("Spurs after : f_lo1: %d f_lo2: %d (kHz)", - (int)(lo1+I),(int)(lo2+I)); - } - return I; -} -#endif - -#define IF2 36150 // IF2 frequency = 36.150 MHz -#define FREF 16000 // Quartz oscillator 16 MHz - -static int mt2060_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct mt2060_priv *priv; - int ret=0; - int i=0; - u32 freq; - u8 lnaband; - u32 f_lo1,f_lo2; - u32 div1,num1,div2,num2; - u8 b[8]; - u32 if1; - - priv = fe->tuner_priv; - - if1 = priv->if1_freq; - b[0] = REG_LO1B1; - b[1] = 0xFF; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - mt2060_writeregs(priv,b,2); - - freq = c->frequency / 1000; /* Hz -> kHz */ - - f_lo1 = freq + if1 * 1000; - f_lo1 = (f_lo1 / 250) * 250; - f_lo2 = f_lo1 - freq - IF2; - // From the Comtech datasheet, the step used is 50kHz. The tuner chip could be more precise - f_lo2 = ((f_lo2 + 25) / 50) * 50; - priv->frequency = (f_lo1 - f_lo2 - IF2) * 1000, - -#ifdef MT2060_SPURCHECK - // LO-related spurs detection and correction - num1 = mt2060_spurcheck(f_lo1,f_lo2,IF2); - f_lo1 += num1; - f_lo2 += num1; -#endif - //Frequency LO1 = 16MHz * (DIV1 + NUM1/64 ) - num1 = f_lo1 / (FREF / 64); - div1 = num1 / 64; - num1 &= 0x3f; - - // Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) - num2 = f_lo2 * 64 / (FREF / 128); - div2 = num2 / 8192; - num2 &= 0x1fff; - - if (freq <= 95000) lnaband = 0xB0; else - if (freq <= 180000) lnaband = 0xA0; else - if (freq <= 260000) lnaband = 0x90; else - if (freq <= 335000) lnaband = 0x80; else - if (freq <= 425000) lnaband = 0x70; else - if (freq <= 480000) lnaband = 0x60; else - if (freq <= 570000) lnaband = 0x50; else - if (freq <= 645000) lnaband = 0x40; else - if (freq <= 730000) lnaband = 0x30; else - if (freq <= 810000) lnaband = 0x20; else lnaband = 0x10; - - b[0] = REG_LO1C1; - b[1] = lnaband | ((num1 >>2) & 0x0F); - b[2] = div1; - b[3] = (num2 & 0x0F) | ((num1 & 3) << 4); - b[4] = num2 >> 4; - b[5] = ((num2 >>12) & 1) | (div2 << 1); - - dprintk("IF1: %dMHz",(int)if1); - dprintk("PLL freq=%dkHz f_lo1=%dkHz f_lo2=%dkHz",(int)freq,(int)f_lo1,(int)f_lo2); - dprintk("PLL div1=%d num1=%d div2=%d num2=%d",(int)div1,(int)num1,(int)div2,(int)num2); - dprintk("PLL [1..5]: %2x %2x %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3],(int)b[4],(int)b[5]); - - mt2060_writeregs(priv,b,6); - - //Waits for pll lock or timeout - i = 0; - do { - mt2060_readreg(priv,REG_LO_STATUS,b); - if ((b[0] & 0x88)==0x88) - break; - msleep(4); - i++; - } while (i<10); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - return ret; -} - -static void mt2060_calibrate(struct mt2060_priv *priv) -{ - u8 b = 0; - int i = 0; - - if (mt2060_writeregs(priv,mt2060_config1,sizeof(mt2060_config1))) - return; - if (mt2060_writeregs(priv,mt2060_config2,sizeof(mt2060_config2))) - return; - - /* initialize the clock output */ - mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30); - - do { - b |= (1 << 6); // FM1SS; - mt2060_writereg(priv, REG_LO2C1,b); - msleep(20); - - if (i == 0) { - b |= (1 << 7); // FM1CA; - mt2060_writereg(priv, REG_LO2C1,b); - b &= ~(1 << 7); // FM1CA; - msleep(20); - } - - b &= ~(1 << 6); // FM1SS - mt2060_writereg(priv, REG_LO2C1,b); - - msleep(20); - i++; - } while (i < 9); - - i = 0; - while (i++ < 10 && mt2060_readreg(priv, REG_MISC_STAT, &b) == 0 && (b & (1 << 6)) == 0) - msleep(20); - - if (i <= 10) { - mt2060_readreg(priv, REG_FM_FREQ, &priv->fmfreq); // now find out, what is fmreq used for :) - dprintk("calibration was successful: %d", (int)priv->fmfreq); - } else - dprintk("FMCAL timed out"); -} - -static int mt2060_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct mt2060_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int mt2060_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - *frequency = IF2 * 1000; - return 0; -} - -static int mt2060_init(struct dvb_frontend *fe) -{ - struct mt2060_priv *priv = fe->tuner_priv; - int ret; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - ret = mt2060_writereg(priv, REG_VGAG, - (priv->cfg->clock_out << 6) | 0x33); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - return ret; -} - -static int mt2060_sleep(struct dvb_frontend *fe) -{ - struct mt2060_priv *priv = fe->tuner_priv; - int ret; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - ret = mt2060_writereg(priv, REG_VGAG, - (priv->cfg->clock_out << 6) | 0x30); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - return ret; -} - -static int mt2060_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static const struct dvb_tuner_ops mt2060_tuner_ops = { - .info = { - .name = "Microtune MT2060", - .frequency_min = 48000000, - .frequency_max = 860000000, - .frequency_step = 50000, - }, - - .release = mt2060_release, - - .init = mt2060_init, - .sleep = mt2060_sleep, - - .set_params = mt2060_set_params, - .get_frequency = mt2060_get_frequency, - .get_if_frequency = mt2060_get_if_frequency, -}; - -/* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */ -struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) -{ - struct mt2060_priv *priv = NULL; - u8 id = 0; - - priv = kzalloc(sizeof(struct mt2060_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->cfg = cfg; - priv->i2c = i2c; - priv->if1_freq = if1; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) { - kfree(priv); - return NULL; - } - - if (id != PART_REV) { - kfree(priv); - return NULL; - } - printk(KERN_INFO "MT2060: successfully identified (IF1 = %d)\n", if1); - memcpy(&fe->ops.tuner_ops, &mt2060_tuner_ops, sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = priv; - - mt2060_calibrate(priv); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - return fe; -} -EXPORT_SYMBOL(mt2060_attach); - -MODULE_AUTHOR("Olivier DANET"); -MODULE_DESCRIPTION("Microtune MT2060 silicon tuner driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/mt2060.h b/drivers/media/common/tuners/mt2060.h deleted file mode 100644 index cb60caffb6b6..000000000000 --- a/drivers/media/common/tuners/mt2060.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" - * - * Copyright (c) 2006 Olivier DANET - * - * 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 MT2060_H -#define MT2060_H - -struct dvb_frontend; -struct i2c_adapter; - -struct mt2060_config { - u8 i2c_address; - u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ -}; - -#if defined(CONFIG_MEDIA_TUNER_MT2060) || (defined(CONFIG_MEDIA_TUNER_MT2060_MODULE) && defined(MODULE)) -extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1); -#else -static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_MEDIA_TUNER_MT2060 - -#endif diff --git a/drivers/media/common/tuners/mt2060_priv.h b/drivers/media/common/tuners/mt2060_priv.h deleted file mode 100644 index 2b60de6c707d..000000000000 --- a/drivers/media/common/tuners/mt2060_priv.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" - * - * Copyright (c) 2006 Olivier DANET - * - * 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 MT2060_PRIV_H -#define MT2060_PRIV_H - -// Uncomment the #define below to enable spurs checking. The results where quite unconvincing. -// #define MT2060_SPURCHECK - -/* This driver is based on the information available in the datasheet of the - "Comtech SDVBT-3K6M" tuner ( K1000737843.pdf ) which features the MT2060 register map : - - I2C Address : 0x60 - - Reg.No | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | ( defaults ) - -------------------------------------------------------------------------------- - 00 | [ PART ] | [ REV ] | R = 0x63 - 01 | [ LNABAND ] | [ NUM1(5:2) ] | RW = 0x3F - 02 | [ DIV1 ] | RW = 0x74 - 03 | FM1CA | FM1SS | [ NUM1(1:0) ] | [ NUM2(3:0) ] | RW = 0x00 - 04 | NUM2(11:4) ] | RW = 0x08 - 05 | [ DIV2 ] |NUM2(12)| RW = 0x93 - 06 | L1LK | [ TAD1 ] | L2LK | [ TAD2 ] | R - 07 | [ FMF ] | R - 08 | ? | FMCAL | ? | ? | ? | ? | ? | TEMP | R - 09 | 0 | 0 | [ FMGC ] | 0 | GP02 | GP01 | 0 | RW = 0x20 - 0A | ?? - 0B | 0 | 0 | 1 | 1 | 0 | 0 | [ VGAG ] | RW = 0x30 - 0C | V1CSE | 1 | 1 | 1 | 1 | 1 | 1 | 1 | RW = 0xFF - 0D | 1 | 0 | [ V1CS ] | RW = 0xB0 - 0E | ?? - 0F | ?? - 10 | ?? - 11 | [ LOTO ] | 0 | 0 | 1 | 0 | RW = 0x42 - - PART : Part code : 6 for MT2060 - REV : Revision code : 3 for current revision - LNABAND : Input frequency range : ( See code for details ) - NUM1 / DIV1 / NUM2 / DIV2 : Frequencies programming ( See code for details ) - FM1CA : Calibration Start Bit - FM1SS : Calibration Single Step bit - L1LK : LO1 Lock Detect - TAD1 : Tune Line ADC ( ? ) - L2LK : LO2 Lock Detect - TAD2 : Tune Line ADC ( ? ) - FMF : Estimated first IF Center frequency Offset ( ? ) - FM1CAL : Calibration done bit - TEMP : On chip temperature sensor - FMCG : Mixer 1 Cap Gain ( ? ) - GP01 / GP02 : Programmable digital outputs. Unconnected pins ? - V1CSE : LO1 VCO Automatic Capacitor Select Enable ( ? ) - V1CS : LO1 Capacitor Selection Value ( ? ) - LOTO : LO Timeout ( ? ) - VGAG : Tuner Output gain -*/ - -#define I2C_ADDRESS 0x60 - -#define REG_PART_REV 0 -#define REG_LO1C1 1 -#define REG_LO1C2 2 -#define REG_LO2C1 3 -#define REG_LO2C2 4 -#define REG_LO2C3 5 -#define REG_LO_STATUS 6 -#define REG_FM_FREQ 7 -#define REG_MISC_STAT 8 -#define REG_MISC_CTRL 9 -#define REG_RESERVED_A 0x0A -#define REG_VGAG 0x0B -#define REG_LO1B1 0x0C -#define REG_LO1B2 0x0D -#define REG_LOTO 0x11 - -#define PART_REV 0x63 // The current driver works only with PART=6 and REV=3 chips - -struct mt2060_priv { - struct mt2060_config *cfg; - struct i2c_adapter *i2c; - - u32 frequency; - u16 if1_freq; - u8 fmfreq; -}; - -#endif diff --git a/drivers/media/common/tuners/mt2063.c b/drivers/media/common/tuners/mt2063.c deleted file mode 100644 index 0ed9091ff48e..000000000000 --- a/drivers/media/common/tuners/mt2063.c +++ /dev/null @@ -1,2307 +0,0 @@ -/* - * Driver for mt2063 Micronas tuner - * - * Copyright (c) 2011 Mauro Carvalho Chehab - * - * This driver came from a driver originally written by: - * Henry Wang - * Made publicly available by Terratec, at: - * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz - * The original driver's license is GPL, as declared with MODULE_LICENSE() - * - * 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 under version 2 of the License. - * - * 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. - */ - -#include -#include -#include -#include -#include - -#include "mt2063.h" - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Set Verbosity level"); - -#define dprintk(level, fmt, arg...) do { \ -if (debug >= level) \ - printk(KERN_DEBUG "mt2063 %s: " fmt, __func__, ## arg); \ -} while (0) - - -/* positive error codes used internally */ - -/* Info: Unavoidable LO-related spur may be present in the output */ -#define MT2063_SPUR_PRESENT_ERR (0x00800000) - -/* Info: Mask of bits used for # of LO-related spurs that were avoided during tuning */ -#define MT2063_SPUR_CNT_MASK (0x001f0000) -#define MT2063_SPUR_SHIFT (16) - -/* Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */ -#define MT2063_UPC_RANGE (0x04000000) - -/* Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */ -#define MT2063_DNC_RANGE (0x08000000) - -/* - * Constant defining the version of the following structure - * and therefore the API for this code. - * - * When compiling the tuner driver, the preprocessor will - * check against this version number to make sure that - * it matches the version that the tuner driver knows about. - */ - -/* DECT Frequency Avoidance */ -#define MT2063_DECT_AVOID_US_FREQS 0x00000001 - -#define MT2063_DECT_AVOID_EURO_FREQS 0x00000002 - -#define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0) - -#define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0) - -enum MT2063_DECT_Avoid_Type { - MT2063_NO_DECT_AVOIDANCE = 0, /* Do not create DECT exclusion zones. */ - MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS, /* Avoid US DECT frequencies. */ - MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS, /* Avoid European DECT frequencies. */ - MT2063_AVOID_BOTH /* Avoid both regions. Not typically used. */ -}; - -#define MT2063_MAX_ZONES 48 - -struct MT2063_ExclZone_t { - u32 min_; - u32 max_; - struct MT2063_ExclZone_t *next_; -}; - -/* - * Structure of data needed for Spur Avoidance - */ -struct MT2063_AvoidSpursData_t { - u32 f_ref; - u32 f_in; - u32 f_LO1; - u32 f_if1_Center; - u32 f_if1_Request; - u32 f_if1_bw; - u32 f_LO2; - u32 f_out; - u32 f_out_bw; - u32 f_LO1_Step; - u32 f_LO2_Step; - u32 f_LO1_FracN_Avoid; - u32 f_LO2_FracN_Avoid; - u32 f_zif_bw; - u32 f_min_LO_Separation; - u32 maxH1; - u32 maxH2; - enum MT2063_DECT_Avoid_Type avoidDECT; - u32 bSpurPresent; - u32 bSpurAvoided; - u32 nSpursFound; - u32 nZones; - struct MT2063_ExclZone_t *freeZones; - struct MT2063_ExclZone_t *usedZones; - struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES]; -}; - -/* - * Parameter for function MT2063_SetPowerMask that specifies the power down - * of various sections of the MT2063. - */ -enum MT2063_Mask_Bits { - MT2063_REG_SD = 0x0040, /* Shutdown regulator */ - MT2063_SRO_SD = 0x0020, /* Shutdown SRO */ - MT2063_AFC_SD = 0x0010, /* Shutdown AFC A/D */ - MT2063_PD_SD = 0x0002, /* Enable power detector shutdown */ - MT2063_PDADC_SD = 0x0001, /* Enable power detector A/D shutdown */ - MT2063_VCO_SD = 0x8000, /* Enable VCO shutdown */ - MT2063_LTX_SD = 0x4000, /* Enable LTX shutdown */ - MT2063_LT1_SD = 0x2000, /* Enable LT1 shutdown */ - MT2063_LNA_SD = 0x1000, /* Enable LNA shutdown */ - MT2063_UPC_SD = 0x0800, /* Enable upconverter shutdown */ - MT2063_DNC_SD = 0x0400, /* Enable downconverter shutdown */ - MT2063_VGA_SD = 0x0200, /* Enable VGA shutdown */ - MT2063_AMP_SD = 0x0100, /* Enable AMP shutdown */ - MT2063_ALL_SD = 0xFF73, /* All shutdown bits for this tuner */ - MT2063_NONE_SD = 0x0000 /* No shutdown bits */ -}; - -/* - * Possible values for MT2063_DNC_OUTPUT - */ -enum MT2063_DNC_Output_Enable { - MT2063_DNC_NONE = 0, - MT2063_DNC_1, - MT2063_DNC_2, - MT2063_DNC_BOTH -}; - -/* - * Two-wire serial bus subaddresses of the tuner registers. - * Also known as the tuner's register addresses. - */ -enum MT2063_Register_Offsets { - MT2063_REG_PART_REV = 0, /* 0x00: Part/Rev Code */ - MT2063_REG_LO1CQ_1, /* 0x01: LO1C Queued Byte 1 */ - MT2063_REG_LO1CQ_2, /* 0x02: LO1C Queued Byte 2 */ - MT2063_REG_LO2CQ_1, /* 0x03: LO2C Queued Byte 1 */ - MT2063_REG_LO2CQ_2, /* 0x04: LO2C Queued Byte 2 */ - MT2063_REG_LO2CQ_3, /* 0x05: LO2C Queued Byte 3 */ - MT2063_REG_RSVD_06, /* 0x06: Reserved */ - MT2063_REG_LO_STATUS, /* 0x07: LO Status */ - MT2063_REG_FIFFC, /* 0x08: FIFF Center */ - MT2063_REG_CLEARTUNE, /* 0x09: ClearTune Filter */ - MT2063_REG_ADC_OUT, /* 0x0A: ADC_OUT */ - MT2063_REG_LO1C_1, /* 0x0B: LO1C Byte 1 */ - MT2063_REG_LO1C_2, /* 0x0C: LO1C Byte 2 */ - MT2063_REG_LO2C_1, /* 0x0D: LO2C Byte 1 */ - MT2063_REG_LO2C_2, /* 0x0E: LO2C Byte 2 */ - MT2063_REG_LO2C_3, /* 0x0F: LO2C Byte 3 */ - MT2063_REG_RSVD_10, /* 0x10: Reserved */ - MT2063_REG_PWR_1, /* 0x11: PWR Byte 1 */ - MT2063_REG_PWR_2, /* 0x12: PWR Byte 2 */ - MT2063_REG_TEMP_STATUS, /* 0x13: Temp Status */ - MT2063_REG_XO_STATUS, /* 0x14: Crystal Status */ - MT2063_REG_RF_STATUS, /* 0x15: RF Attn Status */ - MT2063_REG_FIF_STATUS, /* 0x16: FIF Attn Status */ - MT2063_REG_LNA_OV, /* 0x17: LNA Attn Override */ - MT2063_REG_RF_OV, /* 0x18: RF Attn Override */ - MT2063_REG_FIF_OV, /* 0x19: FIF Attn Override */ - MT2063_REG_LNA_TGT, /* 0x1A: Reserved */ - MT2063_REG_PD1_TGT, /* 0x1B: Pwr Det 1 Target */ - MT2063_REG_PD2_TGT, /* 0x1C: Pwr Det 2 Target */ - MT2063_REG_RSVD_1D, /* 0x1D: Reserved */ - MT2063_REG_RSVD_1E, /* 0x1E: Reserved */ - MT2063_REG_RSVD_1F, /* 0x1F: Reserved */ - MT2063_REG_RSVD_20, /* 0x20: Reserved */ - MT2063_REG_BYP_CTRL, /* 0x21: Bypass Control */ - MT2063_REG_RSVD_22, /* 0x22: Reserved */ - MT2063_REG_RSVD_23, /* 0x23: Reserved */ - MT2063_REG_RSVD_24, /* 0x24: Reserved */ - MT2063_REG_RSVD_25, /* 0x25: Reserved */ - MT2063_REG_RSVD_26, /* 0x26: Reserved */ - MT2063_REG_RSVD_27, /* 0x27: Reserved */ - MT2063_REG_FIFF_CTRL, /* 0x28: FIFF Control */ - MT2063_REG_FIFF_OFFSET, /* 0x29: FIFF Offset */ - MT2063_REG_CTUNE_CTRL, /* 0x2A: Reserved */ - MT2063_REG_CTUNE_OV, /* 0x2B: Reserved */ - MT2063_REG_CTRL_2C, /* 0x2C: Reserved */ - MT2063_REG_FIFF_CTRL2, /* 0x2D: Fiff Control */ - MT2063_REG_RSVD_2E, /* 0x2E: Reserved */ - MT2063_REG_DNC_GAIN, /* 0x2F: DNC Control */ - MT2063_REG_VGA_GAIN, /* 0x30: VGA Gain Ctrl */ - MT2063_REG_RSVD_31, /* 0x31: Reserved */ - MT2063_REG_TEMP_SEL, /* 0x32: Temperature Selection */ - MT2063_REG_RSVD_33, /* 0x33: Reserved */ - MT2063_REG_RSVD_34, /* 0x34: Reserved */ - MT2063_REG_RSVD_35, /* 0x35: Reserved */ - MT2063_REG_RSVD_36, /* 0x36: Reserved */ - MT2063_REG_RSVD_37, /* 0x37: Reserved */ - MT2063_REG_RSVD_38, /* 0x38: Reserved */ - MT2063_REG_RSVD_39, /* 0x39: Reserved */ - MT2063_REG_RSVD_3A, /* 0x3A: Reserved */ - MT2063_REG_RSVD_3B, /* 0x3B: Reserved */ - MT2063_REG_RSVD_3C, /* 0x3C: Reserved */ - MT2063_REG_END_REGS -}; - -struct mt2063_state { - struct i2c_adapter *i2c; - - bool init; - - const struct mt2063_config *config; - struct dvb_tuner_ops ops; - struct dvb_frontend *frontend; - struct tuner_state status; - - u32 frequency; - u32 srate; - u32 bandwidth; - u32 reference; - - u32 tuner_id; - struct MT2063_AvoidSpursData_t AS_Data; - u32 f_IF1_actual; - u32 rcvr_mode; - u32 ctfilt_sw; - u32 CTFiltMax[31]; - u32 num_regs; - u8 reg[MT2063_REG_END_REGS]; -}; - -/* - * mt2063_write - Write data into the I2C bus - */ -static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len) -{ - struct dvb_frontend *fe = state->frontend; - int ret; - u8 buf[60]; - struct i2c_msg msg = { - .addr = state->config->tuner_address, - .flags = 0, - .buf = buf, - .len = len + 1 - }; - - dprintk(2, "\n"); - - msg.buf[0] = reg; - memcpy(msg.buf + 1, data, len); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - ret = i2c_transfer(state->i2c, &msg, 1); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - if (ret < 0) - printk(KERN_ERR "%s error ret=%d\n", __func__, ret); - - return ret; -} - -/* - * mt2063_write - Write register data into the I2C bus, caching the value - */ -static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val) -{ - u32 status; - - dprintk(2, "\n"); - - if (reg >= MT2063_REG_END_REGS) - return -ERANGE; - - status = mt2063_write(state, reg, &val, 1); - if (status < 0) - return status; - - state->reg[reg] = val; - - return 0; -} - -/* - * mt2063_read - Read data from the I2C bus - */ -static u32 mt2063_read(struct mt2063_state *state, - u8 subAddress, u8 *pData, u32 cnt) -{ - u32 status = 0; /* Status to be returned */ - struct dvb_frontend *fe = state->frontend; - u32 i = 0; - - dprintk(2, "addr 0x%02x, cnt %d\n", subAddress, cnt); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - for (i = 0; i < cnt; i++) { - u8 b0[] = { subAddress + i }; - struct i2c_msg msg[] = { - { - .addr = state->config->tuner_address, - .flags = 0, - .buf = b0, - .len = 1 - }, { - .addr = state->config->tuner_address, - .flags = I2C_M_RD, - .buf = pData + i, - .len = 1 - } - }; - - status = i2c_transfer(state->i2c, msg, 2); - dprintk(2, "addr 0x%02x, ret = %d, val = 0x%02x\n", - subAddress + i, status, *(pData + i)); - if (status < 0) - break; - } - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - if (status < 0) - printk(KERN_ERR "Can't read from address 0x%02x,\n", - subAddress + i); - - return status; -} - -/* - * FIXME: Is this really needed? - */ -static int MT2063_Sleep(struct dvb_frontend *fe) -{ - /* - * ToDo: Add code here to implement a OS blocking - */ - msleep(100); - - return 0; -} - -/* - * Microtune spur avoidance - */ - -/* Implement ceiling, floor functions. */ -#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0)) -#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d)) - -struct MT2063_FIFZone_t { - s32 min_; - s32 max_; -}; - -static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t - *pAS_Info, - struct MT2063_ExclZone_t *pPrevNode) -{ - struct MT2063_ExclZone_t *pNode; - - dprintk(2, "\n"); - - /* Check for a node in the free list */ - if (pAS_Info->freeZones != NULL) { - /* Use one from the free list */ - pNode = pAS_Info->freeZones; - pAS_Info->freeZones = pNode->next_; - } else { - /* Grab a node from the array */ - pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones]; - } - - if (pPrevNode != NULL) { - pNode->next_ = pPrevNode->next_; - pPrevNode->next_ = pNode; - } else { /* insert at the beginning of the list */ - - pNode->next_ = pAS_Info->usedZones; - pAS_Info->usedZones = pNode; - } - - pAS_Info->nZones++; - return pNode; -} - -static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t - *pAS_Info, - struct MT2063_ExclZone_t *pPrevNode, - struct MT2063_ExclZone_t - *pNodeToRemove) -{ - struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_; - - dprintk(2, "\n"); - - /* Make previous node point to the subsequent node */ - if (pPrevNode != NULL) - pPrevNode->next_ = pNext; - - /* Add pNodeToRemove to the beginning of the freeZones */ - pNodeToRemove->next_ = pAS_Info->freeZones; - pAS_Info->freeZones = pNodeToRemove; - - /* Decrement node count */ - pAS_Info->nZones--; - - return pNext; -} - -/* - * MT_AddExclZone() - * - * Add (and merge) an exclusion zone into the list. - * If the range (f_min, f_max) is totally outside the - * 1st IF BW, ignore the entry. - * If the range (f_min, f_max) is negative, ignore the entry. - */ -static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info, - u32 f_min, u32 f_max) -{ - struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones; - struct MT2063_ExclZone_t *pPrev = NULL; - struct MT2063_ExclZone_t *pNext = NULL; - - dprintk(2, "\n"); - - /* Check to see if this overlaps the 1st IF filter */ - if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2))) - && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2))) - && (f_min < f_max)) { - /* - * 1 2 3 4 5 6 - * - * New entry: |---| |--| |--| |-| |---| |--| - * or or or or or - * Existing: |--| |--| |--| |---| |-| |--| - */ - - /* Check for our place in the list */ - while ((pNode != NULL) && (pNode->max_ < f_min)) { - pPrev = pNode; - pNode = pNode->next_; - } - - if ((pNode != NULL) && (pNode->min_ < f_max)) { - /* Combine me with pNode */ - if (f_min < pNode->min_) - pNode->min_ = f_min; - if (f_max > pNode->max_) - pNode->max_ = f_max; - } else { - pNode = InsertNode(pAS_Info, pPrev); - pNode->min_ = f_min; - pNode->max_ = f_max; - } - - /* Look for merging possibilities */ - pNext = pNode->next_; - while ((pNext != NULL) && (pNext->min_ < pNode->max_)) { - if (pNext->max_ > pNode->max_) - pNode->max_ = pNext->max_; - /* Remove pNext, return ptr to pNext->next */ - pNext = RemoveNode(pAS_Info, pNode, pNext); - } - } -} - -/* - * Reset all exclusion zones. - * Add zones to protect the PLL FracN regions near zero - */ -static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info) -{ - u32 center; - - dprintk(2, "\n"); - - pAS_Info->nZones = 0; /* this clears the used list */ - pAS_Info->usedZones = NULL; /* reset ptr */ - pAS_Info->freeZones = NULL; /* reset ptr */ - - center = - pAS_Info->f_ref * - ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 + - pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in; - while (center < - pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 + - pAS_Info->f_LO1_FracN_Avoid) { - /* Exclude LO1 FracN */ - MT2063_AddExclZone(pAS_Info, - center - pAS_Info->f_LO1_FracN_Avoid, - center - 1); - MT2063_AddExclZone(pAS_Info, center + 1, - center + pAS_Info->f_LO1_FracN_Avoid); - center += pAS_Info->f_ref; - } - - center = - pAS_Info->f_ref * - ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 - - pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out; - while (center < - pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 + - pAS_Info->f_LO2_FracN_Avoid) { - /* Exclude LO2 FracN */ - MT2063_AddExclZone(pAS_Info, - center - pAS_Info->f_LO2_FracN_Avoid, - center - 1); - MT2063_AddExclZone(pAS_Info, center + 1, - center + pAS_Info->f_LO2_FracN_Avoid); - center += pAS_Info->f_ref; - } - - if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) { - /* Exclude LO1 values that conflict with DECT channels */ - MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */ - MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */ - MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */ - MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */ - MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */ - } - - if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) { - MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */ - MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */ - MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */ - MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */ - MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */ - MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */ - MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */ - MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */ - MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */ - MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */ - } -} - -/* - * MT_ChooseFirstIF - Choose the best available 1st IF - * If f_Desired is not excluded, choose that first. - * Otherwise, return the value closest to f_Center that is - * not excluded - */ -static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info) -{ - /* - * Update "f_Desired" to be the nearest "combinational-multiple" of - * "f_LO1_Step". - * The resulting number, F_LO1 must be a multiple of f_LO1_Step. - * And F_LO1 is the arithmetic sum of f_in + f_Center. - * Neither f_in, nor f_Center must be a multiple of f_LO1_Step. - * However, the sum must be. - */ - const u32 f_Desired = - pAS_Info->f_LO1_Step * - ((pAS_Info->f_if1_Request + pAS_Info->f_in + - pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) - - pAS_Info->f_in; - const u32 f_Step = - (pAS_Info->f_LO1_Step > - pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info-> - f_LO2_Step; - u32 f_Center; - s32 i; - s32 j = 0; - u32 bDesiredExcluded = 0; - u32 bZeroExcluded = 0; - s32 tmpMin, tmpMax; - s32 bestDiff; - struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones; - struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES]; - - dprintk(2, "\n"); - - if (pAS_Info->nZones == 0) - return f_Desired; - - /* - * f_Center needs to be an integer multiple of f_Step away - * from f_Desired - */ - if (pAS_Info->f_if1_Center > f_Desired) - f_Center = - f_Desired + - f_Step * - ((pAS_Info->f_if1_Center - f_Desired + - f_Step / 2) / f_Step); - else - f_Center = - f_Desired - - f_Step * - ((f_Desired - pAS_Info->f_if1_Center + - f_Step / 2) / f_Step); - - /* - * Take MT_ExclZones, center around f_Center and change the - * resolution to f_Step - */ - while (pNode != NULL) { - /* floor function */ - tmpMin = - floor((s32) (pNode->min_ - f_Center), (s32) f_Step); - - /* ceil function */ - tmpMax = - ceil((s32) (pNode->max_ - f_Center), (s32) f_Step); - - if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired)) - bDesiredExcluded = 1; - - if ((tmpMin < 0) && (tmpMax > 0)) - bZeroExcluded = 1; - - /* See if this zone overlaps the previous */ - if ((j > 0) && (tmpMin < zones[j - 1].max_)) - zones[j - 1].max_ = tmpMax; - else { - /* Add new zone */ - zones[j].min_ = tmpMin; - zones[j].max_ = tmpMax; - j++; - } - pNode = pNode->next_; - } - - /* - * If the desired is okay, return with it - */ - if (bDesiredExcluded == 0) - return f_Desired; - - /* - * If the desired is excluded and the center is okay, return with it - */ - if (bZeroExcluded == 0) - return f_Center; - - /* Find the value closest to 0 (f_Center) */ - bestDiff = zones[0].min_; - for (i = 0; i < j; i++) { - if (abs(zones[i].min_) < abs(bestDiff)) - bestDiff = zones[i].min_; - if (abs(zones[i].max_) < abs(bestDiff)) - bestDiff = zones[i].max_; - } - - if (bestDiff < 0) - return f_Center - ((u32) (-bestDiff) * f_Step); - - return f_Center + (bestDiff * f_Step); -} - -/** - * gcd() - Uses Euclid's algorithm - * - * @u, @v: Unsigned values whose GCD is desired. - * - * Returns THE greatest common divisor of u and v, if either value is 0, - * the other value is returned as the result. - */ -static u32 MT2063_gcd(u32 u, u32 v) -{ - u32 r; - - while (v != 0) { - r = u % v; - u = v; - v = r; - } - - return u; -} - -/** - * IsSpurInBand() - Checks to see if a spur will be present within the IF's - * bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW) - * - * ma mb mc md - * <--+-+-+-------------------+-------------------+-+-+--> - * | ^ 0 ^ | - * ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^ - * a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2 - * - * Note that some equations are doubled to prevent round-off - * problems when calculating fIFBW/2 - * - * @pAS_Info: Avoid Spurs information block - * @fm: If spur, amount f_IF1 has to move negative - * @fp: If spur, amount f_IF1 has to move positive - * - * Returns 1 if an LO spur would be present, otherwise 0. - */ -static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info, - u32 *fm, u32 * fp) -{ - /* - ** Calculate LO frequency settings. - */ - u32 n, n0; - const u32 f_LO1 = pAS_Info->f_LO1; - const u32 f_LO2 = pAS_Info->f_LO2; - const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2; - const u32 c = d - pAS_Info->f_out_bw; - const u32 f = pAS_Info->f_zif_bw / 2; - const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1; - s32 f_nsLO1, f_nsLO2; - s32 f_Spur; - u32 ma, mb, mc, md, me, mf; - u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs; - - dprintk(2, "\n"); - - *fm = 0; - - /* - ** For each edge (d, c & f), calculate a scale, based on the gcd - ** of f_LO1, f_LO2 and the edge value. Use the larger of this - ** gcd-based scale factor or f_Scale. - */ - lo_gcd = MT2063_gcd(f_LO1, f_LO2); - gd_Scale = max((u32) MT2063_gcd(lo_gcd, d), f_Scale); - hgds = gd_Scale / 2; - gc_Scale = max((u32) MT2063_gcd(lo_gcd, c), f_Scale); - hgcs = gc_Scale / 2; - gf_Scale = max((u32) MT2063_gcd(lo_gcd, f), f_Scale); - hgfs = gf_Scale / 2; - - n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2); - - /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */ - for (n = n0; n <= pAS_Info->maxH1; ++n) { - md = (n * ((f_LO1 + hgds) / gd_Scale) - - ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale); - - /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */ - if (md >= pAS_Info->maxH1) - break; - - ma = (n * ((f_LO1 + hgds) / gd_Scale) + - ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale); - - /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */ - if (md == ma) - continue; - - mc = (n * ((f_LO1 + hgcs) / gc_Scale) - - ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale); - if (mc != md) { - f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale)); - f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale)); - f_Spur = - (gc_Scale * (f_nsLO1 - f_nsLO2)) + - n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale); - - *fp = ((f_Spur - (s32) c) / (mc - n)) + 1; - *fm = (((s32) d - f_Spur) / (mc - n)) + 1; - return 1; - } - - /* Location of Zero-IF-spur to be checked */ - me = (n * ((f_LO1 + hgfs) / gf_Scale) + - ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale); - mf = (n * ((f_LO1 + hgfs) / gf_Scale) - - ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale); - if (me != mf) { - f_nsLO1 = n * (f_LO1 / gf_Scale); - f_nsLO2 = me * (f_LO2 / gf_Scale); - f_Spur = - (gf_Scale * (f_nsLO1 - f_nsLO2)) + - n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale); - - *fp = ((f_Spur + (s32) f) / (me - n)) + 1; - *fm = (((s32) f - f_Spur) / (me - n)) + 1; - return 1; - } - - mb = (n * ((f_LO1 + hgcs) / gc_Scale) + - ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale); - if (ma != mb) { - f_nsLO1 = n * (f_LO1 / gc_Scale); - f_nsLO2 = ma * (f_LO2 / gc_Scale); - f_Spur = - (gc_Scale * (f_nsLO1 - f_nsLO2)) + - n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale); - - *fp = (((s32) d + f_Spur) / (ma - n)) + 1; - *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1; - return 1; - } - } - - /* No spurs found */ - return 0; -} - -/* - * MT_AvoidSpurs() - Main entry point to avoid spurs. - * Checks for existing spurs in present LO1, LO2 freqs - * and if present, chooses spur-free LO1, LO2 combination - * that tunes the same input/output frequencies. - */ -static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info) -{ - u32 status = 0; - u32 fm, fp; /* restricted range on LO's */ - pAS_Info->bSpurAvoided = 0; - pAS_Info->nSpursFound = 0; - - dprintk(2, "\n"); - - if (pAS_Info->maxH1 == 0) - return 0; - - /* - * Avoid LO Generated Spurs - * - * Make sure that have no LO-related spurs within the IF output - * bandwidth. - * - * If there is an LO spur in this band, start at the current IF1 frequency - * and work out until we find a spur-free frequency or run up against the - * 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they - * will be unchanged if a spur-free setting is not found. - */ - pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp); - if (pAS_Info->bSpurPresent) { - u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */ - u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */ - u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */ - u32 delta_IF1; - u32 new_IF1; - - /* - ** Spur was found, attempt to find a spur-free 1st IF - */ - do { - pAS_Info->nSpursFound++; - - /* Raise f_IF1_upper, if needed */ - MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp); - - /* Choose next IF1 that is closest to f_IF1_CENTER */ - new_IF1 = MT2063_ChooseFirstIF(pAS_Info); - - if (new_IF1 > zfIF1) { - pAS_Info->f_LO1 += (new_IF1 - zfIF1); - pAS_Info->f_LO2 += (new_IF1 - zfIF1); - } else { - pAS_Info->f_LO1 -= (zfIF1 - new_IF1); - pAS_Info->f_LO2 -= (zfIF1 - new_IF1); - } - zfIF1 = new_IF1; - - if (zfIF1 > pAS_Info->f_if1_Center) - delta_IF1 = zfIF1 - pAS_Info->f_if1_Center; - else - delta_IF1 = pAS_Info->f_if1_Center - zfIF1; - - pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp); - /* - * Continue while the new 1st IF is still within the 1st IF bandwidth - * and there is a spur in the band (again) - */ - } while ((2 * delta_IF1 + pAS_Info->f_out_bw <= pAS_Info->f_if1_bw) && pAS_Info->bSpurPresent); - - /* - * Use the LO-spur free values found. If the search went all - * the way to the 1st IF band edge and always found spurs, just - * leave the original choice. It's as "good" as any other. - */ - if (pAS_Info->bSpurPresent == 1) { - status |= MT2063_SPUR_PRESENT_ERR; - pAS_Info->f_LO1 = zfLO1; - pAS_Info->f_LO2 = zfLO2; - } else - pAS_Info->bSpurAvoided = 1; - } - - status |= - ((pAS_Info-> - nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK); - - return status; -} - -/* - * Constants used by the tuning algorithm - */ -#define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */ -#define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */ -#define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */ -#define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */ -#define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */ -#define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */ -#define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */ -#define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */ -#define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */ -#define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */ -#define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */ -#define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */ -#define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */ -#define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */ -#define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */ -#define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */ -#define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */ -#define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */ - -/* - * Define the supported Part/Rev codes for the MT2063 - */ -#define MT2063_B0 (0x9B) -#define MT2063_B1 (0x9C) -#define MT2063_B2 (0x9D) -#define MT2063_B3 (0x9E) - -/** - * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked - * - * @state: struct mt2063_state pointer - * - * This function returns 0, if no lock, 1 if locked and a value < 1 if error - */ -static unsigned int mt2063_lockStatus(struct mt2063_state *state) -{ - const u32 nMaxWait = 100; /* wait a maximum of 100 msec */ - const u32 nPollRate = 2; /* poll status bits every 2 ms */ - const u32 nMaxLoops = nMaxWait / nPollRate; - const u8 LO1LK = 0x80; - u8 LO2LK = 0x08; - u32 status; - u32 nDelays = 0; - - dprintk(2, "\n"); - - /* LO2 Lock bit was in a different place for B0 version */ - if (state->tuner_id == MT2063_B0) - LO2LK = 0x40; - - do { - status = mt2063_read(state, MT2063_REG_LO_STATUS, - &state->reg[MT2063_REG_LO_STATUS], 1); - - if (status < 0) - return status; - - if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) == - (LO1LK | LO2LK)) { - return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO; - } - msleep(nPollRate); /* Wait between retries */ - } while (++nDelays < nMaxLoops); - - /* - * Got no lock or partial lock - */ - return 0; -} - -/* - * Constants for setting receiver modes. - * (6 modes defined at this time, enumerated by mt2063_delivery_sys) - * (DNC1GC & DNC2GC are the values, which are used, when the specific - * DNC Output is selected, the other is always off) - * - * enum mt2063_delivery_sys - * -------------+---------------------------------------------- - * Mode 0 : | MT2063_CABLE_QAM - * Mode 1 : | MT2063_CABLE_ANALOG - * Mode 2 : | MT2063_OFFAIR_COFDM - * Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS - * Mode 4 : | MT2063_OFFAIR_ANALOG - * Mode 5 : | MT2063_OFFAIR_8VSB - * --------------+---------------------------------------------- - * - * |<---------- Mode -------------->| - * Reg Field | 0 | 1 | 2 | 3 | 4 | 5 | - * ------------+-----+-----+-----+-----+-----+-----+ - * RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF - * LNARin | 0 | 0 | 3 | 3 | 3 | 3 - * FIFFQen | 1 | 1 | 1 | 1 | 1 | 1 - * FIFFq | 0 | 0 | 0 | 0 | 0 | 0 - * DNC1gc | 0 | 0 | 0 | 0 | 0 | 0 - * DNC2gc | 0 | 0 | 0 | 0 | 0 | 0 - * GCU Auto | 1 | 1 | 1 | 1 | 1 | 1 - * LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31 - * LNA Target | 44 | 43 | 43 | 43 | 43 | 43 - * ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0 - * RF max Atn | 31 | 31 | 31 | 31 | 31 | 31 - * PD1 Target | 36 | 36 | 38 | 38 | 36 | 38 - * ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0 - * FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5 - * PD2 Target | 40 | 33 | 42 | 42 | 33 | 42 - */ - -enum mt2063_delivery_sys { - MT2063_CABLE_QAM = 0, - MT2063_CABLE_ANALOG, - MT2063_OFFAIR_COFDM, - MT2063_OFFAIR_COFDM_SAWLESS, - MT2063_OFFAIR_ANALOG, - MT2063_OFFAIR_8VSB, - MT2063_NUM_RCVR_MODES -}; - -static const char *mt2063_mode_name[] = { - [MT2063_CABLE_QAM] = "digital cable", - [MT2063_CABLE_ANALOG] = "analog cable", - [MT2063_OFFAIR_COFDM] = "digital offair", - [MT2063_OFFAIR_COFDM_SAWLESS] = "digital offair without SAW", - [MT2063_OFFAIR_ANALOG] = "analog offair", - [MT2063_OFFAIR_8VSB] = "analog offair 8vsb", -}; - -static const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 }; -static const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 }; -static const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 }; -static const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 }; -static const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 }; -static const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 }; -static const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 }; -static const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 }; -static const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 }; -static const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 }; -static const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 }; -static const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 }; -static const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 }; -static const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 }; - -/* - * mt2063_set_dnc_output_enable() - */ -static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state, - enum MT2063_DNC_Output_Enable *pValue) -{ - dprintk(2, "\n"); - - if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */ - if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */ - *pValue = MT2063_DNC_NONE; - else - *pValue = MT2063_DNC_2; - } else { /* DNC1 is on */ - if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */ - *pValue = MT2063_DNC_1; - else - *pValue = MT2063_DNC_BOTH; - } - return 0; -} - -/* - * mt2063_set_dnc_output_enable() - */ -static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state, - enum MT2063_DNC_Output_Enable nValue) -{ - u32 status = 0; /* Status to be returned */ - u8 val = 0; - - dprintk(2, "\n"); - - /* selects, which DNC output is used */ - switch (nValue) { - case MT2063_DNC_NONE: - val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */ - if (state->reg[MT2063_REG_DNC_GAIN] != - val) - status |= - mt2063_setreg(state, - MT2063_REG_DNC_GAIN, - val); - - val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */ - if (state->reg[MT2063_REG_VGA_GAIN] != - val) - status |= - mt2063_setreg(state, - MT2063_REG_VGA_GAIN, - val); - - val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */ - if (state->reg[MT2063_REG_RSVD_20] != - val) - status |= - mt2063_setreg(state, - MT2063_REG_RSVD_20, - val); - - break; - case MT2063_DNC_1: - val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */ - if (state->reg[MT2063_REG_DNC_GAIN] != - val) - status |= - mt2063_setreg(state, - MT2063_REG_DNC_GAIN, - val); - - val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */ - if (state->reg[MT2063_REG_VGA_GAIN] != - val) - status |= - mt2063_setreg(state, - MT2063_REG_VGA_GAIN, - val); - - val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */ - if (state->reg[MT2063_REG_RSVD_20] != - val) - status |= - mt2063_setreg(state, - MT2063_REG_RSVD_20, - val); - - break; - case MT2063_DNC_2: - val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */ - if (state->reg[MT2063_REG_DNC_GAIN] != - val) - status |= - mt2063_setreg(state, - MT2063_REG_DNC_GAIN, - val); - - val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */ - if (state->reg[MT2063_REG_VGA_GAIN] != - val) - status |= - mt2063_setreg(state, - MT2063_REG_VGA_GAIN, - val); - - val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */ - if (state->reg[MT2063_REG_RSVD_20] != - val) - status |= - mt2063_setreg(state, - MT2063_REG_RSVD_20, - val); - - break; - case MT2063_DNC_BOTH: - val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */ - if (state->reg[MT2063_REG_DNC_GAIN] != - val) - status |= - mt2063_setreg(state, - MT2063_REG_DNC_GAIN, - val); - - val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */ - if (state->reg[MT2063_REG_VGA_GAIN] != - val) - status |= - mt2063_setreg(state, - MT2063_REG_VGA_GAIN, - val); - - val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */ - if (state->reg[MT2063_REG_RSVD_20] != - val) - status |= - mt2063_setreg(state, - MT2063_REG_RSVD_20, - val); - - break; - default: - break; - } - - return status; -} - -/* - * MT2063_SetReceiverMode() - Set the MT2063 receiver mode, according with - * the selected enum mt2063_delivery_sys type. - * - * (DNC1GC & DNC2GC are the values, which are used, when the specific - * DNC Output is selected, the other is always off) - * - * @state: ptr to mt2063_state structure - * @Mode: desired reciever delivery system - * - * Note: Register cache must be valid for it to work - */ - -static u32 MT2063_SetReceiverMode(struct mt2063_state *state, - enum mt2063_delivery_sys Mode) -{ - u32 status = 0; /* Status to be returned */ - u8 val; - u32 longval; - - dprintk(2, "\n"); - - if (Mode >= MT2063_NUM_RCVR_MODES) - status = -ERANGE; - - /* RFAGCen */ - if (status >= 0) { - val = - (state-> - reg[MT2063_REG_PD1_TGT] & (u8) ~0x40) | (RFAGCEN[Mode] - ? 0x40 : - 0x00); - if (state->reg[MT2063_REG_PD1_TGT] != val) - status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); - } - - /* LNARin */ - if (status >= 0) { - u8 val = (state->reg[MT2063_REG_CTRL_2C] & (u8) ~0x03) | - (LNARIN[Mode] & 0x03); - if (state->reg[MT2063_REG_CTRL_2C] != val) - status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val); - } - - /* FIFFQEN and FIFFQ */ - if (status >= 0) { - val = - (state-> - reg[MT2063_REG_FIFF_CTRL2] & (u8) ~0xF0) | - (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4); - if (state->reg[MT2063_REG_FIFF_CTRL2] != val) { - status |= - mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val); - /* trigger FIFF calibration, needed after changing FIFFQ */ - val = - (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01); - status |= - mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); - val = - (state-> - reg[MT2063_REG_FIFF_CTRL] & (u8) ~0x01); - status |= - mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); - } - } - - /* DNC1GC & DNC2GC */ - status |= mt2063_get_dnc_output_enable(state, &longval); - status |= mt2063_set_dnc_output_enable(state, longval); - - /* acLNAmax */ - if (status >= 0) { - u8 val = (state->reg[MT2063_REG_LNA_OV] & (u8) ~0x1F) | - (ACLNAMAX[Mode] & 0x1F); - if (state->reg[MT2063_REG_LNA_OV] != val) - status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val); - } - - /* LNATGT */ - if (status >= 0) { - u8 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x3F) | - (LNATGT[Mode] & 0x3F); - if (state->reg[MT2063_REG_LNA_TGT] != val) - status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); - } - - /* ACRF */ - if (status >= 0) { - u8 val = (state->reg[MT2063_REG_RF_OV] & (u8) ~0x1F) | - (ACRFMAX[Mode] & 0x1F); - if (state->reg[MT2063_REG_RF_OV] != val) - status |= mt2063_setreg(state, MT2063_REG_RF_OV, val); - } - - /* PD1TGT */ - if (status >= 0) { - u8 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x3F) | - (PD1TGT[Mode] & 0x3F); - if (state->reg[MT2063_REG_PD1_TGT] != val) - status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); - } - - /* FIFATN */ - if (status >= 0) { - u8 val = ACFIFMAX[Mode]; - if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5) - val = 5; - val = (state->reg[MT2063_REG_FIF_OV] & (u8) ~0x1F) | - (val & 0x1F); - if (state->reg[MT2063_REG_FIF_OV] != val) - status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val); - } - - /* PD2TGT */ - if (status >= 0) { - u8 val = (state->reg[MT2063_REG_PD2_TGT] & (u8) ~0x3F) | - (PD2TGT[Mode] & 0x3F); - if (state->reg[MT2063_REG_PD2_TGT] != val) - status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val); - } - - /* Ignore ATN Overload */ - if (status >= 0) { - val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x80) | - (RFOVDIS[Mode] ? 0x80 : 0x00); - if (state->reg[MT2063_REG_LNA_TGT] != val) - status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); - } - - /* Ignore FIF Overload */ - if (status >= 0) { - val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x80) | - (FIFOVDIS[Mode] ? 0x80 : 0x00); - if (state->reg[MT2063_REG_PD1_TGT] != val) - status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); - } - - if (status >= 0) { - state->rcvr_mode = Mode; - dprintk(1, "mt2063 mode changed to %s\n", - mt2063_mode_name[state->rcvr_mode]); - } - - return status; -} - -/* - * MT2063_ClearPowerMaskBits () - Clears the power-down mask bits for various - * sections of the MT2063 - * - * @Bits: Mask bits to be cleared. - * - * See definition of MT2063_Mask_Bits type for description - * of each of the power bits. - */ -static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, - enum MT2063_Mask_Bits Bits) -{ - u32 status = 0; - - dprintk(2, "\n"); - Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */ - if ((Bits & 0xFF00) != 0) { - state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8); - status |= - mt2063_write(state, - MT2063_REG_PWR_2, - &state->reg[MT2063_REG_PWR_2], 1); - } - if ((Bits & 0xFF) != 0) { - state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF); - status |= - mt2063_write(state, - MT2063_REG_PWR_1, - &state->reg[MT2063_REG_PWR_1], 1); - } - - return status; -} - -/* - * MT2063_SoftwareShutdown() - Enables or disables software shutdown function. - * When Shutdown is 1, any section whose power - * mask is set will be shutdown. - */ -static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown) -{ - u32 status; - - dprintk(2, "\n"); - if (Shutdown == 1) - state->reg[MT2063_REG_PWR_1] |= 0x04; - else - state->reg[MT2063_REG_PWR_1] &= ~0x04; - - status = mt2063_write(state, - MT2063_REG_PWR_1, - &state->reg[MT2063_REG_PWR_1], 1); - - if (Shutdown != 1) { - state->reg[MT2063_REG_BYP_CTRL] = - (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40; - status |= - mt2063_write(state, - MT2063_REG_BYP_CTRL, - &state->reg[MT2063_REG_BYP_CTRL], - 1); - state->reg[MT2063_REG_BYP_CTRL] = - (state->reg[MT2063_REG_BYP_CTRL] & 0x9F); - status |= - mt2063_write(state, - MT2063_REG_BYP_CTRL, - &state->reg[MT2063_REG_BYP_CTRL], - 1); - } - - return status; -} - -static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref) -{ - return f_ref * (f_LO / f_ref) - + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step); -} - -/** - * fLO_FractionalTerm() - Calculates the portion contributed by FracN / denom. - * This function preserves maximum precision without - * risk of overflow. It accurately calculates - * f_ref * num / denom to within 1 HZ with fixed math. - * - * @num : Fractional portion of the multiplier - * @denom: denominator portion of the ratio - * @f_Ref: SRO frequency. - * - * This calculation handles f_ref as two separate 14-bit fields. - * Therefore, a maximum value of 2^28-1 may safely be used for f_ref. - * This is the genesis of the magic number "14" and the magic mask value of - * 0x03FFF. - * - * This routine successfully handles denom values up to and including 2^18. - * Returns: f_ref * num / denom - */ -static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom) -{ - u32 t1 = (f_ref >> 14) * num; - u32 term1 = t1 / denom; - u32 loss = t1 % denom; - u32 term2 = - (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom; - return (term1 << 14) + term2; -} - -/* - * CalcLO1Mult()- Calculates Integer divider value and the numerator - * value for a FracN PLL. - * - * This function assumes that the f_LO and f_Ref are - * evenly divisible by f_LO_Step. - * - * @Div: OUTPUT: Whole number portion of the multiplier - * @FracN: OUTPUT: Fractional portion of the multiplier - * @f_LO: desired LO frequency. - * @f_LO_Step: Minimum step size for the LO (in Hz). - * @f_Ref: SRO frequency. - * @f_Avoid: Range of PLL frequencies to avoid near integer multiples - * of f_Ref (in Hz). - * - * Returns: Recalculated LO frequency. - */ -static u32 MT2063_CalcLO1Mult(u32 *Div, - u32 *FracN, - u32 f_LO, - u32 f_LO_Step, u32 f_Ref) -{ - /* Calculate the whole number portion of the divider */ - *Div = f_LO / f_Ref; - - /* Calculate the numerator value (round to nearest f_LO_Step) */ - *FracN = - (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) + - (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step); - - return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64); -} - -/** - * CalcLO2Mult() - Calculates Integer divider value and the numerator - * value for a FracN PLL. - * - * This function assumes that the f_LO and f_Ref are - * evenly divisible by f_LO_Step. - * - * @Div: OUTPUT: Whole number portion of the multiplier - * @FracN: OUTPUT: Fractional portion of the multiplier - * @f_LO: desired LO frequency. - * @f_LO_Step: Minimum step size for the LO (in Hz). - * @f_Ref: SRO frequency. - * @f_Avoid: Range of PLL frequencies to avoid near - * integer multiples of f_Ref (in Hz). - * - * Returns: Recalculated LO frequency. - */ -static u32 MT2063_CalcLO2Mult(u32 *Div, - u32 *FracN, - u32 f_LO, - u32 f_LO_Step, u32 f_Ref) -{ - /* Calculate the whole number portion of the divider */ - *Div = f_LO / f_Ref; - - /* Calculate the numerator value (round to nearest f_LO_Step) */ - *FracN = - (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) + - (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step); - - return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, - 8191); -} - -/* - * FindClearTuneFilter() - Calculate the corrrect ClearTune filter to be - * used for a given input frequency. - * - * @state: ptr to tuner data structure - * @f_in: RF input center frequency (in Hz). - * - * Returns: ClearTune filter number (0-31) - */ -static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in) -{ - u32 RFBand; - u32 idx; /* index loop */ - - /* - ** Find RF Band setting - */ - RFBand = 31; /* def when f_in > all */ - for (idx = 0; idx < 31; ++idx) { - if (state->CTFiltMax[idx] >= f_in) { - RFBand = idx; - break; - } - } - return RFBand; -} - -/* - * MT2063_Tune() - Change the tuner's tuned frequency to RFin. - */ -static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in) -{ /* RF input center frequency */ - - u32 status = 0; - u32 LO1; /* 1st LO register value */ - u32 Num1; /* Numerator for LO1 reg. value */ - u32 f_IF1; /* 1st IF requested */ - u32 LO2; /* 2nd LO register value */ - u32 Num2; /* Numerator for LO2 reg. value */ - u32 ofLO1, ofLO2; /* last time's LO frequencies */ - u8 fiffc = 0x80; /* FIFF center freq from tuner */ - u32 fiffof; /* Offset from FIFF center freq */ - const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */ - u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */ - u8 val; - u32 RFBand; - - dprintk(2, "\n"); - /* Check the input and output frequency ranges */ - if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ)) - return -EINVAL; - - if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ) - || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ)) - return -EINVAL; - - /* - * Save original LO1 and LO2 register values - */ - ofLO1 = state->AS_Data.f_LO1; - ofLO2 = state->AS_Data.f_LO2; - - /* - * Find and set RF Band setting - */ - if (state->ctfilt_sw == 1) { - val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08); - if (state->reg[MT2063_REG_CTUNE_CTRL] != val) { - status |= - mt2063_setreg(state, MT2063_REG_CTUNE_CTRL, val); - } - val = state->reg[MT2063_REG_CTUNE_OV]; - RFBand = FindClearTuneFilter(state, f_in); - state->reg[MT2063_REG_CTUNE_OV] = - (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F) - | RFBand); - if (state->reg[MT2063_REG_CTUNE_OV] != val) { - status |= - mt2063_setreg(state, MT2063_REG_CTUNE_OV, val); - } - } - - /* - * Read the FIFF Center Frequency from the tuner - */ - if (status >= 0) { - status |= - mt2063_read(state, - MT2063_REG_FIFFC, - &state->reg[MT2063_REG_FIFFC], 1); - fiffc = state->reg[MT2063_REG_FIFFC]; - } - /* - * Assign in the requested values - */ - state->AS_Data.f_in = f_in; - /* Request a 1st IF such that LO1 is on a step size */ - state->AS_Data.f_if1_Request = - MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in, - state->AS_Data.f_LO1_Step, - state->AS_Data.f_ref) - f_in; - - /* - * Calculate frequency settings. f_IF1_FREQ + f_in is the - * desired LO1 frequency - */ - MT2063_ResetExclZones(&state->AS_Data); - - f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data); - - state->AS_Data.f_LO1 = - MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step, - state->AS_Data.f_ref); - - state->AS_Data.f_LO2 = - MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in, - state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); - - /* - * Check for any LO spurs in the output bandwidth and adjust - * the LO settings to avoid them if needed - */ - status |= MT2063_AvoidSpurs(&state->AS_Data); - /* - * MT_AvoidSpurs spurs may have changed the LO1 & LO2 values. - * Recalculate the LO frequencies and the values to be placed - * in the tuning registers. - */ - state->AS_Data.f_LO1 = - MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1, - state->AS_Data.f_LO1_Step, state->AS_Data.f_ref); - state->AS_Data.f_LO2 = - MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in, - state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); - state->AS_Data.f_LO2 = - MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2, - state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); - - /* - * Check the upconverter and downconverter frequency ranges - */ - if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ) - || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ)) - status |= MT2063_UPC_RANGE; - if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ) - || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ)) - status |= MT2063_DNC_RANGE; - /* LO2 Lock bit was in a different place for B0 version */ - if (state->tuner_id == MT2063_B0) - LO2LK = 0x40; - - /* - * If we have the same LO frequencies and we're already locked, - * then skip re-programming the LO registers. - */ - if ((ofLO1 != state->AS_Data.f_LO1) - || (ofLO2 != state->AS_Data.f_LO2) - || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) != - (LO1LK | LO2LK))) { - /* - * Calculate the FIFFOF register value - * - * IF1_Actual - * FIFFOF = ------------ - 8 * FIFFC - 4992 - * f_ref/64 - */ - fiffof = - (state->AS_Data.f_LO1 - - f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc - - 4992; - if (fiffof > 0xFF) - fiffof = 0xFF; - - /* - * Place all of the calculated values into the local tuner - * register fields. - */ - if (status >= 0) { - state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */ - state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */ - state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */ - |(Num2 >> 12)); /* NUM2q (hi) */ - state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */ - state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */ - - /* - * Now write out the computed register values - * IMPORTANT: There is a required order for writing - * (0x05 must follow all the others). - */ - status |= mt2063_write(state, MT2063_REG_LO1CQ_1, &state->reg[MT2063_REG_LO1CQ_1], 5); /* 0x01 - 0x05 */ - if (state->tuner_id == MT2063_B0) { - /* Re-write the one-shot bits to trigger the tune operation */ - status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */ - } - /* Write out the FIFF offset only if it's changing */ - if (state->reg[MT2063_REG_FIFF_OFFSET] != - (u8) fiffof) { - state->reg[MT2063_REG_FIFF_OFFSET] = - (u8) fiffof; - status |= - mt2063_write(state, - MT2063_REG_FIFF_OFFSET, - &state-> - reg[MT2063_REG_FIFF_OFFSET], - 1); - } - } - - /* - * Check for LO's locking - */ - - if (status < 0) - return status; - - status = mt2063_lockStatus(state); - if (status < 0) - return status; - if (!status) - return -EINVAL; /* Couldn't lock */ - - /* - * If we locked OK, assign calculated data to mt2063_state structure - */ - state->f_IF1_actual = state->AS_Data.f_LO1 - f_in; - } - - return status; -} - -static const u8 MT2063B0_defaults[] = { - /* Reg, Value */ - 0x19, 0x05, - 0x1B, 0x1D, - 0x1C, 0x1F, - 0x1D, 0x0F, - 0x1E, 0x3F, - 0x1F, 0x0F, - 0x20, 0x3F, - 0x22, 0x21, - 0x23, 0x3F, - 0x24, 0x20, - 0x25, 0x3F, - 0x27, 0xEE, - 0x2C, 0x27, /* bit at 0x20 is cleared below */ - 0x30, 0x03, - 0x2C, 0x07, /* bit at 0x20 is cleared here */ - 0x2D, 0x87, - 0x2E, 0xAA, - 0x28, 0xE1, /* Set the FIFCrst bit here */ - 0x28, 0xE0, /* Clear the FIFCrst bit here */ - 0x00 -}; - -/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ -static const u8 MT2063B1_defaults[] = { - /* Reg, Value */ - 0x05, 0xF0, - 0x11, 0x10, /* New Enable AFCsd */ - 0x19, 0x05, - 0x1A, 0x6C, - 0x1B, 0x24, - 0x1C, 0x28, - 0x1D, 0x8F, - 0x1E, 0x14, - 0x1F, 0x8F, - 0x20, 0x57, - 0x22, 0x21, /* New - ver 1.03 */ - 0x23, 0x3C, /* New - ver 1.10 */ - 0x24, 0x20, /* New - ver 1.03 */ - 0x2C, 0x24, /* bit at 0x20 is cleared below */ - 0x2D, 0x87, /* FIFFQ=0 */ - 0x2F, 0xF3, - 0x30, 0x0C, /* New - ver 1.11 */ - 0x31, 0x1B, /* New - ver 1.11 */ - 0x2C, 0x04, /* bit at 0x20 is cleared here */ - 0x28, 0xE1, /* Set the FIFCrst bit here */ - 0x28, 0xE0, /* Clear the FIFCrst bit here */ - 0x00 -}; - -/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ -static const u8 MT2063B3_defaults[] = { - /* Reg, Value */ - 0x05, 0xF0, - 0x19, 0x3D, - 0x2C, 0x24, /* bit at 0x20 is cleared below */ - 0x2C, 0x04, /* bit at 0x20 is cleared here */ - 0x28, 0xE1, /* Set the FIFCrst bit here */ - 0x28, 0xE0, /* Clear the FIFCrst bit here */ - 0x00 -}; - -static int mt2063_init(struct dvb_frontend *fe) -{ - u32 status; - struct mt2063_state *state = fe->tuner_priv; - u8 all_resets = 0xF0; /* reset/load bits */ - const u8 *def = NULL; - char *step; - u32 FCRUN; - s32 maxReads; - u32 fcu_osc; - u32 i; - - dprintk(2, "\n"); - - state->rcvr_mode = MT2063_CABLE_QAM; - - /* Read the Part/Rev code from the tuner */ - status = mt2063_read(state, MT2063_REG_PART_REV, - &state->reg[MT2063_REG_PART_REV], 1); - if (status < 0) { - printk(KERN_ERR "Can't read mt2063 part ID\n"); - return status; - } - - /* Check the part/rev code */ - switch (state->reg[MT2063_REG_PART_REV]) { - case MT2063_B0: - step = "B0"; - break; - case MT2063_B1: - step = "B1"; - break; - case MT2063_B2: - step = "B2"; - break; - case MT2063_B3: - step = "B3"; - break; - default: - printk(KERN_ERR "mt2063: Unknown mt2063 device ID (0x%02x)\n", - state->reg[MT2063_REG_PART_REV]); - return -ENODEV; /* Wrong tuner Part/Rev code */ - } - - /* Check the 2nd byte of the Part/Rev code from the tuner */ - status = mt2063_read(state, MT2063_REG_RSVD_3B, - &state->reg[MT2063_REG_RSVD_3B], 1); - - /* b7 != 0 ==> NOT MT2063 */ - if (status < 0 || ((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) { - printk(KERN_ERR "mt2063: Unknown part ID (0x%02x%02x)\n", - state->reg[MT2063_REG_PART_REV], - state->reg[MT2063_REG_RSVD_3B]); - return -ENODEV; /* Wrong tuner Part/Rev code */ - } - - printk(KERN_INFO "mt2063: detected a mt2063 %s\n", step); - - /* Reset the tuner */ - status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1); - if (status < 0) - return status; - - /* change all of the default values that vary from the HW reset values */ - /* def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */ - switch (state->reg[MT2063_REG_PART_REV]) { - case MT2063_B3: - def = MT2063B3_defaults; - break; - - case MT2063_B1: - def = MT2063B1_defaults; - break; - - case MT2063_B0: - def = MT2063B0_defaults; - break; - - default: - return -ENODEV; - break; - } - - while (status >= 0 && *def) { - u8 reg = *def++; - u8 val = *def++; - status = mt2063_write(state, reg, &val, 1); - } - if (status < 0) - return status; - - /* Wait for FIFF location to complete. */ - FCRUN = 1; - maxReads = 10; - while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) { - msleep(2); - status = mt2063_read(state, - MT2063_REG_XO_STATUS, - &state-> - reg[MT2063_REG_XO_STATUS], 1); - FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6; - } - - if (FCRUN != 0 || status < 0) - return -ENODEV; - - status = mt2063_read(state, - MT2063_REG_FIFFC, - &state->reg[MT2063_REG_FIFFC], 1); - if (status < 0) - return status; - - /* Read back all the registers from the tuner */ - status = mt2063_read(state, - MT2063_REG_PART_REV, - state->reg, MT2063_REG_END_REGS); - if (status < 0) - return status; - - /* Initialize the tuner state. */ - state->tuner_id = state->reg[MT2063_REG_PART_REV]; - state->AS_Data.f_ref = MT2063_REF_FREQ; - state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) * - ((u32) state->reg[MT2063_REG_FIFFC] + 640); - state->AS_Data.f_if1_bw = MT2063_IF1_BW; - state->AS_Data.f_out = 43750000UL; - state->AS_Data.f_out_bw = 6750000UL; - state->AS_Data.f_zif_bw = MT2063_ZIF_BW; - state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64; - state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE; - state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1; - state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2; - state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP; - state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center; - state->AS_Data.f_LO1 = 2181000000UL; - state->AS_Data.f_LO2 = 1486249786UL; - state->f_IF1_actual = state->AS_Data.f_if1_Center; - state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual; - state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID; - state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID; - state->num_regs = MT2063_REG_END_REGS; - state->AS_Data.avoidDECT = MT2063_AVOID_BOTH; - state->ctfilt_sw = 0; - - state->CTFiltMax[0] = 69230000; - state->CTFiltMax[1] = 105770000; - state->CTFiltMax[2] = 140350000; - state->CTFiltMax[3] = 177110000; - state->CTFiltMax[4] = 212860000; - state->CTFiltMax[5] = 241130000; - state->CTFiltMax[6] = 274370000; - state->CTFiltMax[7] = 309820000; - state->CTFiltMax[8] = 342450000; - state->CTFiltMax[9] = 378870000; - state->CTFiltMax[10] = 416210000; - state->CTFiltMax[11] = 456500000; - state->CTFiltMax[12] = 495790000; - state->CTFiltMax[13] = 534530000; - state->CTFiltMax[14] = 572610000; - state->CTFiltMax[15] = 598970000; - state->CTFiltMax[16] = 635910000; - state->CTFiltMax[17] = 672130000; - state->CTFiltMax[18] = 714840000; - state->CTFiltMax[19] = 739660000; - state->CTFiltMax[20] = 770410000; - state->CTFiltMax[21] = 814660000; - state->CTFiltMax[22] = 846950000; - state->CTFiltMax[23] = 867820000; - state->CTFiltMax[24] = 915980000; - state->CTFiltMax[25] = 947450000; - state->CTFiltMax[26] = 983110000; - state->CTFiltMax[27] = 1021630000; - state->CTFiltMax[28] = 1061870000; - state->CTFiltMax[29] = 1098330000; - state->CTFiltMax[30] = 1138990000; - - /* - ** Fetch the FCU osc value and use it and the fRef value to - ** scale all of the Band Max values - */ - - state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A; - status = mt2063_write(state, MT2063_REG_CTUNE_CTRL, - &state->reg[MT2063_REG_CTUNE_CTRL], 1); - if (status < 0) - return status; - - /* Read the ClearTune filter calibration value */ - status = mt2063_read(state, MT2063_REG_FIFFC, - &state->reg[MT2063_REG_FIFFC], 1); - if (status < 0) - return status; - - fcu_osc = state->reg[MT2063_REG_FIFFC]; - - state->reg[MT2063_REG_CTUNE_CTRL] = 0x00; - status = mt2063_write(state, MT2063_REG_CTUNE_CTRL, - &state->reg[MT2063_REG_CTUNE_CTRL], 1); - if (status < 0) - return status; - - /* Adjust each of the values in the ClearTune filter cross-over table */ - for (i = 0; i < 31; i++) - state->CTFiltMax[i] = (state->CTFiltMax[i] / 768) * (fcu_osc + 640); - - status = MT2063_SoftwareShutdown(state, 1); - if (status < 0) - return status; - status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD); - if (status < 0) - return status; - - state->init = true; - - return 0; -} - -static int mt2063_get_status(struct dvb_frontend *fe, u32 *tuner_status) -{ - struct mt2063_state *state = fe->tuner_priv; - int status; - - dprintk(2, "\n"); - - if (!state->init) - return -ENODEV; - - *tuner_status = 0; - status = mt2063_lockStatus(state); - if (status < 0) - return status; - if (status) - *tuner_status = TUNER_STATUS_LOCKED; - - dprintk(1, "Tuner status: %d", *tuner_status); - - return 0; -} - -static int mt2063_release(struct dvb_frontend *fe) -{ - struct mt2063_state *state = fe->tuner_priv; - - dprintk(2, "\n"); - - fe->tuner_priv = NULL; - kfree(state); - - return 0; -} - -static int mt2063_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct mt2063_state *state = fe->tuner_priv; - s32 pict_car; - s32 pict2chanb_vsb; - s32 ch_bw; - s32 if_mid; - s32 rcvr_mode; - int status; - - dprintk(2, "\n"); - - if (!state->init) { - status = mt2063_init(fe); - if (status < 0) - return status; - } - - switch (params->mode) { - case V4L2_TUNER_RADIO: - pict_car = 38900000; - ch_bw = 8000000; - pict2chanb_vsb = -(ch_bw / 2); - rcvr_mode = MT2063_OFFAIR_ANALOG; - break; - case V4L2_TUNER_ANALOG_TV: - rcvr_mode = MT2063_CABLE_ANALOG; - if (params->std & ~V4L2_STD_MN) { - pict_car = 38900000; - ch_bw = 6000000; - pict2chanb_vsb = -1250000; - } else if (params->std & V4L2_STD_PAL_G) { - pict_car = 38900000; - ch_bw = 7000000; - pict2chanb_vsb = -1250000; - } else { /* PAL/SECAM standards */ - pict_car = 38900000; - ch_bw = 8000000; - pict2chanb_vsb = -1250000; - } - break; - default: - return -EINVAL; - } - if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2)); - - state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */ - state->AS_Data.f_out = if_mid; - state->AS_Data.f_out_bw = ch_bw + 750000; - status = MT2063_SetReceiverMode(state, rcvr_mode); - if (status < 0) - return status; - - dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n", - params->frequency, ch_bw, pict2chanb_vsb); - - status = MT2063_Tune(state, (params->frequency + (pict2chanb_vsb + (ch_bw / 2)))); - if (status < 0) - return status; - - state->frequency = params->frequency; - return 0; -} - -/* - * As defined on EN 300 429, the DVB-C roll-off factor is 0.15. - * So, the amount of the needed bandwith is given by: - * Bw = Symbol_rate * (1 + 0.15) - * As such, the maximum symbol rate supported by 6 MHz is given by: - * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds - */ -#define MAX_SYMBOL_RATE_6MHz 5217391 - -static int mt2063_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct mt2063_state *state = fe->tuner_priv; - int status; - s32 pict_car; - s32 pict2chanb_vsb; - s32 ch_bw; - s32 if_mid; - s32 rcvr_mode; - - if (!state->init) { - status = mt2063_init(fe); - if (status < 0) - return status; - } - - dprintk(2, "\n"); - - if (c->bandwidth_hz == 0) - return -EINVAL; - if (c->bandwidth_hz <= 6000000) - ch_bw = 6000000; - else if (c->bandwidth_hz <= 7000000) - ch_bw = 7000000; - else - ch_bw = 8000000; - - switch (c->delivery_system) { - case SYS_DVBT: - rcvr_mode = MT2063_OFFAIR_COFDM; - pict_car = 36125000; - pict2chanb_vsb = -(ch_bw / 2); - break; - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - rcvr_mode = MT2063_CABLE_QAM; - pict_car = 36125000; - pict2chanb_vsb = -(ch_bw / 2); - break; - default: - return -EINVAL; - } - if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2)); - - state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */ - state->AS_Data.f_out = if_mid; - state->AS_Data.f_out_bw = ch_bw + 750000; - status = MT2063_SetReceiverMode(state, rcvr_mode); - if (status < 0) - return status; - - dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n", - c->frequency, ch_bw, pict2chanb_vsb); - - status = MT2063_Tune(state, (c->frequency + (pict2chanb_vsb + (ch_bw / 2)))); - - if (status < 0) - return status; - - state->frequency = c->frequency; - return 0; -} - -static int mt2063_get_if_frequency(struct dvb_frontend *fe, u32 *freq) -{ - struct mt2063_state *state = fe->tuner_priv; - - dprintk(2, "\n"); - - if (!state->init) - return -ENODEV; - - *freq = state->AS_Data.f_out; - - dprintk(1, "IF frequency: %d\n", *freq); - - return 0; -} - -static int mt2063_get_bandwidth(struct dvb_frontend *fe, u32 *bw) -{ - struct mt2063_state *state = fe->tuner_priv; - - dprintk(2, "\n"); - - if (!state->init) - return -ENODEV; - - *bw = state->AS_Data.f_out_bw - 750000; - - dprintk(1, "bandwidth: %d\n", *bw); - - return 0; -} - -static struct dvb_tuner_ops mt2063_ops = { - .info = { - .name = "MT2063 Silicon Tuner", - .frequency_min = 45000000, - .frequency_max = 865000000, - .frequency_step = 0, - }, - - .init = mt2063_init, - .sleep = MT2063_Sleep, - .get_status = mt2063_get_status, - .set_analog_params = mt2063_set_analog_params, - .set_params = mt2063_set_params, - .get_if_frequency = mt2063_get_if_frequency, - .get_bandwidth = mt2063_get_bandwidth, - .release = mt2063_release, -}; - -struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, - struct mt2063_config *config, - struct i2c_adapter *i2c) -{ - struct mt2063_state *state = NULL; - - dprintk(2, "\n"); - - state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL); - if (state == NULL) - goto error; - - state->config = config; - state->i2c = i2c; - state->frontend = fe; - state->reference = config->refclock / 1000; /* kHz */ - fe->tuner_priv = state; - fe->ops.tuner_ops = mt2063_ops; - - printk(KERN_INFO "%s: Attaching MT2063\n", __func__); - return fe; - -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL_GPL(mt2063_attach); - -/* - * Ancillary routines visible outside mt2063 - * FIXME: Remove them in favor of using standard tuner callbacks - */ -unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) -{ - struct mt2063_state *state = fe->tuner_priv; - int err = 0; - - dprintk(2, "\n"); - - err = MT2063_SoftwareShutdown(state, 1); - if (err < 0) - printk(KERN_ERR "%s: Couldn't shutdown\n", __func__); - - return err; -} -EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown); - -unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) -{ - struct mt2063_state *state = fe->tuner_priv; - int err = 0; - - dprintk(2, "\n"); - - err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD); - if (err < 0) - printk(KERN_ERR "%s: Invalid parameter\n", __func__); - - return err; -} -EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits); - -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_DESCRIPTION("MT2063 Silicon tuner"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/mt2063.h b/drivers/media/common/tuners/mt2063.h deleted file mode 100644 index 3f5cfd93713f..000000000000 --- a/drivers/media/common/tuners/mt2063.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef __MT2063_H__ -#define __MT2063_H__ - -#include "dvb_frontend.h" - -struct mt2063_config { - u8 tuner_address; - u32 refclock; -}; - -#if defined(CONFIG_MEDIA_TUNER_MT2063) || (defined(CONFIG_MEDIA_TUNER_MT2063_MODULE) && defined(MODULE)) -struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, - struct mt2063_config *config, - struct i2c_adapter *i2c); - -#else - -static inline struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, - struct mt2063_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); - return NULL; -} - -/* FIXME: Should use the standard DVB attachment interfaces */ -unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe); -unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe); - -#endif /* CONFIG_DVB_MT2063 */ - -#endif /* __MT2063_H__ */ diff --git a/drivers/media/common/tuners/mt20xx.c b/drivers/media/common/tuners/mt20xx.c deleted file mode 100644 index 0e74e97e0d1a..000000000000 --- a/drivers/media/common/tuners/mt20xx.c +++ /dev/null @@ -1,670 +0,0 @@ -/* - * i2c tv tuner chip device driver - * controls microtune tuners, mt2032 + mt2050 at the moment. - * - * This "mt20xx" module was split apart from the original "tuner" module. - */ -#include -#include -#include -#include -#include "tuner-i2c.h" -#include "mt20xx.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -/* ---------------------------------------------------------------------- */ - -static unsigned int optimize_vco = 1; -module_param(optimize_vco, int, 0644); - -static unsigned int tv_antenna = 1; -module_param(tv_antenna, int, 0644); - -static unsigned int radio_antenna; -module_param(radio_antenna, int, 0644); - -/* ---------------------------------------------------------------------- */ - -#define MT2032 0x04 -#define MT2030 0x06 -#define MT2040 0x07 -#define MT2050 0x42 - -static char *microtune_part[] = { - [ MT2030 ] = "MT2030", - [ MT2032 ] = "MT2032", - [ MT2040 ] = "MT2040", - [ MT2050 ] = "MT2050", -}; - -struct microtune_priv { - struct tuner_i2c_props i2c_props; - - unsigned int xogc; - //unsigned int radio_if2; - - u32 frequency; -}; - -static int microtune_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - - return 0; -} - -static int microtune_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct microtune_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -// IsSpurInBand()? -static int mt2032_spurcheck(struct dvb_frontend *fe, - int f1, int f2, int spectrum_from,int spectrum_to) -{ - struct microtune_priv *priv = fe->tuner_priv; - int n1=1,n2,f; - - f1=f1/1000; //scale to kHz to avoid 32bit overflows - f2=f2/1000; - spectrum_from/=1000; - spectrum_to/=1000; - - tuner_dbg("spurcheck f1=%d f2=%d from=%d to=%d\n", - f1,f2,spectrum_from,spectrum_to); - - do { - n2=-n1; - f=n1*(f1-f2); - do { - n2--; - f=f-f2; - tuner_dbg("spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f); - - if( (f>spectrum_from) && (f(f2-spectrum_to)) || (n2>-5)); - n1++; - } while (n1<5); - - return 1; -} - -static int mt2032_compute_freq(struct dvb_frontend *fe, - unsigned int rfin, - unsigned int if1, unsigned int if2, - unsigned int spectrum_from, - unsigned int spectrum_to, - unsigned char *buf, - int *ret_sel, - unsigned int xogc) //all in Hz -{ - struct microtune_priv *priv = fe->tuner_priv; - unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, - desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq; - - fref= 5250 *1000; //5.25MHz - desired_lo1=rfin+if1; - - lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000); - lo1n=lo1/8; - lo1a=lo1-(lo1n*8); - - s=rfin/1000/1000+1090; - - if(optimize_vco) { - if(s>1890) sel=0; - else if(s>1720) sel=1; - else if(s>1530) sel=2; - else if(s>1370) sel=3; - else sel=4; // >1090 - } - else { - if(s>1790) sel=0; // <1958 - else if(s>1617) sel=1; - else if(s>1449) sel=2; - else if(s>1291) sel=3; - else sel=4; // >1090 - } - *ret_sel=sel; - - lo1freq=(lo1a+8*lo1n)*fref; - - tuner_dbg("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n", - rfin,lo1,lo1n,lo1a,sel,lo1freq); - - desired_lo2=lo1freq-rfin-if2; - lo2=(desired_lo2)/fref; - lo2n=lo2/8; - lo2a=lo2-(lo2n*8); - lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith - lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000; - - tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n", - rfin,lo2,lo2n,lo2a,lo2num,lo2freq); - - if (lo1a > 7 || lo1n < 17 || lo1n > 48 || lo2a > 7 || lo2n < 17 || - lo2n > 30) { - tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n", - lo1a, lo1n, lo2a,lo2n); - return(-1); - } - - mt2032_spurcheck(fe, lo1freq, desired_lo2, spectrum_from, spectrum_to); - // should recalculate lo1 (one step up/down) - - // set up MT2032 register map for transfer over i2c - buf[0]=lo1n-1; - buf[1]=lo1a | (sel<<4); - buf[2]=0x86; // LOGC - buf[3]=0x0f; //reserved - buf[4]=0x1f; - buf[5]=(lo2n-1) | (lo2a<<5); - if(rfin >400*1000*1000) - buf[6]=0xe4; - else - buf[6]=0xf4; // set PKEN per rev 1.2 - buf[7]=8+xogc; - buf[8]=0xc3; //reserved - buf[9]=0x4e; //reserved - buf[10]=0xec; //reserved - buf[11]=(lo2num&0xff); - buf[12]=(lo2num>>8) |0x80; // Lo2RST - - return 0; -} - -static int mt2032_check_lo_lock(struct dvb_frontend *fe) -{ - struct microtune_priv *priv = fe->tuner_priv; - int try,lock=0; - unsigned char buf[2]; - - for(try=0;try<10;try++) { - buf[0]=0x0e; - tuner_i2c_xfer_send(&priv->i2c_props,buf,1); - tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); - tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]); - lock=buf[0] &0x06; - - if (lock==6) - break; - - tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]); - udelay(1000); - } - return lock; -} - -static int mt2032_optimize_vco(struct dvb_frontend *fe,int sel,int lock) -{ - struct microtune_priv *priv = fe->tuner_priv; - unsigned char buf[2]; - int tad1; - - buf[0]=0x0f; - tuner_i2c_xfer_send(&priv->i2c_props,buf,1); - tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); - tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]); - tad1=buf[0]&0x07; - - if(tad1 ==0) return lock; - if(tad1 ==1) return lock; - - if(tad1==2) { - if(sel==0) - return lock; - else sel--; - } - else { - if(sel<4) - sel++; - else - return lock; - } - - tuner_dbg("mt2032 optimize_vco: sel=%d\n",sel); - - buf[0]=0x0f; - buf[1]=sel; - tuner_i2c_xfer_send(&priv->i2c_props,buf,2); - lock=mt2032_check_lo_lock(fe); - return lock; -} - - -static void mt2032_set_if_freq(struct dvb_frontend *fe, unsigned int rfin, - unsigned int if1, unsigned int if2, - unsigned int from, unsigned int to) -{ - unsigned char buf[21]; - int lint_try,ret,sel,lock=0; - struct microtune_priv *priv = fe->tuner_priv; - - tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n", - rfin,if1,if2,from,to); - - buf[0]=0; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); - tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); - - buf[0]=0; - ret=mt2032_compute_freq(fe,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); - if (ret<0) - return; - - // send only the relevant registers per Rev. 1.2 - buf[0]=0; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,4); - buf[5]=5; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,4); - buf[11]=11; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+11,3); - if(ret!=3) - tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret); - - // wait for PLLs to lock (per manual), retry LINT if not. - for(lint_try=0; lint_try<2; lint_try++) { - lock=mt2032_check_lo_lock(fe); - - if(optimize_vco) - lock=mt2032_optimize_vco(fe,sel,lock); - if(lock==6) break; - - tuner_dbg("mt2032: re-init PLLs by LINT\n"); - buf[0]=7; - buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs - tuner_i2c_xfer_send(&priv->i2c_props,buf,2); - mdelay(10); - buf[1]=8+priv->xogc; - tuner_i2c_xfer_send(&priv->i2c_props,buf,2); - } - - if (lock!=6) - tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n"); - - buf[0]=2; - buf[1]=0x20; // LOGC for optimal phase noise - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); - if (ret!=2) - tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); -} - - -static int mt2032_set_tv_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - int if2,from,to; - - // signal bandwidth and picture carrier - if (params->std & V4L2_STD_525_60) { - // NTSC - from = 40750*1000; - to = 46750*1000; - if2 = 45750*1000; - } else { - // PAL - from = 32900*1000; - to = 39900*1000; - if2 = 38900*1000; - } - - mt2032_set_if_freq(fe, params->frequency*62500, - 1090*1000*1000, if2, from, to); - - return 0; -} - -static int mt2032_set_radio_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct microtune_priv *priv = fe->tuner_priv; - int if2; - - if (params->std & V4L2_STD_525_60) { - tuner_dbg("pinnacle ntsc\n"); - if2 = 41300 * 1000; - } else { - tuner_dbg("pinnacle pal\n"); - if2 = 33300 * 1000; - } - - // per Manual for FM tuning: first if center freq. 1085 MHz - mt2032_set_if_freq(fe, params->frequency * 125 / 2, - 1085*1000*1000,if2,if2,if2); - - return 0; -} - -static int mt2032_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct microtune_priv *priv = fe->tuner_priv; - int ret = -EINVAL; - - switch (params->mode) { - case V4L2_TUNER_RADIO: - ret = mt2032_set_radio_freq(fe, params); - priv->frequency = params->frequency * 125 / 2; - break; - case V4L2_TUNER_ANALOG_TV: - case V4L2_TUNER_DIGITAL_TV: - ret = mt2032_set_tv_freq(fe, params); - priv->frequency = params->frequency * 62500; - break; - } - - return ret; -} - -static struct dvb_tuner_ops mt2032_tuner_ops = { - .set_analog_params = mt2032_set_params, - .release = microtune_release, - .get_frequency = microtune_get_frequency, -}; - -// Initialization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 -static int mt2032_init(struct dvb_frontend *fe) -{ - struct microtune_priv *priv = fe->tuner_priv; - unsigned char buf[21]; - int ret,xogc,xok=0; - - // Initialize Registers per spec. - buf[1]=2; // Index to register 2 - buf[2]=0xff; - buf[3]=0x0f; - buf[4]=0x1f; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+1,4); - - buf[5]=6; // Index register 6 - buf[6]=0xe4; - buf[7]=0x8f; - buf[8]=0xc3; - buf[9]=0x4e; - buf[10]=0xec; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,6); - - buf[12]=13; // Index register 13 - buf[13]=0x32; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+12,2); - - // Adjust XOGC (register 7), wait for XOK - xogc=7; - do { - tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); - mdelay(10); - buf[0]=0x0e; - tuner_i2c_xfer_send(&priv->i2c_props,buf,1); - tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); - xok=buf[0]&0x01; - tuner_dbg("mt2032: xok = 0x%02x\n",xok); - if (xok == 1) break; - - xogc--; - tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); - if (xogc == 3) { - xogc=4; // min. 4 per spec - break; - } - buf[0]=0x07; - buf[1]=0x88 + xogc; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); - if (ret!=2) - tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); - } while (xok != 1 ); - priv->xogc=xogc; - - memcpy(&fe->ops.tuner_ops, &mt2032_tuner_ops, sizeof(struct dvb_tuner_ops)); - - return(1); -} - -static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna) -{ - struct microtune_priv *priv = fe->tuner_priv; - unsigned char buf[2]; - - buf[0] = 6; - buf[1] = antenna ? 0x11 : 0x10; - tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); - tuner_dbg("mt2050: enabled antenna connector %d\n", antenna); -} - -static void mt2050_set_if_freq(struct dvb_frontend *fe,unsigned int freq, unsigned int if2) -{ - struct microtune_priv *priv = fe->tuner_priv; - unsigned int if1=1218*1000*1000; - unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; - int ret; - unsigned char buf[6]; - - tuner_dbg("mt2050_set_if_freq freq=%d if1=%d if2=%d\n", - freq,if1,if2); - - f_lo1=freq+if1; - f_lo1=(f_lo1/1000000)*1000000; - - f_lo2=f_lo1-freq-if2; - f_lo2=(f_lo2/50000)*50000; - - lo1=f_lo1/4000000; - lo2=f_lo2/4000000; - - f_lo1_modulo= f_lo1-(lo1*4000000); - f_lo2_modulo= f_lo2-(lo2*4000000); - - num1=4*f_lo1_modulo/4000000; - num2=4096*(f_lo2_modulo/1000)/4000; - - // todo spurchecks - - div1a=(lo1/12)-1; - div1b=lo1-(div1a+1)*12; - - div2a=(lo2/8)-1; - div2b=lo2-(div2a+1)*8; - - if (debug > 1) { - tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2); - tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n", - num1,num2,div1a,div1b,div2a,div2b); - } - - buf[0]=1; - buf[1]= 4*div1b + num1; - if(freq<275*1000*1000) buf[1] = buf[1]|0x80; - - buf[2]=div1a; - buf[3]=32*div2b + num2/256; - buf[4]=num2-(num2/256)*256; - buf[5]=div2a; - if(num2!=0) buf[5]=buf[5]|0x40; - - if (debug > 1) { - int i; - tuner_dbg("bufs is: "); - for(i=0;i<6;i++) - printk("%x ",buf[i]); - printk("\n"); - } - - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,6); - if (ret!=6) - tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret); -} - -static int mt2050_set_tv_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - unsigned int if2; - - if (params->std & V4L2_STD_525_60) { - // NTSC - if2 = 45750*1000; - } else { - // PAL - if2 = 38900*1000; - } - if (V4L2_TUNER_DIGITAL_TV == params->mode) { - // DVB (pinnacle 300i) - if2 = 36150*1000; - } - mt2050_set_if_freq(fe, params->frequency*62500, if2); - mt2050_set_antenna(fe, tv_antenna); - - return 0; -} - -static int mt2050_set_radio_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct microtune_priv *priv = fe->tuner_priv; - int if2; - - if (params->std & V4L2_STD_525_60) { - tuner_dbg("pinnacle ntsc\n"); - if2 = 41300 * 1000; - } else { - tuner_dbg("pinnacle pal\n"); - if2 = 33300 * 1000; - } - - mt2050_set_if_freq(fe, params->frequency * 125 / 2, if2); - mt2050_set_antenna(fe, radio_antenna); - - return 0; -} - -static int mt2050_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct microtune_priv *priv = fe->tuner_priv; - int ret = -EINVAL; - - switch (params->mode) { - case V4L2_TUNER_RADIO: - ret = mt2050_set_radio_freq(fe, params); - priv->frequency = params->frequency * 125 / 2; - break; - case V4L2_TUNER_ANALOG_TV: - case V4L2_TUNER_DIGITAL_TV: - ret = mt2050_set_tv_freq(fe, params); - priv->frequency = params->frequency * 62500; - break; - } - - return ret; -} - -static struct dvb_tuner_ops mt2050_tuner_ops = { - .set_analog_params = mt2050_set_params, - .release = microtune_release, - .get_frequency = microtune_get_frequency, -}; - -static int mt2050_init(struct dvb_frontend *fe) -{ - struct microtune_priv *priv = fe->tuner_priv; - unsigned char buf[2]; - - buf[0] = 6; - buf[1] = 0x10; - tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); /* power */ - - buf[0] = 0x0f; - buf[1] = 0x0f; - tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); /* m1lo */ - - buf[0] = 0x0d; - tuner_i2c_xfer_send(&priv->i2c_props, buf, 1); - tuner_i2c_xfer_recv(&priv->i2c_props, buf, 1); - - tuner_dbg("mt2050: sro is %x\n", buf[0]); - - memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops)); - - return 0; -} - -struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr) -{ - struct microtune_priv *priv = NULL; - char *name; - unsigned char buf[21]; - int company_code; - - priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - fe->tuner_priv = priv; - - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; - priv->i2c_props.name = "mt20xx"; - - //priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ - - memset(buf,0,sizeof(buf)); - - name = "unknown"; - - tuner_i2c_xfer_send(&priv->i2c_props,buf,1); - tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); - if (debug) { - int i; - tuner_dbg("MT20xx hexdump:"); - for(i=0;i<21;i++) { - printk(" %02x",buf[i]); - if(((i+1)%8)==0) printk(" "); - } - printk("\n"); - } - company_code = buf[0x11] << 8 | buf[0x12]; - tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n", - company_code,buf[0x13],buf[0x14]); - - - if (buf[0x13] < ARRAY_SIZE(microtune_part) && - NULL != microtune_part[buf[0x13]]) - name = microtune_part[buf[0x13]]; - switch (buf[0x13]) { - case MT2032: - mt2032_init(fe); - break; - case MT2050: - mt2050_init(fe); - break; - default: - tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n", - name); - return NULL; - } - - strlcpy(fe->ops.tuner_ops.info.name, name, - sizeof(fe->ops.tuner_ops.info.name)); - tuner_info("microtune %s found, OK\n",name); - return fe; -} - -EXPORT_SYMBOL_GPL(microtune_attach); - -MODULE_DESCRIPTION("Microtune tuner driver"); -MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); -MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/common/tuners/mt20xx.h b/drivers/media/common/tuners/mt20xx.h deleted file mode 100644 index 259553a24903..000000000000 --- a/drivers/media/common/tuners/mt20xx.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - 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 __MT20XX_H__ -#define __MT20XX_H__ - -#include -#include "dvb_frontend.h" - -#if defined(CONFIG_MEDIA_TUNER_MT20XX) || (defined(CONFIG_MEDIA_TUNER_MT20XX_MODULE) && defined(MODULE)) -extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr); -#else -static inline struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* __MT20XX_H__ */ diff --git a/drivers/media/common/tuners/mt2131.c b/drivers/media/common/tuners/mt2131.c deleted file mode 100644 index f83b0c1ea6c8..000000000000 --- a/drivers/media/common/tuners/mt2131.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" - * - * Copyright (c) 2006 Steven Toth - * - * 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 -#include -#include -#include -#include - -#include "dvb_frontend.h" - -#include "mt2131.h" -#include "mt2131_priv.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -#define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_INFO "%s: " fmt, "mt2131", ## arg) - -static u8 mt2131_config1[] = { - 0x01, - 0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88, - 0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32, - 0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80, - 0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00 -}; - -static u8 mt2131_config2[] = { - 0x10, - 0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04 -}; - -static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val) -{ - struct i2c_msg msg[2] = { - { .addr = priv->cfg->i2c_address, .flags = 0, - .buf = ®, .len = 1 }, - { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, - .buf = val, .len = 1 }, - }; - - if (i2c_transfer(priv->i2c, msg, 2) != 2) { - printk(KERN_WARNING "mt2131 I2C read failed\n"); - return -EREMOTEIO; - } - return 0; -} - -static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val) -{ - u8 buf[2] = { reg, val }; - struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, - .buf = buf, .len = 2 }; - - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "mt2131 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; -} - -static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) -{ - struct i2c_msg msg = { .addr = priv->cfg->i2c_address, - .flags = 0, .buf = buf, .len = len }; - - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n", - (int)len); - return -EREMOTEIO; - } - return 0; -} - -static int mt2131_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct mt2131_priv *priv; - int ret=0, i; - u32 freq; - u8 if_band_center; - u32 f_lo1, f_lo2; - u32 div1, num1, div2, num2; - u8 b[8]; - u8 lockval = 0; - - priv = fe->tuner_priv; - - freq = c->frequency / 1000; /* Hz -> kHz */ - dprintk(1, "%s() freq=%d\n", __func__, freq); - - f_lo1 = freq + MT2131_IF1 * 1000; - f_lo1 = (f_lo1 / 250) * 250; - f_lo2 = f_lo1 - freq - MT2131_IF2; - - priv->frequency = (f_lo1 - f_lo2 - MT2131_IF2) * 1000; - - /* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */ - num1 = f_lo1 * 64 / (MT2131_FREF / 128); - div1 = num1 / 8192; - num1 &= 0x1fff; - - /* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */ - num2 = f_lo2 * 64 / (MT2131_FREF / 128); - div2 = num2 / 8192; - num2 &= 0x1fff; - - if (freq <= 82500) if_band_center = 0x00; else - if (freq <= 137500) if_band_center = 0x01; else - if (freq <= 192500) if_band_center = 0x02; else - if (freq <= 247500) if_band_center = 0x03; else - if (freq <= 302500) if_band_center = 0x04; else - if (freq <= 357500) if_band_center = 0x05; else - if (freq <= 412500) if_band_center = 0x06; else - if (freq <= 467500) if_band_center = 0x07; else - if (freq <= 522500) if_band_center = 0x08; else - if (freq <= 577500) if_band_center = 0x09; else - if (freq <= 632500) if_band_center = 0x0A; else - if (freq <= 687500) if_band_center = 0x0B; else - if (freq <= 742500) if_band_center = 0x0C; else - if (freq <= 797500) if_band_center = 0x0D; else - if (freq <= 852500) if_band_center = 0x0E; else - if (freq <= 907500) if_band_center = 0x0F; else - if (freq <= 962500) if_band_center = 0x10; else - if (freq <= 1017500) if_band_center = 0x11; else - if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13; - - b[0] = 1; - b[1] = (num1 >> 5) & 0xFF; - b[2] = (num1 & 0x1F); - b[3] = div1; - b[4] = (num2 >> 5) & 0xFF; - b[5] = num2 & 0x1F; - b[6] = div2; - - dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2); - dprintk(1, "PLL freq=%dkHz band=%d\n", (int)freq, (int)if_band_center); - dprintk(1, "PLL f_lo1=%dkHz f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2); - dprintk(1, "PLL div1=%d num1=%d div2=%d num2=%d\n", - (int)div1, (int)num1, (int)div2, (int)num2); - dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n", - (int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5], - (int)b[6]); - - ret = mt2131_writeregs(priv,b,7); - if (ret < 0) - return ret; - - mt2131_writereg(priv, 0x0b, if_band_center); - - /* Wait for lock */ - i = 0; - do { - mt2131_readreg(priv, 0x08, &lockval); - if ((lockval & 0x88) == 0x88) - break; - msleep(4); - i++; - } while (i < 10); - - return ret; -} - -static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct mt2131_priv *priv = fe->tuner_priv; - dprintk(1, "%s()\n", __func__); - *frequency = priv->frequency; - return 0; -} - -static int mt2131_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct mt2131_priv *priv = fe->tuner_priv; - u8 lock_status = 0; - u8 afc_status = 0; - - *status = 0; - - mt2131_readreg(priv, 0x08, &lock_status); - if ((lock_status & 0x88) == 0x88) - *status = TUNER_STATUS_LOCKED; - - mt2131_readreg(priv, 0x09, &afc_status); - dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n", - __func__, lock_status, afc_status); - - return 0; -} - -static int mt2131_init(struct dvb_frontend *fe) -{ - struct mt2131_priv *priv = fe->tuner_priv; - int ret; - dprintk(1, "%s()\n", __func__); - - if ((ret = mt2131_writeregs(priv, mt2131_config1, - sizeof(mt2131_config1))) < 0) - return ret; - - mt2131_writereg(priv, 0x0b, 0x09); - mt2131_writereg(priv, 0x15, 0x47); - mt2131_writereg(priv, 0x07, 0xf2); - mt2131_writereg(priv, 0x0b, 0x01); - - if ((ret = mt2131_writeregs(priv, mt2131_config2, - sizeof(mt2131_config2))) < 0) - return ret; - - return ret; -} - -static int mt2131_release(struct dvb_frontend *fe) -{ - dprintk(1, "%s()\n", __func__); - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static const struct dvb_tuner_ops mt2131_tuner_ops = { - .info = { - .name = "Microtune MT2131", - .frequency_min = 48000000, - .frequency_max = 860000000, - .frequency_step = 50000, - }, - - .release = mt2131_release, - .init = mt2131_init, - - .set_params = mt2131_set_params, - .get_frequency = mt2131_get_frequency, - .get_status = mt2131_get_status -}; - -struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct mt2131_config *cfg, u16 if1) -{ - struct mt2131_priv *priv = NULL; - u8 id = 0; - - dprintk(1, "%s()\n", __func__); - - priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->cfg = cfg; - priv->i2c = i2c; - - if (mt2131_readreg(priv, 0, &id) != 0) { - kfree(priv); - return NULL; - } - if ( (id != 0x3E) && (id != 0x3F) ) { - printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n", - cfg->i2c_address); - kfree(priv); - return NULL; - } - - printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n", - cfg->i2c_address); - memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = priv; - return fe; -} -EXPORT_SYMBOL(mt2131_attach); - -MODULE_AUTHOR("Steven Toth"); -MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver"); -MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/common/tuners/mt2131.h b/drivers/media/common/tuners/mt2131.h deleted file mode 100644 index 6632de640df0..000000000000 --- a/drivers/media/common/tuners/mt2131.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" - * - * Copyright (c) 2006 Steven Toth - * - * 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 __MT2131_H__ -#define __MT2131_H__ - -struct dvb_frontend; -struct i2c_adapter; - -struct mt2131_config { - u8 i2c_address; - u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ -}; - -#if defined(CONFIG_MEDIA_TUNER_MT2131) || (defined(CONFIG_MEDIA_TUNER_MT2131_MODULE) && defined(MODULE)) -extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct mt2131_config *cfg, - u16 if1); -#else -static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct mt2131_config *cfg, - u16 if1) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_MEDIA_TUNER_MT2131 */ - -#endif /* __MT2131_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/common/tuners/mt2131_priv.h b/drivers/media/common/tuners/mt2131_priv.h deleted file mode 100644 index 62aeedf5c550..000000000000 --- a/drivers/media/common/tuners/mt2131_priv.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" - * - * Copyright (c) 2006 Steven Toth - * - * 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 __MT2131_PRIV_H__ -#define __MT2131_PRIV_H__ - -/* Regs */ -#define MT2131_PWR 0x07 -#define MT2131_UPC_1 0x0b -#define MT2131_AGC_RL 0x10 -#define MT2131_MISC_2 0x15 - -/* frequency values in KHz */ -#define MT2131_IF1 1220 -#define MT2131_IF2 44000 -#define MT2131_FREF 16000 - -struct mt2131_priv { - struct mt2131_config *cfg; - struct i2c_adapter *i2c; - - u32 frequency; -}; - -#endif /* __MT2131_PRIV_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/common/tuners/mt2266.c b/drivers/media/common/tuners/mt2266.c deleted file mode 100644 index bca4d75e42d4..000000000000 --- a/drivers/media/common/tuners/mt2266.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" - * - * Copyright (c) 2007 Olivier DANET - * - * 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. - */ - -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "mt2266.h" - -#define I2C_ADDRESS 0x60 - -#define REG_PART_REV 0 -#define REG_TUNE 1 -#define REG_BAND 6 -#define REG_BANDWIDTH 8 -#define REG_LOCK 0x12 - -#define PART_REV 0x85 - -struct mt2266_priv { - struct mt2266_config *cfg; - struct i2c_adapter *i2c; - - u32 frequency; - u32 bandwidth; - u8 band; -}; - -#define MT2266_VHF 1 -#define MT2266_UHF 0 - -/* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0) - -// Reads a single register -static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val) -{ - struct i2c_msg msg[2] = { - { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, - { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, - }; - if (i2c_transfer(priv->i2c, msg, 2) != 2) { - printk(KERN_WARNING "MT2266 I2C read failed\n"); - return -EREMOTEIO; - } - return 0; -} - -// Writes a single register -static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val) -{ - u8 buf[2] = { reg, val }; - struct i2c_msg msg = { - .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 - }; - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "MT2266 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; -} - -// Writes a set of consecutive registers -static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len) -{ - struct i2c_msg msg = { - .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len - }; - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len); - return -EREMOTEIO; - } - return 0; -} - -// Initialisation sequences -static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28, - 0x00, 0x52, 0x99, 0x3f }; - -static u8 mt2266_init2[] = { - 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4, - 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, - 0xff, 0x00, 0x77, 0x0f, 0x2d -}; - -static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22 }; - -static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32 }; - -static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7 }; - -static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64, - 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 }; - -static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5, - 0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f }; - -#define FREF 30000 // Quartz oscillator 30 MHz - -static int mt2266_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct mt2266_priv *priv; - int ret=0; - u32 freq; - u32 tune; - u8 lnaband; - u8 b[10]; - int i; - u8 band; - - priv = fe->tuner_priv; - - freq = priv->frequency / 1000; /* Hz -> kHz */ - if (freq < 470000 && freq > 230000) - return -EINVAL; /* Gap between VHF and UHF bands */ - - priv->frequency = c->frequency; - tune = 2 * freq * (8192/16) / (FREF/16); - band = (freq < 300000) ? MT2266_VHF : MT2266_UHF; - if (band == MT2266_VHF) - tune *= 2; - - switch (c->bandwidth_hz) { - case 6000000: - mt2266_writeregs(priv, mt2266_init_6mhz, - sizeof(mt2266_init_6mhz)); - break; - case 8000000: - mt2266_writeregs(priv, mt2266_init_8mhz, - sizeof(mt2266_init_8mhz)); - break; - case 7000000: - default: - mt2266_writeregs(priv, mt2266_init_7mhz, - sizeof(mt2266_init_7mhz)); - break; - } - priv->bandwidth = c->bandwidth_hz; - - if (band == MT2266_VHF && priv->band == MT2266_UHF) { - dprintk("Switch from UHF to VHF"); - mt2266_writereg(priv, 0x05, 0x04); - mt2266_writereg(priv, 0x19, 0x61); - mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf)); - } else if (band == MT2266_UHF && priv->band == MT2266_VHF) { - dprintk("Switch from VHF to UHF"); - mt2266_writereg(priv, 0x05, 0x52); - mt2266_writereg(priv, 0x19, 0x61); - mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf)); - } - msleep(10); - - if (freq <= 495000) - lnaband = 0xEE; - else if (freq <= 525000) - lnaband = 0xDD; - else if (freq <= 550000) - lnaband = 0xCC; - else if (freq <= 580000) - lnaband = 0xBB; - else if (freq <= 605000) - lnaband = 0xAA; - else if (freq <= 630000) - lnaband = 0x99; - else if (freq <= 655000) - lnaband = 0x88; - else if (freq <= 685000) - lnaband = 0x77; - else if (freq <= 710000) - lnaband = 0x66; - else if (freq <= 735000) - lnaband = 0x55; - else if (freq <= 765000) - lnaband = 0x44; - else if (freq <= 802000) - lnaband = 0x33; - else if (freq <= 840000) - lnaband = 0x22; - else - lnaband = 0x11; - - b[0] = REG_TUNE; - b[1] = (tune >> 8) & 0x1F; - b[2] = tune & 0xFF; - b[3] = tune >> 13; - mt2266_writeregs(priv,b,4); - - dprintk("set_parms: tune=%d band=%d %s", - (int) tune, (int) lnaband, - (band == MT2266_UHF) ? "UHF" : "VHF"); - dprintk("set_parms: [1..3]: %2x %2x %2x", - (int) b[1], (int) b[2], (int)b[3]); - - if (band == MT2266_UHF) { - b[0] = 0x05; - b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62; - b[2] = lnaband; - mt2266_writeregs(priv, b, 3); - } - - /* Wait for pll lock or timeout */ - i = 0; - do { - mt2266_readreg(priv,REG_LOCK,b); - if (b[0] & 0x40) - break; - msleep(10); - i++; - } while (i<10); - dprintk("Lock when i=%i",(int)i); - - if (band == MT2266_UHF && priv->band == MT2266_VHF) - mt2266_writereg(priv, 0x05, 0x62); - - priv->band = band; - - return ret; -} - -static void mt2266_calibrate(struct mt2266_priv *priv) -{ - mt2266_writereg(priv, 0x11, 0x03); - mt2266_writereg(priv, 0x11, 0x01); - mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1)); - mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2)); - mt2266_writereg(priv, 0x33, 0x5e); - mt2266_writereg(priv, 0x10, 0x10); - mt2266_writereg(priv, 0x10, 0x00); - mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz)); - msleep(25); - mt2266_writereg(priv, 0x17, 0x6d); - mt2266_writereg(priv, 0x1c, 0x00); - msleep(75); - mt2266_writereg(priv, 0x17, 0x6d); - mt2266_writereg(priv, 0x1c, 0xff); -} - -static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct mt2266_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct mt2266_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; - return 0; -} - -static int mt2266_init(struct dvb_frontend *fe) -{ - int ret; - struct mt2266_priv *priv = fe->tuner_priv; - ret = mt2266_writereg(priv, 0x17, 0x6d); - if (ret < 0) - return ret; - ret = mt2266_writereg(priv, 0x1c, 0xff); - if (ret < 0) - return ret; - return 0; -} - -static int mt2266_sleep(struct dvb_frontend *fe) -{ - struct mt2266_priv *priv = fe->tuner_priv; - mt2266_writereg(priv, 0x17, 0x6d); - mt2266_writereg(priv, 0x1c, 0x00); - return 0; -} - -static int mt2266_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static const struct dvb_tuner_ops mt2266_tuner_ops = { - .info = { - .name = "Microtune MT2266", - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_step = 50000, - }, - .release = mt2266_release, - .init = mt2266_init, - .sleep = mt2266_sleep, - .set_params = mt2266_set_params, - .get_frequency = mt2266_get_frequency, - .get_bandwidth = mt2266_get_bandwidth -}; - -struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) -{ - struct mt2266_priv *priv = NULL; - u8 id = 0; - - priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->cfg = cfg; - priv->i2c = i2c; - priv->band = MT2266_UHF; - - if (mt2266_readreg(priv, 0, &id)) { - kfree(priv); - return NULL; - } - if (id != PART_REV) { - kfree(priv); - return NULL; - } - printk(KERN_INFO "MT2266: successfully identified\n"); - memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = priv; - mt2266_calibrate(priv); - return fe; -} -EXPORT_SYMBOL(mt2266_attach); - -MODULE_AUTHOR("Olivier DANET"); -MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/mt2266.h b/drivers/media/common/tuners/mt2266.h deleted file mode 100644 index 4d083882d044..000000000000 --- a/drivers/media/common/tuners/mt2266.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" - * - * Copyright (c) 2007 Olivier DANET - * - * 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. - */ - -#ifndef MT2266_H -#define MT2266_H - -struct dvb_frontend; -struct i2c_adapter; - -struct mt2266_config { - u8 i2c_address; -}; - -#if defined(CONFIG_MEDIA_TUNER_MT2266) || (defined(CONFIG_MEDIA_TUNER_MT2266_MODULE) && defined(MODULE)) -extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg); -#else -static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_MEDIA_TUNER_MT2266 - -#endif diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c deleted file mode 100644 index 6133315fb0e3..000000000000 --- a/drivers/media/common/tuners/mxl5005s.c +++ /dev/null @@ -1,4109 +0,0 @@ -/* - MaxLinear MXL5005S VSB/QAM/DVBT tuner driver - - Copyright (C) 2008 MaxLinear - Copyright (C) 2006 Steven Toth - Functions: - mxl5005s_reset() - mxl5005s_writereg() - mxl5005s_writeregs() - mxl5005s_init() - mxl5005s_reconfigure() - mxl5005s_AssignTunerMode() - mxl5005s_set_params() - mxl5005s_get_frequency() - mxl5005s_get_bandwidth() - mxl5005s_release() - mxl5005s_attach() - - Copyright (C) 2008 Realtek - Copyright (C) 2008 Jan Hoogenraad - Functions: - mxl5005s_SetRfFreqHz() - - 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. - -*/ - -/* - History of this driver (Steven Toth): - I was given a public release of a linux driver that included - support for the MaxLinear MXL5005S silicon tuner. Analysis of - the tuner driver showed clearly three things. - - 1. The tuner driver didn't support the LinuxTV tuner API - so the code Realtek added had to be removed. - - 2. A significant amount of the driver is reference driver code - from MaxLinear, I felt it was important to identify and - preserve this. - - 3. New code has to be added to interface correctly with the - LinuxTV API, as a regular kernel module. - - Other than the reference driver enum's, I've clearly marked - sections of the code and retained the copyright of the - respective owners. -*/ -#include -#include -#include -#include -#include -#include -#include "dvb_frontend.h" -#include "mxl5005s.h" - -static int debug; - -#define dprintk(level, arg...) do { \ - if (level <= debug) \ - printk(arg); \ - } while (0) - -#define TUNER_REGS_NUM 104 -#define INITCTRL_NUM 40 - -#ifdef _MXL_PRODUCTION -#define CHCTRL_NUM 39 -#else -#define CHCTRL_NUM 36 -#endif - -#define MXLCTRL_NUM 189 -#define MASTER_CONTROL_ADDR 9 - -/* Enumeration of Master Control Register State */ -enum master_control_state { - MC_LOAD_START = 1, - MC_POWER_DOWN, - MC_SYNTH_RESET, - MC_SEQ_OFF -}; - -/* Enumeration of MXL5005 Tuner Modulation Type */ -enum { - MXL_DEFAULT_MODULATION = 0, - MXL_DVBT, - MXL_ATSC, - MXL_QAM, - MXL_ANALOG_CABLE, - MXL_ANALOG_OTA -}; - -/* MXL5005 Tuner Register Struct */ -struct TunerReg { - u16 Reg_Num; /* Tuner Register Address */ - u16 Reg_Val; /* Current sw programmed value waiting to be written */ -}; - -enum { - /* Initialization Control Names */ - DN_IQTN_AMP_CUT = 1, /* 1 */ - BB_MODE, /* 2 */ - BB_BUF, /* 3 */ - BB_BUF_OA, /* 4 */ - BB_ALPF_BANDSELECT, /* 5 */ - BB_IQSWAP, /* 6 */ - BB_DLPF_BANDSEL, /* 7 */ - RFSYN_CHP_GAIN, /* 8 */ - RFSYN_EN_CHP_HIGAIN, /* 9 */ - AGC_IF, /* 10 */ - AGC_RF, /* 11 */ - IF_DIVVAL, /* 12 */ - IF_VCO_BIAS, /* 13 */ - CHCAL_INT_MOD_IF, /* 14 */ - CHCAL_FRAC_MOD_IF, /* 15 */ - DRV_RES_SEL, /* 16 */ - I_DRIVER, /* 17 */ - EN_AAF, /* 18 */ - EN_3P, /* 19 */ - EN_AUX_3P, /* 20 */ - SEL_AAF_BAND, /* 21 */ - SEQ_ENCLK16_CLK_OUT, /* 22 */ - SEQ_SEL4_16B, /* 23 */ - XTAL_CAPSELECT, /* 24 */ - IF_SEL_DBL, /* 25 */ - RFSYN_R_DIV, /* 26 */ - SEQ_EXTSYNTHCALIF, /* 27 */ - SEQ_EXTDCCAL, /* 28 */ - AGC_EN_RSSI, /* 29 */ - RFA_ENCLKRFAGC, /* 30 */ - RFA_RSSI_REFH, /* 31 */ - RFA_RSSI_REF, /* 32 */ - RFA_RSSI_REFL, /* 33 */ - RFA_FLR, /* 34 */ - RFA_CEIL, /* 35 */ - SEQ_EXTIQFSMPULSE, /* 36 */ - OVERRIDE_1, /* 37 */ - BB_INITSTATE_DLPF_TUNE, /* 38 */ - TG_R_DIV, /* 39 */ - EN_CHP_LIN_B, /* 40 */ - - /* Channel Change Control Names */ - DN_POLY = 51, /* 51 */ - DN_RFGAIN, /* 52 */ - DN_CAP_RFLPF, /* 53 */ - DN_EN_VHFUHFBAR, /* 54 */ - DN_GAIN_ADJUST, /* 55 */ - DN_IQTNBUF_AMP, /* 56 */ - DN_IQTNGNBFBIAS_BST, /* 57 */ - RFSYN_EN_OUTMUX, /* 58 */ - RFSYN_SEL_VCO_OUT, /* 59 */ - RFSYN_SEL_VCO_HI, /* 60 */ - RFSYN_SEL_DIVM, /* 61 */ - RFSYN_RF_DIV_BIAS, /* 62 */ - DN_SEL_FREQ, /* 63 */ - RFSYN_VCO_BIAS, /* 64 */ - CHCAL_INT_MOD_RF, /* 65 */ - CHCAL_FRAC_MOD_RF, /* 66 */ - RFSYN_LPF_R, /* 67 */ - CHCAL_EN_INT_RF, /* 68 */ - TG_LO_DIVVAL, /* 69 */ - TG_LO_SELVAL, /* 70 */ - TG_DIV_VAL, /* 71 */ - TG_VCO_BIAS, /* 72 */ - SEQ_EXTPOWERUP, /* 73 */ - OVERRIDE_2, /* 74 */ - OVERRIDE_3, /* 75 */ - OVERRIDE_4, /* 76 */ - SEQ_FSM_PULSE, /* 77 */ - GPIO_4B, /* 78 */ - GPIO_3B, /* 79 */ - GPIO_4, /* 80 */ - GPIO_3, /* 81 */ - GPIO_1B, /* 82 */ - DAC_A_ENABLE, /* 83 */ - DAC_B_ENABLE, /* 84 */ - DAC_DIN_A, /* 85 */ - DAC_DIN_B, /* 86 */ -#ifdef _MXL_PRODUCTION - RFSYN_EN_DIV, /* 87 */ - RFSYN_DIVM, /* 88 */ - DN_BYPASS_AGC_I2C /* 89 */ -#endif -}; - -/* - * The following context is source code provided by MaxLinear. - * MaxLinear source code - Common_MXL.h (?) - */ - -/* Constants */ -#define MXL5005S_REG_WRITING_TABLE_LEN_MAX 104 -#define MXL5005S_LATCH_BYTE 0xfe - -/* Register address, MSB, and LSB */ -#define MXL5005S_BB_IQSWAP_ADDR 59 -#define MXL5005S_BB_IQSWAP_MSB 0 -#define MXL5005S_BB_IQSWAP_LSB 0 - -#define MXL5005S_BB_DLPF_BANDSEL_ADDR 53 -#define MXL5005S_BB_DLPF_BANDSEL_MSB 4 -#define MXL5005S_BB_DLPF_BANDSEL_LSB 3 - -/* Standard modes */ -enum { - MXL5005S_STANDARD_DVBT, - MXL5005S_STANDARD_ATSC, -}; -#define MXL5005S_STANDARD_MODE_NUM 2 - -/* Bandwidth modes */ -enum { - MXL5005S_BANDWIDTH_6MHZ = 6000000, - MXL5005S_BANDWIDTH_7MHZ = 7000000, - MXL5005S_BANDWIDTH_8MHZ = 8000000, -}; -#define MXL5005S_BANDWIDTH_MODE_NUM 3 - -/* MXL5005 Tuner Control Struct */ -struct TunerControl { - u16 Ctrl_Num; /* Control Number */ - u16 size; /* Number of bits to represent Value */ - u16 addr[25]; /* Array of Tuner Register Address for each bit pos */ - u16 bit[25]; /* Array of bit pos in Reg Addr for each bit pos */ - u16 val[25]; /* Binary representation of Value */ -}; - -/* MXL5005 Tuner Struct */ -struct mxl5005s_state { - u8 Mode; /* 0: Analog Mode ; 1: Digital Mode */ - u8 IF_Mode; /* for Analog Mode, 0: zero IF; 1: low IF */ - u32 Chan_Bandwidth; /* filter channel bandwidth (6, 7, 8) */ - u32 IF_OUT; /* Desired IF Out Frequency */ - u16 IF_OUT_LOAD; /* IF Out Load Resistor (200/300 Ohms) */ - u32 RF_IN; /* RF Input Frequency */ - u32 Fxtal; /* XTAL Frequency */ - u8 AGC_Mode; /* AGC Mode 0: Dual AGC; 1: Single AGC */ - u16 TOP; /* Value: take over point */ - u8 CLOCK_OUT; /* 0: turn off clk out; 1: turn on clock out */ - u8 DIV_OUT; /* 4MHz or 16MHz */ - u8 CAPSELECT; /* 0: disable On-Chip pulling cap; 1: enable */ - u8 EN_RSSI; /* 0: disable RSSI; 1: enable RSSI */ - - /* Modulation Type; */ - /* 0 - Default; 1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */ - u8 Mod_Type; - - /* Tracking Filter Type */ - /* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */ - u8 TF_Type; - - /* Calculated Settings */ - u32 RF_LO; /* Synth RF LO Frequency */ - u32 IF_LO; /* Synth IF LO Frequency */ - u32 TG_LO; /* Synth TG_LO Frequency */ - - /* Pointers to ControlName Arrays */ - u16 Init_Ctrl_Num; /* Number of INIT Control Names */ - struct TunerControl - Init_Ctrl[INITCTRL_NUM]; /* INIT Control Names Array Pointer */ - - u16 CH_Ctrl_Num; /* Number of CH Control Names */ - struct TunerControl - CH_Ctrl[CHCTRL_NUM]; /* CH Control Name Array Pointer */ - - u16 MXL_Ctrl_Num; /* Number of MXL Control Names */ - struct TunerControl - MXL_Ctrl[MXLCTRL_NUM]; /* MXL Control Name Array Pointer */ - - /* Pointer to Tuner Register Array */ - u16 TunerRegs_Num; /* Number of Tuner Registers */ - struct TunerReg - TunerRegs[TUNER_REGS_NUM]; /* Tuner Register Array Pointer */ - - /* Linux driver framework specific */ - struct mxl5005s_config *config; - struct dvb_frontend *frontend; - struct i2c_adapter *i2c; - - /* Cache values */ - u32 current_mode; - -}; - -static u16 MXL_GetMasterControl(u8 *MasterReg, int state); -static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value); -static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value); -static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit, - u8 bitVal); -static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, - u8 *RegVal, int *count); -static u32 MXL_Ceiling(u32 value, u32 resolution); -static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal); -static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, - u32 value, u16 controlGroup); -static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val); -static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum, - u8 *RegVal, int *count); -static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq); -static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe); -static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe); -static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum, - u8 *RegVal, int *count); -static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable, - u8 *datatable, u8 len); -static u16 MXL_IFSynthInit(struct dvb_frontend *fe); -static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type, - u32 bandwidth); -static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type, - u32 bandwidth); - -/* ---------------------------------------------------------------- - * Begin: Custom code salvaged from the Realtek driver. - * Copyright (C) 2008 Realtek - * Copyright (C) 2008 Jan Hoogenraad - * This code is placed under the terms of the GNU General Public License - * - * Released by Realtek under GPLv2. - * Thanks to Realtek for a lot of support we received ! - * - * Revision: 080314 - original version - */ - -static int mxl5005s_SetRfFreqHz(struct dvb_frontend *fe, unsigned long RfFreqHz) -{ - struct mxl5005s_state *state = fe->tuner_priv; - unsigned char AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; - unsigned char ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; - int TableLen; - - u32 IfDivval = 0; - unsigned char MasterControlByte; - - dprintk(1, "%s() freq=%ld\n", __func__, RfFreqHz); - - /* Set MxL5005S tuner RF frequency according to example code. */ - - /* Tuner RF frequency setting stage 0 */ - MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET); - AddrTable[0] = MASTER_CONTROL_ADDR; - ByteTable[0] |= state->config->AgcMasterByte; - - mxl5005s_writeregs(fe, AddrTable, ByteTable, 1); - - /* Tuner RF frequency setting stage 1 */ - MXL_TuneRF(fe, RfFreqHz); - - MXL_ControlRead(fe, IF_DIVVAL, &IfDivval); - - MXL_ControlWrite(fe, SEQ_FSM_PULSE, 0); - MXL_ControlWrite(fe, SEQ_EXTPOWERUP, 1); - MXL_ControlWrite(fe, IF_DIVVAL, 8); - MXL_GetCHRegister(fe, AddrTable, ByteTable, &TableLen); - - MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START); - AddrTable[TableLen] = MASTER_CONTROL_ADDR ; - ByteTable[TableLen] = MasterControlByte | - state->config->AgcMasterByte; - TableLen += 1; - - mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); - - /* Wait 30 ms. */ - msleep(150); - - /* Tuner RF frequency setting stage 2 */ - MXL_ControlWrite(fe, SEQ_FSM_PULSE, 1); - MXL_ControlWrite(fe, IF_DIVVAL, IfDivval); - MXL_GetCHRegister_ZeroIF(fe, AddrTable, ByteTable, &TableLen); - - MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START); - AddrTable[TableLen] = MASTER_CONTROL_ADDR ; - ByteTable[TableLen] = MasterControlByte | - state->config->AgcMasterByte ; - TableLen += 1; - - mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); - - msleep(100); - - return 0; -} -/* End: Custom code taken from the Realtek driver */ - -/* ---------------------------------------------------------------- - * Begin: Reference driver code found in the Realtek driver. - * Copyright (C) 2008 MaxLinear - */ -static u16 MXL5005_RegisterInit(struct dvb_frontend *fe) -{ - struct mxl5005s_state *state = fe->tuner_priv; - state->TunerRegs_Num = TUNER_REGS_NUM ; - - state->TunerRegs[0].Reg_Num = 9 ; - state->TunerRegs[0].Reg_Val = 0x40 ; - - state->TunerRegs[1].Reg_Num = 11 ; - state->TunerRegs[1].Reg_Val = 0x19 ; - - state->TunerRegs[2].Reg_Num = 12 ; - state->TunerRegs[2].Reg_Val = 0x60 ; - - state->TunerRegs[3].Reg_Num = 13 ; - state->TunerRegs[3].Reg_Val = 0x00 ; - - state->TunerRegs[4].Reg_Num = 14 ; - state->TunerRegs[4].Reg_Val = 0x00 ; - - state->TunerRegs[5].Reg_Num = 15 ; - state->TunerRegs[5].Reg_Val = 0xC0 ; - - state->TunerRegs[6].Reg_Num = 16 ; - state->TunerRegs[6].Reg_Val = 0x00 ; - - state->TunerRegs[7].Reg_Num = 17 ; - state->TunerRegs[7].Reg_Val = 0x00 ; - - state->TunerRegs[8].Reg_Num = 18 ; - state->TunerRegs[8].Reg_Val = 0x00 ; - - state->TunerRegs[9].Reg_Num = 19 ; - state->TunerRegs[9].Reg_Val = 0x34 ; - - state->TunerRegs[10].Reg_Num = 21 ; - state->TunerRegs[10].Reg_Val = 0x00 ; - - state->TunerRegs[11].Reg_Num = 22 ; - state->TunerRegs[11].Reg_Val = 0x6B ; - - state->TunerRegs[12].Reg_Num = 23 ; - state->TunerRegs[12].Reg_Val = 0x35 ; - - state->TunerRegs[13].Reg_Num = 24 ; - state->TunerRegs[13].Reg_Val = 0x70 ; - - state->TunerRegs[14].Reg_Num = 25 ; - state->TunerRegs[14].Reg_Val = 0x3E ; - - state->TunerRegs[15].Reg_Num = 26 ; - state->TunerRegs[15].Reg_Val = 0x82 ; - - state->TunerRegs[16].Reg_Num = 31 ; - state->TunerRegs[16].Reg_Val = 0x00 ; - - state->TunerRegs[17].Reg_Num = 32 ; - state->TunerRegs[17].Reg_Val = 0x40 ; - - state->TunerRegs[18].Reg_Num = 33 ; - state->TunerRegs[18].Reg_Val = 0x53 ; - - state->TunerRegs[19].Reg_Num = 34 ; - state->TunerRegs[19].Reg_Val = 0x81 ; - - state->TunerRegs[20].Reg_Num = 35 ; - state->TunerRegs[20].Reg_Val = 0xC9 ; - - state->TunerRegs[21].Reg_Num = 36 ; - state->TunerRegs[21].Reg_Val = 0x01 ; - - state->TunerRegs[22].Reg_Num = 37 ; - state->TunerRegs[22].Reg_Val = 0x00 ; - - state->TunerRegs[23].Reg_Num = 41 ; - state->TunerRegs[23].Reg_Val = 0x00 ; - - state->TunerRegs[24].Reg_Num = 42 ; - state->TunerRegs[24].Reg_Val = 0xF8 ; - - state->TunerRegs[25].Reg_Num = 43 ; - state->TunerRegs[25].Reg_Val = 0x43 ; - - state->TunerRegs[26].Reg_Num = 44 ; - state->TunerRegs[26].Reg_Val = 0x20 ; - - state->TunerRegs[27].Reg_Num = 45 ; - state->TunerRegs[27].Reg_Val = 0x80 ; - - state->TunerRegs[28].Reg_Num = 46 ; - state->TunerRegs[28].Reg_Val = 0x88 ; - - state->TunerRegs[29].Reg_Num = 47 ; - state->TunerRegs[29].Reg_Val = 0x86 ; - - state->TunerRegs[30].Reg_Num = 48 ; - state->TunerRegs[30].Reg_Val = 0x00 ; - - state->TunerRegs[31].Reg_Num = 49 ; - state->TunerRegs[31].Reg_Val = 0x00 ; - - state->TunerRegs[32].Reg_Num = 53 ; - state->TunerRegs[32].Reg_Val = 0x94 ; - - state->TunerRegs[33].Reg_Num = 54 ; - state->TunerRegs[33].Reg_Val = 0xFA ; - - state->TunerRegs[34].Reg_Num = 55 ; - state->TunerRegs[34].Reg_Val = 0x92 ; - - state->TunerRegs[35].Reg_Num = 56 ; - state->TunerRegs[35].Reg_Val = 0x80 ; - - state->TunerRegs[36].Reg_Num = 57 ; - state->TunerRegs[36].Reg_Val = 0x41 ; - - state->TunerRegs[37].Reg_Num = 58 ; - state->TunerRegs[37].Reg_Val = 0xDB ; - - state->TunerRegs[38].Reg_Num = 59 ; - state->TunerRegs[38].Reg_Val = 0x00 ; - - state->TunerRegs[39].Reg_Num = 60 ; - state->TunerRegs[39].Reg_Val = 0x00 ; - - state->TunerRegs[40].Reg_Num = 61 ; - state->TunerRegs[40].Reg_Val = 0x00 ; - - state->TunerRegs[41].Reg_Num = 62 ; - state->TunerRegs[41].Reg_Val = 0x00 ; - - state->TunerRegs[42].Reg_Num = 65 ; - state->TunerRegs[42].Reg_Val = 0xF8 ; - - state->TunerRegs[43].Reg_Num = 66 ; - state->TunerRegs[43].Reg_Val = 0xE4 ; - - state->TunerRegs[44].Reg_Num = 67 ; - state->TunerRegs[44].Reg_Val = 0x90 ; - - state->TunerRegs[45].Reg_Num = 68 ; - state->TunerRegs[45].Reg_Val = 0xC0 ; - - state->TunerRegs[46].Reg_Num = 69 ; - state->TunerRegs[46].Reg_Val = 0x01 ; - - state->TunerRegs[47].Reg_Num = 70 ; - state->TunerRegs[47].Reg_Val = 0x50 ; - - state->TunerRegs[48].Reg_Num = 71 ; - state->TunerRegs[48].Reg_Val = 0x06 ; - - state->TunerRegs[49].Reg_Num = 72 ; - state->TunerRegs[49].Reg_Val = 0x00 ; - - state->TunerRegs[50].Reg_Num = 73 ; - state->TunerRegs[50].Reg_Val = 0x20 ; - - state->TunerRegs[51].Reg_Num = 76 ; - state->TunerRegs[51].Reg_Val = 0xBB ; - - state->TunerRegs[52].Reg_Num = 77 ; - state->TunerRegs[52].Reg_Val = 0x13 ; - - state->TunerRegs[53].Reg_Num = 81 ; - state->TunerRegs[53].Reg_Val = 0x04 ; - - state->TunerRegs[54].Reg_Num = 82 ; - state->TunerRegs[54].Reg_Val = 0x75 ; - - state->TunerRegs[55].Reg_Num = 83 ; - state->TunerRegs[55].Reg_Val = 0x00 ; - - state->TunerRegs[56].Reg_Num = 84 ; - state->TunerRegs[56].Reg_Val = 0x00 ; - - state->TunerRegs[57].Reg_Num = 85 ; - state->TunerRegs[57].Reg_Val = 0x00 ; - - state->TunerRegs[58].Reg_Num = 91 ; - state->TunerRegs[58].Reg_Val = 0x70 ; - - state->TunerRegs[59].Reg_Num = 92 ; - state->TunerRegs[59].Reg_Val = 0x00 ; - - state->TunerRegs[60].Reg_Num = 93 ; - state->TunerRegs[60].Reg_Val = 0x00 ; - - state->TunerRegs[61].Reg_Num = 94 ; - state->TunerRegs[61].Reg_Val = 0x00 ; - - state->TunerRegs[62].Reg_Num = 95 ; - state->TunerRegs[62].Reg_Val = 0x0C ; - - state->TunerRegs[63].Reg_Num = 96 ; - state->TunerRegs[63].Reg_Val = 0x00 ; - - state->TunerRegs[64].Reg_Num = 97 ; - state->TunerRegs[64].Reg_Val = 0x00 ; - - state->TunerRegs[65].Reg_Num = 98 ; - state->TunerRegs[65].Reg_Val = 0xE2 ; - - state->TunerRegs[66].Reg_Num = 99 ; - state->TunerRegs[66].Reg_Val = 0x00 ; - - state->TunerRegs[67].Reg_Num = 100 ; - state->TunerRegs[67].Reg_Val = 0x00 ; - - state->TunerRegs[68].Reg_Num = 101 ; - state->TunerRegs[68].Reg_Val = 0x12 ; - - state->TunerRegs[69].Reg_Num = 102 ; - state->TunerRegs[69].Reg_Val = 0x80 ; - - state->TunerRegs[70].Reg_Num = 103 ; - state->TunerRegs[70].Reg_Val = 0x32 ; - - state->TunerRegs[71].Reg_Num = 104 ; - state->TunerRegs[71].Reg_Val = 0xB4 ; - - state->TunerRegs[72].Reg_Num = 105 ; - state->TunerRegs[72].Reg_Val = 0x60 ; - - state->TunerRegs[73].Reg_Num = 106 ; - state->TunerRegs[73].Reg_Val = 0x83 ; - - state->TunerRegs[74].Reg_Num = 107 ; - state->TunerRegs[74].Reg_Val = 0x84 ; - - state->TunerRegs[75].Reg_Num = 108 ; - state->TunerRegs[75].Reg_Val = 0x9C ; - - state->TunerRegs[76].Reg_Num = 109 ; - state->TunerRegs[76].Reg_Val = 0x02 ; - - state->TunerRegs[77].Reg_Num = 110 ; - state->TunerRegs[77].Reg_Val = 0x81 ; - - state->TunerRegs[78].Reg_Num = 111 ; - state->TunerRegs[78].Reg_Val = 0xC0 ; - - state->TunerRegs[79].Reg_Num = 112 ; - state->TunerRegs[79].Reg_Val = 0x10 ; - - state->TunerRegs[80].Reg_Num = 131 ; - state->TunerRegs[80].Reg_Val = 0x8A ; - - state->TunerRegs[81].Reg_Num = 132 ; - state->TunerRegs[81].Reg_Val = 0x10 ; - - state->TunerRegs[82].Reg_Num = 133 ; - state->TunerRegs[82].Reg_Val = 0x24 ; - - state->TunerRegs[83].Reg_Num = 134 ; - state->TunerRegs[83].Reg_Val = 0x00 ; - - state->TunerRegs[84].Reg_Num = 135 ; - state->TunerRegs[84].Reg_Val = 0x00 ; - - state->TunerRegs[85].Reg_Num = 136 ; - state->TunerRegs[85].Reg_Val = 0x7E ; - - state->TunerRegs[86].Reg_Num = 137 ; - state->TunerRegs[86].Reg_Val = 0x40 ; - - state->TunerRegs[87].Reg_Num = 138 ; - state->TunerRegs[87].Reg_Val = 0x38 ; - - state->TunerRegs[88].Reg_Num = 146 ; - state->TunerRegs[88].Reg_Val = 0xF6 ; - - state->TunerRegs[89].Reg_Num = 147 ; - state->TunerRegs[89].Reg_Val = 0x1A ; - - state->TunerRegs[90].Reg_Num = 148 ; - state->TunerRegs[90].Reg_Val = 0x62 ; - - state->TunerRegs[91].Reg_Num = 149 ; - state->TunerRegs[91].Reg_Val = 0x33 ; - - state->TunerRegs[92].Reg_Num = 150 ; - state->TunerRegs[92].Reg_Val = 0x80 ; - - state->TunerRegs[93].Reg_Num = 156 ; - state->TunerRegs[93].Reg_Val = 0x56 ; - - state->TunerRegs[94].Reg_Num = 157 ; - state->TunerRegs[94].Reg_Val = 0x17 ; - - state->TunerRegs[95].Reg_Num = 158 ; - state->TunerRegs[95].Reg_Val = 0xA9 ; - - state->TunerRegs[96].Reg_Num = 159 ; - state->TunerRegs[96].Reg_Val = 0x00 ; - - state->TunerRegs[97].Reg_Num = 160 ; - state->TunerRegs[97].Reg_Val = 0x00 ; - - state->TunerRegs[98].Reg_Num = 161 ; - state->TunerRegs[98].Reg_Val = 0x00 ; - - state->TunerRegs[99].Reg_Num = 162 ; - state->TunerRegs[99].Reg_Val = 0x40 ; - - state->TunerRegs[100].Reg_Num = 166 ; - state->TunerRegs[100].Reg_Val = 0xAE ; - - state->TunerRegs[101].Reg_Num = 167 ; - state->TunerRegs[101].Reg_Val = 0x1B ; - - state->TunerRegs[102].Reg_Num = 168 ; - state->TunerRegs[102].Reg_Val = 0xF2 ; - - state->TunerRegs[103].Reg_Num = 195 ; - state->TunerRegs[103].Reg_Val = 0x00 ; - - return 0 ; -} - -static u16 MXL5005_ControlInit(struct dvb_frontend *fe) -{ - struct mxl5005s_state *state = fe->tuner_priv; - state->Init_Ctrl_Num = INITCTRL_NUM; - - state->Init_Ctrl[0].Ctrl_Num = DN_IQTN_AMP_CUT ; - state->Init_Ctrl[0].size = 1 ; - state->Init_Ctrl[0].addr[0] = 73; - state->Init_Ctrl[0].bit[0] = 7; - state->Init_Ctrl[0].val[0] = 0; - - state->Init_Ctrl[1].Ctrl_Num = BB_MODE ; - state->Init_Ctrl[1].size = 1 ; - state->Init_Ctrl[1].addr[0] = 53; - state->Init_Ctrl[1].bit[0] = 2; - state->Init_Ctrl[1].val[0] = 1; - - state->Init_Ctrl[2].Ctrl_Num = BB_BUF ; - state->Init_Ctrl[2].size = 2 ; - state->Init_Ctrl[2].addr[0] = 53; - state->Init_Ctrl[2].bit[0] = 1; - state->Init_Ctrl[2].val[0] = 0; - state->Init_Ctrl[2].addr[1] = 57; - state->Init_Ctrl[2].bit[1] = 0; - state->Init_Ctrl[2].val[1] = 1; - - state->Init_Ctrl[3].Ctrl_Num = BB_BUF_OA ; - state->Init_Ctrl[3].size = 1 ; - state->Init_Ctrl[3].addr[0] = 53; - state->Init_Ctrl[3].bit[0] = 0; - state->Init_Ctrl[3].val[0] = 0; - - state->Init_Ctrl[4].Ctrl_Num = BB_ALPF_BANDSELECT ; - state->Init_Ctrl[4].size = 3 ; - state->Init_Ctrl[4].addr[0] = 53; - state->Init_Ctrl[4].bit[0] = 5; - state->Init_Ctrl[4].val[0] = 0; - state->Init_Ctrl[4].addr[1] = 53; - state->Init_Ctrl[4].bit[1] = 6; - state->Init_Ctrl[4].val[1] = 0; - state->Init_Ctrl[4].addr[2] = 53; - state->Init_Ctrl[4].bit[2] = 7; - state->Init_Ctrl[4].val[2] = 1; - - state->Init_Ctrl[5].Ctrl_Num = BB_IQSWAP ; - state->Init_Ctrl[5].size = 1 ; - state->Init_Ctrl[5].addr[0] = 59; - state->Init_Ctrl[5].bit[0] = 0; - state->Init_Ctrl[5].val[0] = 0; - - state->Init_Ctrl[6].Ctrl_Num = BB_DLPF_BANDSEL ; - state->Init_Ctrl[6].size = 2 ; - state->Init_Ctrl[6].addr[0] = 53; - state->Init_Ctrl[6].bit[0] = 3; - state->Init_Ctrl[6].val[0] = 0; - state->Init_Ctrl[6].addr[1] = 53; - state->Init_Ctrl[6].bit[1] = 4; - state->Init_Ctrl[6].val[1] = 1; - - state->Init_Ctrl[7].Ctrl_Num = RFSYN_CHP_GAIN ; - state->Init_Ctrl[7].size = 4 ; - state->Init_Ctrl[7].addr[0] = 22; - state->Init_Ctrl[7].bit[0] = 4; - state->Init_Ctrl[7].val[0] = 0; - state->Init_Ctrl[7].addr[1] = 22; - state->Init_Ctrl[7].bit[1] = 5; - state->Init_Ctrl[7].val[1] = 1; - state->Init_Ctrl[7].addr[2] = 22; - state->Init_Ctrl[7].bit[2] = 6; - state->Init_Ctrl[7].val[2] = 1; - state->Init_Ctrl[7].addr[3] = 22; - state->Init_Ctrl[7].bit[3] = 7; - state->Init_Ctrl[7].val[3] = 0; - - state->Init_Ctrl[8].Ctrl_Num = RFSYN_EN_CHP_HIGAIN ; - state->Init_Ctrl[8].size = 1 ; - state->Init_Ctrl[8].addr[0] = 22; - state->Init_Ctrl[8].bit[0] = 2; - state->Init_Ctrl[8].val[0] = 0; - - state->Init_Ctrl[9].Ctrl_Num = AGC_IF ; - state->Init_Ctrl[9].size = 4 ; - state->Init_Ctrl[9].addr[0] = 76; - state->Init_Ctrl[9].bit[0] = 0; - state->Init_Ctrl[9].val[0] = 1; - state->Init_Ctrl[9].addr[1] = 76; - state->Init_Ctrl[9].bit[1] = 1; - state->Init_Ctrl[9].val[1] = 1; - state->Init_Ctrl[9].addr[2] = 76; - state->Init_Ctrl[9].bit[2] = 2; - state->Init_Ctrl[9].val[2] = 0; - state->Init_Ctrl[9].addr[3] = 76; - state->Init_Ctrl[9].bit[3] = 3; - state->Init_Ctrl[9].val[3] = 1; - - state->Init_Ctrl[10].Ctrl_Num = AGC_RF ; - state->Init_Ctrl[10].size = 4 ; - state->Init_Ctrl[10].addr[0] = 76; - state->Init_Ctrl[10].bit[0] = 4; - state->Init_Ctrl[10].val[0] = 1; - state->Init_Ctrl[10].addr[1] = 76; - state->Init_Ctrl[10].bit[1] = 5; - state->Init_Ctrl[10].val[1] = 1; - state->Init_Ctrl[10].addr[2] = 76; - state->Init_Ctrl[10].bit[2] = 6; - state->Init_Ctrl[10].val[2] = 0; - state->Init_Ctrl[10].addr[3] = 76; - state->Init_Ctrl[10].bit[3] = 7; - state->Init_Ctrl[10].val[3] = 1; - - state->Init_Ctrl[11].Ctrl_Num = IF_DIVVAL ; - state->Init_Ctrl[11].size = 5 ; - state->Init_Ctrl[11].addr[0] = 43; - state->Init_Ctrl[11].bit[0] = 3; - state->Init_Ctrl[11].val[0] = 0; - state->Init_Ctrl[11].addr[1] = 43; - state->Init_Ctrl[11].bit[1] = 4; - state->Init_Ctrl[11].val[1] = 0; - state->Init_Ctrl[11].addr[2] = 43; - state->Init_Ctrl[11].bit[2] = 5; - state->Init_Ctrl[11].val[2] = 0; - state->Init_Ctrl[11].addr[3] = 43; - state->Init_Ctrl[11].bit[3] = 6; - state->Init_Ctrl[11].val[3] = 1; - state->Init_Ctrl[11].addr[4] = 43; - state->Init_Ctrl[11].bit[4] = 7; - state->Init_Ctrl[11].val[4] = 0; - - state->Init_Ctrl[12].Ctrl_Num = IF_VCO_BIAS ; - state->Init_Ctrl[12].size = 6 ; - state->Init_Ctrl[12].addr[0] = 44; - state->Init_Ctrl[12].bit[0] = 2; - state->Init_Ctrl[12].val[0] = 0; - state->Init_Ctrl[12].addr[1] = 44; - state->Init_Ctrl[12].bit[1] = 3; - state->Init_Ctrl[12].val[1] = 0; - state->Init_Ctrl[12].addr[2] = 44; - state->Init_Ctrl[12].bit[2] = 4; - state->Init_Ctrl[12].val[2] = 0; - state->Init_Ctrl[12].addr[3] = 44; - state->Init_Ctrl[12].bit[3] = 5; - state->Init_Ctrl[12].val[3] = 1; - state->Init_Ctrl[12].addr[4] = 44; - state->Init_Ctrl[12].bit[4] = 6; - state->Init_Ctrl[12].val[4] = 0; - state->Init_Ctrl[12].addr[5] = 44; - state->Init_Ctrl[12].bit[5] = 7; - state->Init_Ctrl[12].val[5] = 0; - - state->Init_Ctrl[13].Ctrl_Num = CHCAL_INT_MOD_IF ; - state->Init_Ctrl[13].size = 7 ; - state->Init_Ctrl[13].addr[0] = 11; - state->Init_Ctrl[13].bit[0] = 0; - state->Init_Ctrl[13].val[0] = 1; - state->Init_Ctrl[13].addr[1] = 11; - state->Init_Ctrl[13].bit[1] = 1; - state->Init_Ctrl[13].val[1] = 0; - state->Init_Ctrl[13].addr[2] = 11; - state->Init_Ctrl[13].bit[2] = 2; - state->Init_Ctrl[13].val[2] = 0; - state->Init_Ctrl[13].addr[3] = 11; - state->Init_Ctrl[13].bit[3] = 3; - state->Init_Ctrl[13].val[3] = 1; - state->Init_Ctrl[13].addr[4] = 11; - state->Init_Ctrl[13].bit[4] = 4; - state->Init_Ctrl[13].val[4] = 1; - state->Init_Ctrl[13].addr[5] = 11; - state->Init_Ctrl[13].bit[5] = 5; - state->Init_Ctrl[13].val[5] = 0; - state->Init_Ctrl[13].addr[6] = 11; - state->Init_Ctrl[13].bit[6] = 6; - state->Init_Ctrl[13].val[6] = 0; - - state->Init_Ctrl[14].Ctrl_Num = CHCAL_FRAC_MOD_IF ; - state->Init_Ctrl[14].size = 16 ; - state->Init_Ctrl[14].addr[0] = 13; - state->Init_Ctrl[14].bit[0] = 0; - state->Init_Ctrl[14].val[0] = 0; - state->Init_Ctrl[14].addr[1] = 13; - state->Init_Ctrl[14].bit[1] = 1; - state->Init_Ctrl[14].val[1] = 0; - state->Init_Ctrl[14].addr[2] = 13; - state->Init_Ctrl[14].bit[2] = 2; - state->Init_Ctrl[14].val[2] = 0; - state->Init_Ctrl[14].addr[3] = 13; - state->Init_Ctrl[14].bit[3] = 3; - state->Init_Ctrl[14].val[3] = 0; - state->Init_Ctrl[14].addr[4] = 13; - state->Init_Ctrl[14].bit[4] = 4; - state->Init_Ctrl[14].val[4] = 0; - state->Init_Ctrl[14].addr[5] = 13; - state->Init_Ctrl[14].bit[5] = 5; - state->Init_Ctrl[14].val[5] = 0; - state->Init_Ctrl[14].addr[6] = 13; - state->Init_Ctrl[14].bit[6] = 6; - state->Init_Ctrl[14].val[6] = 0; - state->Init_Ctrl[14].addr[7] = 13; - state->Init_Ctrl[14].bit[7] = 7; - state->Init_Ctrl[14].val[7] = 0; - state->Init_Ctrl[14].addr[8] = 12; - state->Init_Ctrl[14].bit[8] = 0; - state->Init_Ctrl[14].val[8] = 0; - state->Init_Ctrl[14].addr[9] = 12; - state->Init_Ctrl[14].bit[9] = 1; - state->Init_Ctrl[14].val[9] = 0; - state->Init_Ctrl[14].addr[10] = 12; - state->Init_Ctrl[14].bit[10] = 2; - state->Init_Ctrl[14].val[10] = 0; - state->Init_Ctrl[14].addr[11] = 12; - state->Init_Ctrl[14].bit[11] = 3; - state->Init_Ctrl[14].val[11] = 0; - state->Init_Ctrl[14].addr[12] = 12; - state->Init_Ctrl[14].bit[12] = 4; - state->Init_Ctrl[14].val[12] = 0; - state->Init_Ctrl[14].addr[13] = 12; - state->Init_Ctrl[14].bit[13] = 5; - state->Init_Ctrl[14].val[13] = 1; - state->Init_Ctrl[14].addr[14] = 12; - state->Init_Ctrl[14].bit[14] = 6; - state->Init_Ctrl[14].val[14] = 1; - state->Init_Ctrl[14].addr[15] = 12; - state->Init_Ctrl[14].bit[15] = 7; - state->Init_Ctrl[14].val[15] = 0; - - state->Init_Ctrl[15].Ctrl_Num = DRV_RES_SEL ; - state->Init_Ctrl[15].size = 3 ; - state->Init_Ctrl[15].addr[0] = 147; - state->Init_Ctrl[15].bit[0] = 2; - state->Init_Ctrl[15].val[0] = 0; - state->Init_Ctrl[15].addr[1] = 147; - state->Init_Ctrl[15].bit[1] = 3; - state->Init_Ctrl[15].val[1] = 1; - state->Init_Ctrl[15].addr[2] = 147; - state->Init_Ctrl[15].bit[2] = 4; - state->Init_Ctrl[15].val[2] = 1; - - state->Init_Ctrl[16].Ctrl_Num = I_DRIVER ; - state->Init_Ctrl[16].size = 2 ; - state->Init_Ctrl[16].addr[0] = 147; - state->Init_Ctrl[16].bit[0] = 0; - state->Init_Ctrl[16].val[0] = 0; - state->Init_Ctrl[16].addr[1] = 147; - state->Init_Ctrl[16].bit[1] = 1; - state->Init_Ctrl[16].val[1] = 1; - - state->Init_Ctrl[17].Ctrl_Num = EN_AAF ; - state->Init_Ctrl[17].size = 1 ; - state->Init_Ctrl[17].addr[0] = 147; - state->Init_Ctrl[17].bit[0] = 7; - state->Init_Ctrl[17].val[0] = 0; - - state->Init_Ctrl[18].Ctrl_Num = EN_3P ; - state->Init_Ctrl[18].size = 1 ; - state->Init_Ctrl[18].addr[0] = 147; - state->Init_Ctrl[18].bit[0] = 6; - state->Init_Ctrl[18].val[0] = 0; - - state->Init_Ctrl[19].Ctrl_Num = EN_AUX_3P ; - state->Init_Ctrl[19].size = 1 ; - state->Init_Ctrl[19].addr[0] = 156; - state->Init_Ctrl[19].bit[0] = 0; - state->Init_Ctrl[19].val[0] = 0; - - state->Init_Ctrl[20].Ctrl_Num = SEL_AAF_BAND ; - state->Init_Ctrl[20].size = 1 ; - state->Init_Ctrl[20].addr[0] = 147; - state->Init_Ctrl[20].bit[0] = 5; - state->Init_Ctrl[20].val[0] = 0; - - state->Init_Ctrl[21].Ctrl_Num = SEQ_ENCLK16_CLK_OUT ; - state->Init_Ctrl[21].size = 1 ; - state->Init_Ctrl[21].addr[0] = 137; - state->Init_Ctrl[21].bit[0] = 4; - state->Init_Ctrl[21].val[0] = 0; - - state->Init_Ctrl[22].Ctrl_Num = SEQ_SEL4_16B ; - state->Init_Ctrl[22].size = 1 ; - state->Init_Ctrl[22].addr[0] = 137; - state->Init_Ctrl[22].bit[0] = 7; - state->Init_Ctrl[22].val[0] = 0; - - state->Init_Ctrl[23].Ctrl_Num = XTAL_CAPSELECT ; - state->Init_Ctrl[23].size = 1 ; - state->Init_Ctrl[23].addr[0] = 91; - state->Init_Ctrl[23].bit[0] = 5; - state->Init_Ctrl[23].val[0] = 1; - - state->Init_Ctrl[24].Ctrl_Num = IF_SEL_DBL ; - state->Init_Ctrl[24].size = 1 ; - state->Init_Ctrl[24].addr[0] = 43; - state->Init_Ctrl[24].bit[0] = 0; - state->Init_Ctrl[24].val[0] = 1; - - state->Init_Ctrl[25].Ctrl_Num = RFSYN_R_DIV ; - state->Init_Ctrl[25].size = 2 ; - state->Init_Ctrl[25].addr[0] = 22; - state->Init_Ctrl[25].bit[0] = 0; - state->Init_Ctrl[25].val[0] = 1; - state->Init_Ctrl[25].addr[1] = 22; - state->Init_Ctrl[25].bit[1] = 1; - state->Init_Ctrl[25].val[1] = 1; - - state->Init_Ctrl[26].Ctrl_Num = SEQ_EXTSYNTHCALIF ; - state->Init_Ctrl[26].size = 1 ; - state->Init_Ctrl[26].addr[0] = 134; - state->Init_Ctrl[26].bit[0] = 2; - state->Init_Ctrl[26].val[0] = 0; - - state->Init_Ctrl[27].Ctrl_Num = SEQ_EXTDCCAL ; - state->Init_Ctrl[27].size = 1 ; - state->Init_Ctrl[27].addr[0] = 137; - state->Init_Ctrl[27].bit[0] = 3; - state->Init_Ctrl[27].val[0] = 0; - - state->Init_Ctrl[28].Ctrl_Num = AGC_EN_RSSI ; - state->Init_Ctrl[28].size = 1 ; - state->Init_Ctrl[28].addr[0] = 77; - state->Init_Ctrl[28].bit[0] = 7; - state->Init_Ctrl[28].val[0] = 0; - - state->Init_Ctrl[29].Ctrl_Num = RFA_ENCLKRFAGC ; - state->Init_Ctrl[29].size = 1 ; - state->Init_Ctrl[29].addr[0] = 166; - state->Init_Ctrl[29].bit[0] = 7; - state->Init_Ctrl[29].val[0] = 1; - - state->Init_Ctrl[30].Ctrl_Num = RFA_RSSI_REFH ; - state->Init_Ctrl[30].size = 3 ; - state->Init_Ctrl[30].addr[0] = 166; - state->Init_Ctrl[30].bit[0] = 0; - state->Init_Ctrl[30].val[0] = 0; - state->Init_Ctrl[30].addr[1] = 166; - state->Init_Ctrl[30].bit[1] = 1; - state->Init_Ctrl[30].val[1] = 1; - state->Init_Ctrl[30].addr[2] = 166; - state->Init_Ctrl[30].bit[2] = 2; - state->Init_Ctrl[30].val[2] = 1; - - state->Init_Ctrl[31].Ctrl_Num = RFA_RSSI_REF ; - state->Init_Ctrl[31].size = 3 ; - state->Init_Ctrl[31].addr[0] = 166; - state->Init_Ctrl[31].bit[0] = 3; - state->Init_Ctrl[31].val[0] = 1; - state->Init_Ctrl[31].addr[1] = 166; - state->Init_Ctrl[31].bit[1] = 4; - state->Init_Ctrl[31].val[1] = 0; - state->Init_Ctrl[31].addr[2] = 166; - state->Init_Ctrl[31].bit[2] = 5; - state->Init_Ctrl[31].val[2] = 1; - - state->Init_Ctrl[32].Ctrl_Num = RFA_RSSI_REFL ; - state->Init_Ctrl[32].size = 3 ; - state->Init_Ctrl[32].addr[0] = 167; - state->Init_Ctrl[32].bit[0] = 0; - state->Init_Ctrl[32].val[0] = 1; - state->Init_Ctrl[32].addr[1] = 167; - state->Init_Ctrl[32].bit[1] = 1; - state->Init_Ctrl[32].val[1] = 1; - state->Init_Ctrl[32].addr[2] = 167; - state->Init_Ctrl[32].bit[2] = 2; - state->Init_Ctrl[32].val[2] = 0; - - state->Init_Ctrl[33].Ctrl_Num = RFA_FLR ; - state->Init_Ctrl[33].size = 4 ; - state->Init_Ctrl[33].addr[0] = 168; - state->Init_Ctrl[33].bit[0] = 0; - state->Init_Ctrl[33].val[0] = 0; - state->Init_Ctrl[33].addr[1] = 168; - state->Init_Ctrl[33].bit[1] = 1; - state->Init_Ctrl[33].val[1] = 1; - state->Init_Ctrl[33].addr[2] = 168; - state->Init_Ctrl[33].bit[2] = 2; - state->Init_Ctrl[33].val[2] = 0; - state->Init_Ctrl[33].addr[3] = 168; - state->Init_Ctrl[33].bit[3] = 3; - state->Init_Ctrl[33].val[3] = 0; - - state->Init_Ctrl[34].Ctrl_Num = RFA_CEIL ; - state->Init_Ctrl[34].size = 4 ; - state->Init_Ctrl[34].addr[0] = 168; - state->Init_Ctrl[34].bit[0] = 4; - state->Init_Ctrl[34].val[0] = 1; - state->Init_Ctrl[34].addr[1] = 168; - state->Init_Ctrl[34].bit[1] = 5; - state->Init_Ctrl[34].val[1] = 1; - state->Init_Ctrl[34].addr[2] = 168; - state->Init_Ctrl[34].bit[2] = 6; - state->Init_Ctrl[34].val[2] = 1; - state->Init_Ctrl[34].addr[3] = 168; - state->Init_Ctrl[34].bit[3] = 7; - state->Init_Ctrl[34].val[3] = 1; - - state->Init_Ctrl[35].Ctrl_Num = SEQ_EXTIQFSMPULSE ; - state->Init_Ctrl[35].size = 1 ; - state->Init_Ctrl[35].addr[0] = 135; - state->Init_Ctrl[35].bit[0] = 0; - state->Init_Ctrl[35].val[0] = 0; - - state->Init_Ctrl[36].Ctrl_Num = OVERRIDE_1 ; - state->Init_Ctrl[36].size = 1 ; - state->Init_Ctrl[36].addr[0] = 56; - state->Init_Ctrl[36].bit[0] = 3; - state->Init_Ctrl[36].val[0] = 0; - - state->Init_Ctrl[37].Ctrl_Num = BB_INITSTATE_DLPF_TUNE ; - state->Init_Ctrl[37].size = 7 ; - state->Init_Ctrl[37].addr[0] = 59; - state->Init_Ctrl[37].bit[0] = 1; - state->Init_Ctrl[37].val[0] = 0; - state->Init_Ctrl[37].addr[1] = 59; - state->Init_Ctrl[37].bit[1] = 2; - state->Init_Ctrl[37].val[1] = 0; - state->Init_Ctrl[37].addr[2] = 59; - state->Init_Ctrl[37].bit[2] = 3; - state->Init_Ctrl[37].val[2] = 0; - state->Init_Ctrl[37].addr[3] = 59; - state->Init_Ctrl[37].bit[3] = 4; - state->Init_Ctrl[37].val[3] = 0; - state->Init_Ctrl[37].addr[4] = 59; - state->Init_Ctrl[37].bit[4] = 5; - state->Init_Ctrl[37].val[4] = 0; - state->Init_Ctrl[37].addr[5] = 59; - state->Init_Ctrl[37].bit[5] = 6; - state->Init_Ctrl[37].val[5] = 0; - state->Init_Ctrl[37].addr[6] = 59; - state->Init_Ctrl[37].bit[6] = 7; - state->Init_Ctrl[37].val[6] = 0; - - state->Init_Ctrl[38].Ctrl_Num = TG_R_DIV ; - state->Init_Ctrl[38].size = 6 ; - state->Init_Ctrl[38].addr[0] = 32; - state->Init_Ctrl[38].bit[0] = 2; - state->Init_Ctrl[38].val[0] = 0; - state->Init_Ctrl[38].addr[1] = 32; - state->Init_Ctrl[38].bit[1] = 3; - state->Init_Ctrl[38].val[1] = 0; - state->Init_Ctrl[38].addr[2] = 32; - state->Init_Ctrl[38].bit[2] = 4; - state->Init_Ctrl[38].val[2] = 0; - state->Init_Ctrl[38].addr[3] = 32; - state->Init_Ctrl[38].bit[3] = 5; - state->Init_Ctrl[38].val[3] = 0; - state->Init_Ctrl[38].addr[4] = 32; - state->Init_Ctrl[38].bit[4] = 6; - state->Init_Ctrl[38].val[4] = 1; - state->Init_Ctrl[38].addr[5] = 32; - state->Init_Ctrl[38].bit[5] = 7; - state->Init_Ctrl[38].val[5] = 0; - - state->Init_Ctrl[39].Ctrl_Num = EN_CHP_LIN_B ; - state->Init_Ctrl[39].size = 1 ; - state->Init_Ctrl[39].addr[0] = 25; - state->Init_Ctrl[39].bit[0] = 3; - state->Init_Ctrl[39].val[0] = 1; - - - state->CH_Ctrl_Num = CHCTRL_NUM ; - - state->CH_Ctrl[0].Ctrl_Num = DN_POLY ; - state->CH_Ctrl[0].size = 2 ; - state->CH_Ctrl[0].addr[0] = 68; - state->CH_Ctrl[0].bit[0] = 6; - state->CH_Ctrl[0].val[0] = 1; - state->CH_Ctrl[0].addr[1] = 68; - state->CH_Ctrl[0].bit[1] = 7; - state->CH_Ctrl[0].val[1] = 1; - - state->CH_Ctrl[1].Ctrl_Num = DN_RFGAIN ; - state->CH_Ctrl[1].size = 2 ; - state->CH_Ctrl[1].addr[0] = 70; - state->CH_Ctrl[1].bit[0] = 6; - state->CH_Ctrl[1].val[0] = 1; - state->CH_Ctrl[1].addr[1] = 70; - state->CH_Ctrl[1].bit[1] = 7; - state->CH_Ctrl[1].val[1] = 0; - - state->CH_Ctrl[2].Ctrl_Num = DN_CAP_RFLPF ; - state->CH_Ctrl[2].size = 9 ; - state->CH_Ctrl[2].addr[0] = 69; - state->CH_Ctrl[2].bit[0] = 5; - state->CH_Ctrl[2].val[0] = 0; - state->CH_Ctrl[2].addr[1] = 69; - state->CH_Ctrl[2].bit[1] = 6; - state->CH_Ctrl[2].val[1] = 0; - state->CH_Ctrl[2].addr[2] = 69; - state->CH_Ctrl[2].bit[2] = 7; - state->CH_Ctrl[2].val[2] = 0; - state->CH_Ctrl[2].addr[3] = 68; - state->CH_Ctrl[2].bit[3] = 0; - state->CH_Ctrl[2].val[3] = 0; - state->CH_Ctrl[2].addr[4] = 68; - state->CH_Ctrl[2].bit[4] = 1; - state->CH_Ctrl[2].val[4] = 0; - state->CH_Ctrl[2].addr[5] = 68; - state->CH_Ctrl[2].bit[5] = 2; - state->CH_Ctrl[2].val[5] = 0; - state->CH_Ctrl[2].addr[6] = 68; - state->CH_Ctrl[2].bit[6] = 3; - state->CH_Ctrl[2].val[6] = 0; - state->CH_Ctrl[2].addr[7] = 68; - state->CH_Ctrl[2].bit[7] = 4; - state->CH_Ctrl[2].val[7] = 0; - state->CH_Ctrl[2].addr[8] = 68; - state->CH_Ctrl[2].bit[8] = 5; - state->CH_Ctrl[2].val[8] = 0; - - state->CH_Ctrl[3].Ctrl_Num = DN_EN_VHFUHFBAR ; - state->CH_Ctrl[3].size = 1 ; - state->CH_Ctrl[3].addr[0] = 70; - state->CH_Ctrl[3].bit[0] = 5; - state->CH_Ctrl[3].val[0] = 0; - - state->CH_Ctrl[4].Ctrl_Num = DN_GAIN_ADJUST ; - state->CH_Ctrl[4].size = 3 ; - state->CH_Ctrl[4].addr[0] = 73; - state->CH_Ctrl[4].bit[0] = 4; - state->CH_Ctrl[4].val[0] = 0; - state->CH_Ctrl[4].addr[1] = 73; - state->CH_Ctrl[4].bit[1] = 5; - state->CH_Ctrl[4].val[1] = 1; - state->CH_Ctrl[4].addr[2] = 73; - state->CH_Ctrl[4].bit[2] = 6; - state->CH_Ctrl[4].val[2] = 0; - - state->CH_Ctrl[5].Ctrl_Num = DN_IQTNBUF_AMP ; - state->CH_Ctrl[5].size = 4 ; - state->CH_Ctrl[5].addr[0] = 70; - state->CH_Ctrl[5].bit[0] = 0; - state->CH_Ctrl[5].val[0] = 0; - state->CH_Ctrl[5].addr[1] = 70; - state->CH_Ctrl[5].bit[1] = 1; - state->CH_Ctrl[5].val[1] = 0; - state->CH_Ctrl[5].addr[2] = 70; - state->CH_Ctrl[5].bit[2] = 2; - state->CH_Ctrl[5].val[2] = 0; - state->CH_Ctrl[5].addr[3] = 70; - state->CH_Ctrl[5].bit[3] = 3; - state->CH_Ctrl[5].val[3] = 0; - - state->CH_Ctrl[6].Ctrl_Num = DN_IQTNGNBFBIAS_BST ; - state->CH_Ctrl[6].size = 1 ; - state->CH_Ctrl[6].addr[0] = 70; - state->CH_Ctrl[6].bit[0] = 4; - state->CH_Ctrl[6].val[0] = 1; - - state->CH_Ctrl[7].Ctrl_Num = RFSYN_EN_OUTMUX ; - state->CH_Ctrl[7].size = 1 ; - state->CH_Ctrl[7].addr[0] = 111; - state->CH_Ctrl[7].bit[0] = 4; - state->CH_Ctrl[7].val[0] = 0; - - state->CH_Ctrl[8].Ctrl_Num = RFSYN_SEL_VCO_OUT ; - state->CH_Ctrl[8].size = 1 ; - state->CH_Ctrl[8].addr[0] = 111; - state->CH_Ctrl[8].bit[0] = 7; - state->CH_Ctrl[8].val[0] = 1; - - state->CH_Ctrl[9].Ctrl_Num = RFSYN_SEL_VCO_HI ; - state->CH_Ctrl[9].size = 1 ; - state->CH_Ctrl[9].addr[0] = 111; - state->CH_Ctrl[9].bit[0] = 6; - state->CH_Ctrl[9].val[0] = 1; - - state->CH_Ctrl[10].Ctrl_Num = RFSYN_SEL_DIVM ; - state->CH_Ctrl[10].size = 1 ; - state->CH_Ctrl[10].addr[0] = 111; - state->CH_Ctrl[10].bit[0] = 5; - state->CH_Ctrl[10].val[0] = 0; - - state->CH_Ctrl[11].Ctrl_Num = RFSYN_RF_DIV_BIAS ; - state->CH_Ctrl[11].size = 2 ; - state->CH_Ctrl[11].addr[0] = 110; - state->CH_Ctrl[11].bit[0] = 0; - state->CH_Ctrl[11].val[0] = 1; - state->CH_Ctrl[11].addr[1] = 110; - state->CH_Ctrl[11].bit[1] = 1; - state->CH_Ctrl[11].val[1] = 0; - - state->CH_Ctrl[12].Ctrl_Num = DN_SEL_FREQ ; - state->CH_Ctrl[12].size = 3 ; - state->CH_Ctrl[12].addr[0] = 69; - state->CH_Ctrl[12].bit[0] = 2; - state->CH_Ctrl[12].val[0] = 0; - state->CH_Ctrl[12].addr[1] = 69; - state->CH_Ctrl[12].bit[1] = 3; - state->CH_Ctrl[12].val[1] = 0; - state->CH_Ctrl[12].addr[2] = 69; - state->CH_Ctrl[12].bit[2] = 4; - state->CH_Ctrl[12].val[2] = 0; - - state->CH_Ctrl[13].Ctrl_Num = RFSYN_VCO_BIAS ; - state->CH_Ctrl[13].size = 6 ; - state->CH_Ctrl[13].addr[0] = 110; - state->CH_Ctrl[13].bit[0] = 2; - state->CH_Ctrl[13].val[0] = 0; - state->CH_Ctrl[13].addr[1] = 110; - state->CH_Ctrl[13].bit[1] = 3; - state->CH_Ctrl[13].val[1] = 0; - state->CH_Ctrl[13].addr[2] = 110; - state->CH_Ctrl[13].bit[2] = 4; - state->CH_Ctrl[13].val[2] = 0; - state->CH_Ctrl[13].addr[3] = 110; - state->CH_Ctrl[13].bit[3] = 5; - state->CH_Ctrl[13].val[3] = 0; - state->CH_Ctrl[13].addr[4] = 110; - state->CH_Ctrl[13].bit[4] = 6; - state->CH_Ctrl[13].val[4] = 0; - state->CH_Ctrl[13].addr[5] = 110; - state->CH_Ctrl[13].bit[5] = 7; - state->CH_Ctrl[13].val[5] = 1; - - state->CH_Ctrl[14].Ctrl_Num = CHCAL_INT_MOD_RF ; - state->CH_Ctrl[14].size = 7 ; - state->CH_Ctrl[14].addr[0] = 14; - state->CH_Ctrl[14].bit[0] = 0; - state->CH_Ctrl[14].val[0] = 0; - state->CH_Ctrl[14].addr[1] = 14; - state->CH_Ctrl[14].bit[1] = 1; - state->CH_Ctrl[14].val[1] = 0; - state->CH_Ctrl[14].addr[2] = 14; - state->CH_Ctrl[14].bit[2] = 2; - state->CH_Ctrl[14].val[2] = 0; - state->CH_Ctrl[14].addr[3] = 14; - state->CH_Ctrl[14].bit[3] = 3; - state->CH_Ctrl[14].val[3] = 0; - state->CH_Ctrl[14].addr[4] = 14; - state->CH_Ctrl[14].bit[4] = 4; - state->CH_Ctrl[14].val[4] = 0; - state->CH_Ctrl[14].addr[5] = 14; - state->CH_Ctrl[14].bit[5] = 5; - state->CH_Ctrl[14].val[5] = 0; - state->CH_Ctrl[14].addr[6] = 14; - state->CH_Ctrl[14].bit[6] = 6; - state->CH_Ctrl[14].val[6] = 0; - - state->CH_Ctrl[15].Ctrl_Num = CHCAL_FRAC_MOD_RF ; - state->CH_Ctrl[15].size = 18 ; - state->CH_Ctrl[15].addr[0] = 17; - state->CH_Ctrl[15].bit[0] = 6; - state->CH_Ctrl[15].val[0] = 0; - state->CH_Ctrl[15].addr[1] = 17; - state->CH_Ctrl[15].bit[1] = 7; - state->CH_Ctrl[15].val[1] = 0; - state->CH_Ctrl[15].addr[2] = 16; - state->CH_Ctrl[15].bit[2] = 0; - state->CH_Ctrl[15].val[2] = 0; - state->CH_Ctrl[15].addr[3] = 16; - state->CH_Ctrl[15].bit[3] = 1; - state->CH_Ctrl[15].val[3] = 0; - state->CH_Ctrl[15].addr[4] = 16; - state->CH_Ctrl[15].bit[4] = 2; - state->CH_Ctrl[15].val[4] = 0; - state->CH_Ctrl[15].addr[5] = 16; - state->CH_Ctrl[15].bit[5] = 3; - state->CH_Ctrl[15].val[5] = 0; - state->CH_Ctrl[15].addr[6] = 16; - state->CH_Ctrl[15].bit[6] = 4; - state->CH_Ctrl[15].val[6] = 0; - state->CH_Ctrl[15].addr[7] = 16; - state->CH_Ctrl[15].bit[7] = 5; - state->CH_Ctrl[15].val[7] = 0; - state->CH_Ctrl[15].addr[8] = 16; - state->CH_Ctrl[15].bit[8] = 6; - state->CH_Ctrl[15].val[8] = 0; - state->CH_Ctrl[15].addr[9] = 16; - state->CH_Ctrl[15].bit[9] = 7; - state->CH_Ctrl[15].val[9] = 0; - state->CH_Ctrl[15].addr[10] = 15; - state->CH_Ctrl[15].bit[10] = 0; - state->CH_Ctrl[15].val[10] = 0; - state->CH_Ctrl[15].addr[11] = 15; - state->CH_Ctrl[15].bit[11] = 1; - state->CH_Ctrl[15].val[11] = 0; - state->CH_Ctrl[15].addr[12] = 15; - state->CH_Ctrl[15].bit[12] = 2; - state->CH_Ctrl[15].val[12] = 0; - state->CH_Ctrl[15].addr[13] = 15; - state->CH_Ctrl[15].bit[13] = 3; - state->CH_Ctrl[15].val[13] = 0; - state->CH_Ctrl[15].addr[14] = 15; - state->CH_Ctrl[15].bit[14] = 4; - state->CH_Ctrl[15].val[14] = 0; - state->CH_Ctrl[15].addr[15] = 15; - state->CH_Ctrl[15].bit[15] = 5; - state->CH_Ctrl[15].val[15] = 0; - state->CH_Ctrl[15].addr[16] = 15; - state->CH_Ctrl[15].bit[16] = 6; - state->CH_Ctrl[15].val[16] = 1; - state->CH_Ctrl[15].addr[17] = 15; - state->CH_Ctrl[15].bit[17] = 7; - state->CH_Ctrl[15].val[17] = 1; - - state->CH_Ctrl[16].Ctrl_Num = RFSYN_LPF_R ; - state->CH_Ctrl[16].size = 5 ; - state->CH_Ctrl[16].addr[0] = 112; - state->CH_Ctrl[16].bit[0] = 0; - state->CH_Ctrl[16].val[0] = 0; - state->CH_Ctrl[16].addr[1] = 112; - state->CH_Ctrl[16].bit[1] = 1; - state->CH_Ctrl[16].val[1] = 0; - state->CH_Ctrl[16].addr[2] = 112; - state->CH_Ctrl[16].bit[2] = 2; - state->CH_Ctrl[16].val[2] = 0; - state->CH_Ctrl[16].addr[3] = 112; - state->CH_Ctrl[16].bit[3] = 3; - state->CH_Ctrl[16].val[3] = 0; - state->CH_Ctrl[16].addr[4] = 112; - state->CH_Ctrl[16].bit[4] = 4; - state->CH_Ctrl[16].val[4] = 1; - - state->CH_Ctrl[17].Ctrl_Num = CHCAL_EN_INT_RF ; - state->CH_Ctrl[17].size = 1 ; - state->CH_Ctrl[17].addr[0] = 14; - state->CH_Ctrl[17].bit[0] = 7; - state->CH_Ctrl[17].val[0] = 0; - - state->CH_Ctrl[18].Ctrl_Num = TG_LO_DIVVAL ; - state->CH_Ctrl[18].size = 4 ; - state->CH_Ctrl[18].addr[0] = 107; - state->CH_Ctrl[18].bit[0] = 3; - state->CH_Ctrl[18].val[0] = 0; - state->CH_Ctrl[18].addr[1] = 107; - state->CH_Ctrl[18].bit[1] = 4; - state->CH_Ctrl[18].val[1] = 0; - state->CH_Ctrl[18].addr[2] = 107; - state->CH_Ctrl[18].bit[2] = 5; - state->CH_Ctrl[18].val[2] = 0; - state->CH_Ctrl[18].addr[3] = 107; - state->CH_Ctrl[18].bit[3] = 6; - state->CH_Ctrl[18].val[3] = 0; - - state->CH_Ctrl[19].Ctrl_Num = TG_LO_SELVAL ; - state->CH_Ctrl[19].size = 3 ; - state->CH_Ctrl[19].addr[0] = 107; - state->CH_Ctrl[19].bit[0] = 7; - state->CH_Ctrl[19].val[0] = 1; - state->CH_Ctrl[19].addr[1] = 106; - state->CH_Ctrl[19].bit[1] = 0; - state->CH_Ctrl[19].val[1] = 1; - state->CH_Ctrl[19].addr[2] = 106; - state->CH_Ctrl[19].bit[2] = 1; - state->CH_Ctrl[19].val[2] = 1; - - state->CH_Ctrl[20].Ctrl_Num = TG_DIV_VAL ; - state->CH_Ctrl[20].size = 11 ; - state->CH_Ctrl[20].addr[0] = 109; - state->CH_Ctrl[20].bit[0] = 2; - state->CH_Ctrl[20].val[0] = 0; - state->CH_Ctrl[20].addr[1] = 109; - state->CH_Ctrl[20].bit[1] = 3; - state->CH_Ctrl[20].val[1] = 0; - state->CH_Ctrl[20].addr[2] = 109; - state->CH_Ctrl[20].bit[2] = 4; - state->CH_Ctrl[20].val[2] = 0; - state->CH_Ctrl[20].addr[3] = 109; - state->CH_Ctrl[20].bit[3] = 5; - state->CH_Ctrl[20].val[3] = 0; - state->CH_Ctrl[20].addr[4] = 109; - state->CH_Ctrl[20].bit[4] = 6; - state->CH_Ctrl[20].val[4] = 0; - state->CH_Ctrl[20].addr[5] = 109; - state->CH_Ctrl[20].bit[5] = 7; - state->CH_Ctrl[20].val[5] = 0; - state->CH_Ctrl[20].addr[6] = 108; - state->CH_Ctrl[20].bit[6] = 0; - state->CH_Ctrl[20].val[6] = 0; - state->CH_Ctrl[20].addr[7] = 108; - state->CH_Ctrl[20].bit[7] = 1; - state->CH_Ctrl[20].val[7] = 0; - state->CH_Ctrl[20].addr[8] = 108; - state->CH_Ctrl[20].bit[8] = 2; - state->CH_Ctrl[20].val[8] = 1; - state->CH_Ctrl[20].addr[9] = 108; - state->CH_Ctrl[20].bit[9] = 3; - state->CH_Ctrl[20].val[9] = 1; - state->CH_Ctrl[20].addr[10] = 108; - state->CH_Ctrl[20].bit[10] = 4; - state->CH_Ctrl[20].val[10] = 1; - - state->CH_Ctrl[21].Ctrl_Num = TG_VCO_BIAS ; - state->CH_Ctrl[21].size = 6 ; - state->CH_Ctrl[21].addr[0] = 106; - state->CH_Ctrl[21].bit[0] = 2; - state->CH_Ctrl[21].val[0] = 0; - state->CH_Ctrl[21].addr[1] = 106; - state->CH_Ctrl[21].bit[1] = 3; - state->CH_Ctrl[21].val[1] = 0; - state->CH_Ctrl[21].addr[2] = 106; - state->CH_Ctrl[21].bit[2] = 4; - state->CH_Ctrl[21].val[2] = 0; - state->CH_Ctrl[21].addr[3] = 106; - state->CH_Ctrl[21].bit[3] = 5; - state->CH_Ctrl[21].val[3] = 0; - state->CH_Ctrl[21].addr[4] = 106; - state->CH_Ctrl[21].bit[4] = 6; - state->CH_Ctrl[21].val[4] = 0; - state->CH_Ctrl[21].addr[5] = 106; - state->CH_Ctrl[21].bit[5] = 7; - state->CH_Ctrl[21].val[5] = 1; - - state->CH_Ctrl[22].Ctrl_Num = SEQ_EXTPOWERUP ; - state->CH_Ctrl[22].size = 1 ; - state->CH_Ctrl[22].addr[0] = 138; - state->CH_Ctrl[22].bit[0] = 4; - state->CH_Ctrl[22].val[0] = 1; - - state->CH_Ctrl[23].Ctrl_Num = OVERRIDE_2 ; - state->CH_Ctrl[23].size = 1 ; - state->CH_Ctrl[23].addr[0] = 17; - state->CH_Ctrl[23].bit[0] = 5; - state->CH_Ctrl[23].val[0] = 0; - - state->CH_Ctrl[24].Ctrl_Num = OVERRIDE_3 ; - state->CH_Ctrl[24].size = 1 ; - state->CH_Ctrl[24].addr[0] = 111; - state->CH_Ctrl[24].bit[0] = 3; - state->CH_Ctrl[24].val[0] = 0; - - state->CH_Ctrl[25].Ctrl_Num = OVERRIDE_4 ; - state->CH_Ctrl[25].size = 1 ; - state->CH_Ctrl[25].addr[0] = 112; - state->CH_Ctrl[25].bit[0] = 7; - state->CH_Ctrl[25].val[0] = 0; - - state->CH_Ctrl[26].Ctrl_Num = SEQ_FSM_PULSE ; - state->CH_Ctrl[26].size = 1 ; - state->CH_Ctrl[26].addr[0] = 136; - state->CH_Ctrl[26].bit[0] = 7; - state->CH_Ctrl[26].val[0] = 0; - - state->CH_Ctrl[27].Ctrl_Num = GPIO_4B ; - state->CH_Ctrl[27].size = 1 ; - state->CH_Ctrl[27].addr[0] = 149; - state->CH_Ctrl[27].bit[0] = 7; - state->CH_Ctrl[27].val[0] = 0; - - state->CH_Ctrl[28].Ctrl_Num = GPIO_3B ; - state->CH_Ctrl[28].size = 1 ; - state->CH_Ctrl[28].addr[0] = 149; - state->CH_Ctrl[28].bit[0] = 6; - state->CH_Ctrl[28].val[0] = 0; - - state->CH_Ctrl[29].Ctrl_Num = GPIO_4 ; - state->CH_Ctrl[29].size = 1 ; - state->CH_Ctrl[29].addr[0] = 149; - state->CH_Ctrl[29].bit[0] = 5; - state->CH_Ctrl[29].val[0] = 1; - - state->CH_Ctrl[30].Ctrl_Num = GPIO_3 ; - state->CH_Ctrl[30].size = 1 ; - state->CH_Ctrl[30].addr[0] = 149; - state->CH_Ctrl[30].bit[0] = 4; - state->CH_Ctrl[30].val[0] = 1; - - state->CH_Ctrl[31].Ctrl_Num = GPIO_1B ; - state->CH_Ctrl[31].size = 1 ; - state->CH_Ctrl[31].addr[0] = 149; - state->CH_Ctrl[31].bit[0] = 3; - state->CH_Ctrl[31].val[0] = 0; - - state->CH_Ctrl[32].Ctrl_Num = DAC_A_ENABLE ; - state->CH_Ctrl[32].size = 1 ; - state->CH_Ctrl[32].addr[0] = 93; - state->CH_Ctrl[32].bit[0] = 1; - state->CH_Ctrl[32].val[0] = 0; - - state->CH_Ctrl[33].Ctrl_Num = DAC_B_ENABLE ; - state->CH_Ctrl[33].size = 1 ; - state->CH_Ctrl[33].addr[0] = 93; - state->CH_Ctrl[33].bit[0] = 0; - state->CH_Ctrl[33].val[0] = 0; - - state->CH_Ctrl[34].Ctrl_Num = DAC_DIN_A ; - state->CH_Ctrl[34].size = 6 ; - state->CH_Ctrl[34].addr[0] = 92; - state->CH_Ctrl[34].bit[0] = 2; - state->CH_Ctrl[34].val[0] = 0; - state->CH_Ctrl[34].addr[1] = 92; - state->CH_Ctrl[34].bit[1] = 3; - state->CH_Ctrl[34].val[1] = 0; - state->CH_Ctrl[34].addr[2] = 92; - state->CH_Ctrl[34].bit[2] = 4; - state->CH_Ctrl[34].val[2] = 0; - state->CH_Ctrl[34].addr[3] = 92; - state->CH_Ctrl[34].bit[3] = 5; - state->CH_Ctrl[34].val[3] = 0; - state->CH_Ctrl[34].addr[4] = 92; - state->CH_Ctrl[34].bit[4] = 6; - state->CH_Ctrl[34].val[4] = 0; - state->CH_Ctrl[34].addr[5] = 92; - state->CH_Ctrl[34].bit[5] = 7; - state->CH_Ctrl[34].val[5] = 0; - - state->CH_Ctrl[35].Ctrl_Num = DAC_DIN_B ; - state->CH_Ctrl[35].size = 6 ; - state->CH_Ctrl[35].addr[0] = 93; - state->CH_Ctrl[35].bit[0] = 2; - state->CH_Ctrl[35].val[0] = 0; - state->CH_Ctrl[35].addr[1] = 93; - state->CH_Ctrl[35].bit[1] = 3; - state->CH_Ctrl[35].val[1] = 0; - state->CH_Ctrl[35].addr[2] = 93; - state->CH_Ctrl[35].bit[2] = 4; - state->CH_Ctrl[35].val[2] = 0; - state->CH_Ctrl[35].addr[3] = 93; - state->CH_Ctrl[35].bit[3] = 5; - state->CH_Ctrl[35].val[3] = 0; - state->CH_Ctrl[35].addr[4] = 93; - state->CH_Ctrl[35].bit[4] = 6; - state->CH_Ctrl[35].val[4] = 0; - state->CH_Ctrl[35].addr[5] = 93; - state->CH_Ctrl[35].bit[5] = 7; - state->CH_Ctrl[35].val[5] = 0; - -#ifdef _MXL_PRODUCTION - state->CH_Ctrl[36].Ctrl_Num = RFSYN_EN_DIV ; - state->CH_Ctrl[36].size = 1 ; - state->CH_Ctrl[36].addr[0] = 109; - state->CH_Ctrl[36].bit[0] = 1; - state->CH_Ctrl[36].val[0] = 1; - - state->CH_Ctrl[37].Ctrl_Num = RFSYN_DIVM ; - state->CH_Ctrl[37].size = 2 ; - state->CH_Ctrl[37].addr[0] = 112; - state->CH_Ctrl[37].bit[0] = 5; - state->CH_Ctrl[37].val[0] = 0; - state->CH_Ctrl[37].addr[1] = 112; - state->CH_Ctrl[37].bit[1] = 6; - state->CH_Ctrl[37].val[1] = 0; - - state->CH_Ctrl[38].Ctrl_Num = DN_BYPASS_AGC_I2C ; - state->CH_Ctrl[38].size = 1 ; - state->CH_Ctrl[38].addr[0] = 65; - state->CH_Ctrl[38].bit[0] = 1; - state->CH_Ctrl[38].val[0] = 0; -#endif - - return 0 ; -} - -static void InitTunerControls(struct dvb_frontend *fe) -{ - MXL5005_RegisterInit(fe); - MXL5005_ControlInit(fe); -#ifdef _MXL_INTERNAL - MXL5005_MXLControlInit(fe); -#endif -} - -static u16 MXL5005_TunerConfig(struct dvb_frontend *fe, - u8 Mode, /* 0: Analog Mode ; 1: Digital Mode */ - u8 IF_mode, /* for Analog Mode, 0: zero IF; 1: low IF */ - u32 Bandwidth, /* filter channel bandwidth (6, 7, 8) */ - u32 IF_out, /* Desired IF Out Frequency */ - u32 Fxtal, /* XTAL Frequency */ - u8 AGC_Mode, /* AGC Mode - Dual AGC: 0, Single AGC: 1 */ - u16 TOP, /* 0: Dual AGC; Value: take over point */ - u16 IF_OUT_LOAD, /* IF Out Load Resistor (200 / 300 Ohms) */ - u8 CLOCK_OUT, /* 0: turn off clk out; 1: turn on clock out */ - u8 DIV_OUT, /* 0: Div-1; 1: Div-4 */ - u8 CAPSELECT, /* 0: disable On-Chip pulling cap; 1: enable */ - u8 EN_RSSI, /* 0: disable RSSI; 1: enable RSSI */ - - /* Modulation Type; */ - /* 0 - Default; 1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */ - u8 Mod_Type, - - /* Tracking Filter */ - /* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */ - u8 TF_Type - ) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u16 status = 0; - - state->Mode = Mode; - state->IF_Mode = IF_mode; - state->Chan_Bandwidth = Bandwidth; - state->IF_OUT = IF_out; - state->Fxtal = Fxtal; - state->AGC_Mode = AGC_Mode; - state->TOP = TOP; - state->IF_OUT_LOAD = IF_OUT_LOAD; - state->CLOCK_OUT = CLOCK_OUT; - state->DIV_OUT = DIV_OUT; - state->CAPSELECT = CAPSELECT; - state->EN_RSSI = EN_RSSI; - state->Mod_Type = Mod_Type; - state->TF_Type = TF_Type; - - /* Initialize all the controls and registers */ - InitTunerControls(fe); - - /* Synthesizer LO frequency calculation */ - MXL_SynthIFLO_Calc(fe); - - return status; -} - -static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe) -{ - struct mxl5005s_state *state = fe->tuner_priv; - if (state->Mode == 1) /* Digital Mode */ - state->IF_LO = state->IF_OUT; - else /* Analog Mode */ { - if (state->IF_Mode == 0) /* Analog Zero IF mode */ - state->IF_LO = state->IF_OUT + 400000; - else /* Analog Low IF mode */ - state->IF_LO = state->IF_OUT + state->Chan_Bandwidth/2; - } -} - -static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe) -{ - struct mxl5005s_state *state = fe->tuner_priv; - - if (state->Mode == 1) /* Digital Mode */ { - /* remove 20.48MHz setting for 2.6.10 */ - state->RF_LO = state->RF_IN; - /* change for 2.6.6 */ - state->TG_LO = state->RF_IN - 750000; - } else /* Analog Mode */ { - if (state->IF_Mode == 0) /* Analog Zero IF mode */ { - state->RF_LO = state->RF_IN - 400000; - state->TG_LO = state->RF_IN - 1750000; - } else /* Analog Low IF mode */ { - state->RF_LO = state->RF_IN - state->Chan_Bandwidth/2; - state->TG_LO = state->RF_IN - - state->Chan_Bandwidth + 500000; - } - } -} - -static u16 MXL_OverwriteICDefault(struct dvb_frontend *fe) -{ - u16 status = 0; - - status += MXL_ControlWrite(fe, OVERRIDE_1, 1); - status += MXL_ControlWrite(fe, OVERRIDE_2, 1); - status += MXL_ControlWrite(fe, OVERRIDE_3, 1); - status += MXL_ControlWrite(fe, OVERRIDE_4, 1); - - return status; -} - -static u16 MXL_BlockInit(struct dvb_frontend *fe) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u16 status = 0; - - status += MXL_OverwriteICDefault(fe); - - /* Downconverter Control Dig Ana */ - status += MXL_ControlWrite(fe, DN_IQTN_AMP_CUT, state->Mode ? 1 : 0); - - /* Filter Control Dig Ana */ - status += MXL_ControlWrite(fe, BB_MODE, state->Mode ? 0 : 1); - status += MXL_ControlWrite(fe, BB_BUF, state->Mode ? 3 : 2); - status += MXL_ControlWrite(fe, BB_BUF_OA, state->Mode ? 1 : 0); - status += MXL_ControlWrite(fe, BB_IQSWAP, state->Mode ? 0 : 1); - status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 0); - - /* Initialize Low-Pass Filter */ - if (state->Mode) { /* Digital Mode */ - switch (state->Chan_Bandwidth) { - case 8000000: - status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 0); - break; - case 7000000: - status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 2); - break; - case 6000000: - status += MXL_ControlWrite(fe, - BB_DLPF_BANDSEL, 3); - break; - } - } else { /* Analog Mode */ - switch (state->Chan_Bandwidth) { - case 8000000: /* Low Zero */ - status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, - (state->IF_Mode ? 0 : 3)); - break; - case 7000000: - status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, - (state->IF_Mode ? 1 : 4)); - break; - case 6000000: - status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, - (state->IF_Mode ? 2 : 5)); - break; - } - } - - /* Charge Pump Control Dig Ana */ - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, state->Mode ? 5 : 8); - status += MXL_ControlWrite(fe, - RFSYN_EN_CHP_HIGAIN, state->Mode ? 1 : 1); - status += MXL_ControlWrite(fe, EN_CHP_LIN_B, state->Mode ? 0 : 0); - - /* AGC TOP Control */ - if (state->AGC_Mode == 0) /* Dual AGC */ { - status += MXL_ControlWrite(fe, AGC_IF, 15); - status += MXL_ControlWrite(fe, AGC_RF, 15); - } else /* Single AGC Mode Dig Ana */ - status += MXL_ControlWrite(fe, AGC_RF, state->Mode ? 15 : 12); - - if (state->TOP == 55) /* TOP == 5.5 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x0); - - if (state->TOP == 72) /* TOP == 7.2 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x1); - - if (state->TOP == 92) /* TOP == 9.2 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x2); - - if (state->TOP == 110) /* TOP == 11.0 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x3); - - if (state->TOP == 129) /* TOP == 12.9 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x4); - - if (state->TOP == 147) /* TOP == 14.7 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x5); - - if (state->TOP == 168) /* TOP == 16.8 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x6); - - if (state->TOP == 194) /* TOP == 19.4 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x7); - - if (state->TOP == 212) /* TOP == 21.2 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x9); - - if (state->TOP == 232) /* TOP == 23.2 */ - status += MXL_ControlWrite(fe, AGC_IF, 0xA); - - if (state->TOP == 252) /* TOP == 25.2 */ - status += MXL_ControlWrite(fe, AGC_IF, 0xB); - - if (state->TOP == 271) /* TOP == 27.1 */ - status += MXL_ControlWrite(fe, AGC_IF, 0xC); - - if (state->TOP == 292) /* TOP == 29.2 */ - status += MXL_ControlWrite(fe, AGC_IF, 0xD); - - if (state->TOP == 317) /* TOP == 31.7 */ - status += MXL_ControlWrite(fe, AGC_IF, 0xE); - - if (state->TOP == 349) /* TOP == 34.9 */ - status += MXL_ControlWrite(fe, AGC_IF, 0xF); - - /* IF Synthesizer Control */ - status += MXL_IFSynthInit(fe); - - /* IF UpConverter Control */ - if (state->IF_OUT_LOAD == 200) { - status += MXL_ControlWrite(fe, DRV_RES_SEL, 6); - status += MXL_ControlWrite(fe, I_DRIVER, 2); - } - if (state->IF_OUT_LOAD == 300) { - status += MXL_ControlWrite(fe, DRV_RES_SEL, 4); - status += MXL_ControlWrite(fe, I_DRIVER, 1); - } - - /* Anti-Alias Filtering Control - * initialise Anti-Aliasing Filter - */ - if (state->Mode) { /* Digital Mode */ - if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 6280000UL) { - status += MXL_ControlWrite(fe, EN_AAF, 1); - status += MXL_ControlWrite(fe, EN_3P, 1); - status += MXL_ControlWrite(fe, EN_AUX_3P, 1); - status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); - } - if ((state->IF_OUT == 36125000UL) || - (state->IF_OUT == 36150000UL)) { - status += MXL_ControlWrite(fe, EN_AAF, 1); - status += MXL_ControlWrite(fe, EN_3P, 1); - status += MXL_ControlWrite(fe, EN_AUX_3P, 1); - status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1); - } - if (state->IF_OUT > 36150000UL) { - status += MXL_ControlWrite(fe, EN_AAF, 0); - status += MXL_ControlWrite(fe, EN_3P, 1); - status += MXL_ControlWrite(fe, EN_AUX_3P, 1); - status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1); - } - } else { /* Analog Mode */ - if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 5000000UL) { - status += MXL_ControlWrite(fe, EN_AAF, 1); - status += MXL_ControlWrite(fe, EN_3P, 1); - status += MXL_ControlWrite(fe, EN_AUX_3P, 1); - status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); - } - if (state->IF_OUT > 5000000UL) { - status += MXL_ControlWrite(fe, EN_AAF, 0); - status += MXL_ControlWrite(fe, EN_3P, 0); - status += MXL_ControlWrite(fe, EN_AUX_3P, 0); - status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); - } - } - - /* Demod Clock Out */ - if (state->CLOCK_OUT) - status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 1); - else - status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 0); - - if (state->DIV_OUT == 1) - status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 1); - if (state->DIV_OUT == 0) - status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 0); - - /* Crystal Control */ - if (state->CAPSELECT) - status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 1); - else - status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 0); - - if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL) - status += MXL_ControlWrite(fe, IF_SEL_DBL, 1); - if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL) - status += MXL_ControlWrite(fe, IF_SEL_DBL, 0); - - if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL) - status += MXL_ControlWrite(fe, RFSYN_R_DIV, 3); - if (state->Fxtal > 22000000UL && state->Fxtal <= 32000000UL) - status += MXL_ControlWrite(fe, RFSYN_R_DIV, 0); - - /* Misc Controls */ - if (state->Mode == 0 && state->IF_Mode == 1) /* Analog LowIF mode */ - status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 0); - else - status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 1); - - /* status += MXL_ControlRead(fe, IF_DIVVAL, &IF_DIVVAL_Val); */ - - /* Set TG_R_DIV */ - status += MXL_ControlWrite(fe, TG_R_DIV, - MXL_Ceiling(state->Fxtal, 1000000)); - - /* Apply Default value to BB_INITSTATE_DLPF_TUNE */ - - /* RSSI Control */ - if (state->EN_RSSI) { - status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); - status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); - status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); - - /* RSSI reference point */ - status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2); - status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 3); - status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); - - /* TOP point */ - status += MXL_ControlWrite(fe, RFA_FLR, 0); - status += MXL_ControlWrite(fe, RFA_CEIL, 12); - } - - /* Modulation type bit settings - * Override the control values preset - */ - if (state->Mod_Type == MXL_DVBT) /* DVB-T Mode */ { - state->AGC_Mode = 1; /* Single AGC Mode */ - - /* Enable RSSI */ - status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); - status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); - status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); - - /* RSSI reference point */ - status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); - status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); - status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); - - /* TOP point */ - status += MXL_ControlWrite(fe, RFA_FLR, 2); - status += MXL_ControlWrite(fe, RFA_CEIL, 13); - if (state->IF_OUT <= 6280000UL) /* Low IF */ - status += MXL_ControlWrite(fe, BB_IQSWAP, 0); - else /* High IF */ - status += MXL_ControlWrite(fe, BB_IQSWAP, 1); - - } - if (state->Mod_Type == MXL_ATSC) /* ATSC Mode */ { - state->AGC_Mode = 1; /* Single AGC Mode */ - - /* Enable RSSI */ - status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); - status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); - status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); - - /* RSSI reference point */ - status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2); - status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 4); - status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); - - /* TOP point */ - status += MXL_ControlWrite(fe, RFA_FLR, 2); - status += MXL_ControlWrite(fe, RFA_CEIL, 13); - status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 1); - /* Low Zero */ - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5); - - if (state->IF_OUT <= 6280000UL) /* Low IF */ - status += MXL_ControlWrite(fe, BB_IQSWAP, 0); - else /* High IF */ - status += MXL_ControlWrite(fe, BB_IQSWAP, 1); - } - if (state->Mod_Type == MXL_QAM) /* QAM Mode */ { - state->Mode = MXL_DIGITAL_MODE; - - /* state->AGC_Mode = 1; */ /* Single AGC Mode */ - - /* Disable RSSI */ /* change here for v2.6.5 */ - status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); - status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); - status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); - - /* RSSI reference point */ - status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); - status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); - status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); - /* change here for v2.6.5 */ - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); - - if (state->IF_OUT <= 6280000UL) /* Low IF */ - status += MXL_ControlWrite(fe, BB_IQSWAP, 0); - else /* High IF */ - status += MXL_ControlWrite(fe, BB_IQSWAP, 1); - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2); - - } - if (state->Mod_Type == MXL_ANALOG_CABLE) { - /* Analog Cable Mode */ - /* state->Mode = MXL_DIGITAL_MODE; */ - - state->AGC_Mode = 1; /* Single AGC Mode */ - - /* Disable RSSI */ - status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); - status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); - status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); - /* change for 2.6.3 */ - status += MXL_ControlWrite(fe, AGC_IF, 1); - status += MXL_ControlWrite(fe, AGC_RF, 15); - status += MXL_ControlWrite(fe, BB_IQSWAP, 1); - } - - if (state->Mod_Type == MXL_ANALOG_OTA) { - /* Analog OTA Terrestrial mode add for 2.6.7 */ - /* state->Mode = MXL_ANALOG_MODE; */ - - /* Enable RSSI */ - status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); - status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); - status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); - - /* RSSI reference point */ - status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); - status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); - status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); - status += MXL_ControlWrite(fe, BB_IQSWAP, 1); - } - - /* RSSI disable */ - if (state->EN_RSSI == 0) { - status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); - status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); - status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); - } - - return status; -} - -static u16 MXL_IFSynthInit(struct dvb_frontend *fe) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u16 status = 0 ; - u32 Fref = 0 ; - u32 Kdbl, intModVal ; - u32 fracModVal ; - Kdbl = 2 ; - - if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL) - Kdbl = 2 ; - if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL) - Kdbl = 1 ; - - /* IF Synthesizer Control */ - if (state->Mode == 0 && state->IF_Mode == 1) /* Analog Low IF mode */ { - if (state->IF_LO == 41000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); - Fref = 328000000UL ; - } - if (state->IF_LO == 47000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 376000000UL ; - } - if (state->IF_LO == 54000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); - Fref = 324000000UL ; - } - if (state->IF_LO == 60000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 360000000UL ; - } - if (state->IF_LO == 39250000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); - Fref = 314000000UL ; - } - if (state->IF_LO == 39650000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); - Fref = 317200000UL ; - } - if (state->IF_LO == 40150000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); - Fref = 321200000UL ; - } - if (state->IF_LO == 40650000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); - Fref = 325200000UL ; - } - } - - if (state->Mode || (state->Mode == 0 && state->IF_Mode == 0)) { - if (state->IF_LO == 57000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 342000000UL ; - } - if (state->IF_LO == 44000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 352000000UL ; - } - if (state->IF_LO == 43750000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 350000000UL ; - } - if (state->IF_LO == 36650000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 366500000UL ; - } - if (state->IF_LO == 36150000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 361500000UL ; - } - if (state->IF_LO == 36000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 360000000UL ; - } - if (state->IF_LO == 35250000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 352500000UL ; - } - if (state->IF_LO == 34750000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 347500000UL ; - } - if (state->IF_LO == 6280000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 376800000UL ; - } - if (state->IF_LO == 5000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 360000000UL ; - } - if (state->IF_LO == 4500000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 360000000UL ; - } - if (state->IF_LO == 4570000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 365600000UL ; - } - if (state->IF_LO == 4000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x05); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 360000000UL ; - } - if (state->IF_LO == 57400000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 344400000UL ; - } - if (state->IF_LO == 44400000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 355200000UL ; - } - if (state->IF_LO == 44150000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 353200000UL ; - } - if (state->IF_LO == 37050000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 370500000UL ; - } - if (state->IF_LO == 36550000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 365500000UL ; - } - if (state->IF_LO == 36125000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 361250000UL ; - } - if (state->IF_LO == 6000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 360000000UL ; - } - if (state->IF_LO == 5400000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); - Fref = 324000000UL ; - } - if (state->IF_LO == 5380000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); - Fref = 322800000UL ; - } - if (state->IF_LO == 5200000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 374400000UL ; - } - if (state->IF_LO == 4900000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 352800000UL ; - } - if (state->IF_LO == 4400000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 352000000UL ; - } - if (state->IF_LO == 4063000UL) /* add for 2.6.8 */ { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x05); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 365670000UL ; - } - } - /* CHCAL_INT_MOD_IF */ - /* CHCAL_FRAC_MOD_IF */ - intModVal = Fref / (state->Fxtal * Kdbl/2); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_IF, intModVal); - - fracModVal = (2<<15)*(Fref/1000 - (state->Fxtal/1000 * Kdbl/2) * - intModVal); - - fracModVal = fracModVal / ((state->Fxtal * Kdbl/2)/1000); - status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_IF, fracModVal); - - return status ; -} - -static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u16 status = 0; - u32 divider_val, E3, E4, E5, E5A; - u32 Fmax, Fmin, FmaxBin, FminBin; - u32 Kdbl_RF = 2; - u32 tg_divval; - u32 tg_lo; - - u32 Fref_TG; - u32 Fvco; - - state->RF_IN = RF_Freq; - - MXL_SynthRFTGLO_Calc(fe); - - if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL) - Kdbl_RF = 2; - if (state->Fxtal > 22000000 && state->Fxtal <= 32000000) - Kdbl_RF = 1; - - /* Downconverter Controls - * Look-Up Table Implementation for: - * DN_POLY - * DN_RFGAIN - * DN_CAP_RFLPF - * DN_EN_VHFUHFBAR - * DN_GAIN_ADJUST - * Change the boundary reference from RF_IN to RF_LO - */ - if (state->RF_LO < 40000000UL) - return -1; - - if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) { - status += MXL_ControlWrite(fe, DN_POLY, 2); - status += MXL_ControlWrite(fe, DN_RFGAIN, 3); - status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 423); - status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); - status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 1); - } - if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) { - status += MXL_ControlWrite(fe, DN_POLY, 3); - status += MXL_ControlWrite(fe, DN_RFGAIN, 3); - status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 222); - status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); - status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 1); - } - if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) { - status += MXL_ControlWrite(fe, DN_POLY, 3); - status += MXL_ControlWrite(fe, DN_RFGAIN, 3); - status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 147); - status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); - status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 2); - } - if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) { - status += MXL_ControlWrite(fe, DN_POLY, 3); - status += MXL_ControlWrite(fe, DN_RFGAIN, 3); - status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 9); - status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); - status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 2); - } - if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) { - status += MXL_ControlWrite(fe, DN_POLY, 3); - status += MXL_ControlWrite(fe, DN_RFGAIN, 3); - status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); - status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); - status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); - } - if (state->RF_LO > 300000000UL && state->RF_LO <= 650000000UL) { - status += MXL_ControlWrite(fe, DN_POLY, 3); - status += MXL_ControlWrite(fe, DN_RFGAIN, 1); - status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); - status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 0); - status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); - } - if (state->RF_LO > 650000000UL && state->RF_LO <= 900000000UL) { - status += MXL_ControlWrite(fe, DN_POLY, 3); - status += MXL_ControlWrite(fe, DN_RFGAIN, 2); - status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); - status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 0); - status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); - } - if (state->RF_LO > 900000000UL) - return -1; - - /* DN_IQTNBUF_AMP */ - /* DN_IQTNGNBFBIAS_BST */ - if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 300000000UL && state->RF_LO <= 400000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 400000000UL && state->RF_LO <= 450000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 450000000UL && state->RF_LO <= 500000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 500000000UL && state->RF_LO <= 550000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 550000000UL && state->RF_LO <= 600000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 600000000UL && state->RF_LO <= 650000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 650000000UL && state->RF_LO <= 700000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 700000000UL && state->RF_LO <= 750000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 750000000UL && state->RF_LO <= 800000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 800000000UL && state->RF_LO <= 850000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 10); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 1); - } - if (state->RF_LO > 850000000UL && state->RF_LO <= 900000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 10); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 1); - } - - /* - * Set RF Synth and LO Path Control - * - * Look-Up table implementation for: - * RFSYN_EN_OUTMUX - * RFSYN_SEL_VCO_OUT - * RFSYN_SEL_VCO_HI - * RFSYN_SEL_DIVM - * RFSYN_RF_DIV_BIAS - * DN_SEL_FREQ - * - * Set divider_val, Fmax, Fmix to use in Equations - */ - FminBin = 28000000UL ; - FmaxBin = 42500000UL ; - if (state->RF_LO >= 40000000UL && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); - divider_val = 64 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 42500000UL ; - FmaxBin = 56000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); - divider_val = 64 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 56000000UL ; - FmaxBin = 85000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); - divider_val = 32 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 85000000UL ; - FmaxBin = 112000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); - divider_val = 32 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 112000000UL ; - FmaxBin = 170000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 2); - divider_val = 16 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 170000000UL ; - FmaxBin = 225000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 2); - divider_val = 16 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 225000000UL ; - FmaxBin = 300000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 4); - divider_val = 8 ; - Fmax = 340000000UL ; - Fmin = FminBin ; - } - FminBin = 300000000UL ; - FmaxBin = 340000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); - divider_val = 8 ; - Fmax = FmaxBin ; - Fmin = 225000000UL ; - } - FminBin = 340000000UL ; - FmaxBin = 450000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 2); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); - divider_val = 8 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 450000000UL ; - FmaxBin = 680000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 1); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); - divider_val = 4 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 680000000UL ; - FmaxBin = 900000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 1); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); - divider_val = 4 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - - /* CHCAL_INT_MOD_RF - * CHCAL_FRAC_MOD_RF - * RFSYN_LPF_R - * CHCAL_EN_INT_RF - */ - /* Equation E3 RFSYN_VCO_BIAS */ - E3 = (((Fmax-state->RF_LO)/1000)*32)/((Fmax-Fmin)/1000) + 8 ; - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, E3); - - /* Equation E4 CHCAL_INT_MOD_RF */ - E4 = (state->RF_LO*divider_val/1000)/(2*state->Fxtal*Kdbl_RF/1000); - MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, E4); - - /* Equation E5 CHCAL_FRAC_MOD_RF CHCAL_EN_INT_RF */ - E5 = ((2<<17)*(state->RF_LO/10000*divider_val - - (E4*(2*state->Fxtal*Kdbl_RF)/10000))) / - (2*state->Fxtal*Kdbl_RF/10000); - - status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5); - - /* Equation E5A RFSYN_LPF_R */ - E5A = (((Fmax - state->RF_LO)/1000)*4/((Fmax-Fmin)/1000)) + 1 ; - status += MXL_ControlWrite(fe, RFSYN_LPF_R, E5A); - - /* Euqation E5B CHCAL_EN_INIT_RF */ - status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, ((E5 == 0) ? 1 : 0)); - /*if (E5 == 0) - * status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, 1); - *else - * status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5); - */ - - /* - * Set TG Synth - * - * Look-Up table implementation for: - * TG_LO_DIVVAL - * TG_LO_SELVAL - * - * Set divider_val, Fmax, Fmix to use in Equations - */ - if (state->TG_LO < 33000000UL) - return -1; - - FminBin = 33000000UL ; - FmaxBin = 50000000UL ; - if (state->TG_LO >= FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x6); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x0); - divider_val = 36 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 50000000UL ; - FmaxBin = 67000000UL ; - if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x1); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x0); - divider_val = 24 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 67000000UL ; - FmaxBin = 100000000UL ; - if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0xC); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); - divider_val = 18 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 100000000UL ; - FmaxBin = 150000000UL ; - if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); - divider_val = 12 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 150000000UL ; - FmaxBin = 200000000UL ; - if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); - divider_val = 8 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 200000000UL ; - FmaxBin = 300000000UL ; - if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x3); - divider_val = 6 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 300000000UL ; - FmaxBin = 400000000UL ; - if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x3); - divider_val = 4 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 400000000UL ; - FmaxBin = 600000000UL ; - if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x7); - divider_val = 3 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 600000000UL ; - FmaxBin = 900000000UL ; - if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x7); - divider_val = 2 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - - /* TG_DIV_VAL */ - tg_divval = (state->TG_LO*divider_val/100000) * - (MXL_Ceiling(state->Fxtal, 1000000) * 100) / - (state->Fxtal/1000); - - status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval); - - if (state->TG_LO > 600000000UL) - status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval + 1); - - Fmax = 1800000000UL ; - Fmin = 1200000000UL ; - - /* prevent overflow of 32 bit unsigned integer, use - * following equation. Edit for v2.6.4 - */ - /* Fref_TF = Fref_TG * 1000 */ - Fref_TG = (state->Fxtal/1000) / MXL_Ceiling(state->Fxtal, 1000000); - - /* Fvco = Fvco/10 */ - Fvco = (state->TG_LO/10000) * divider_val * Fref_TG; - - tg_lo = (((Fmax/10 - Fvco)/100)*32) / ((Fmax-Fmin)/1000)+8; - - /* below equation is same as above but much harder to debug. - * - * static u32 MXL_GetXtalInt(u32 Xtal_Freq) - * { - * if ((Xtal_Freq % 1000000) == 0) - * return (Xtal_Freq / 10000); - * else - * return (((Xtal_Freq / 1000000) + 1)*100); - * } - * - * u32 Xtal_Int = MXL_GetXtalInt(state->Fxtal); - * tg_lo = ( ((Fmax/10000 * Xtal_Int)/100) - - * ((state->TG_LO/10000)*divider_val * - * (state->Fxtal/10000)/100) )*32/((Fmax-Fmin)/10000 * - * Xtal_Int/100) + 8; - */ - - status += MXL_ControlWrite(fe, TG_VCO_BIAS , tg_lo); - - /* add for 2.6.5 Special setting for QAM */ - if (state->Mod_Type == MXL_QAM) { - if (state->config->qam_gain != 0) - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, - state->config->qam_gain); - else if (state->RF_IN < 680000000) - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); - else - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2); - } - - /* Off Chip Tracking Filter Control */ - if (state->TF_Type == MXL_TF_OFF) { - /* Tracking Filter Off State; turn off all the banks */ - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 3, 1); /* Bank1 Off */ - status += MXL_SetGPIO(fe, 1, 1); /* Bank2 Off */ - status += MXL_SetGPIO(fe, 4, 1); /* Bank3 Off */ - } - - if (state->TF_Type == MXL_TF_C) /* Tracking Filter type C */ { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_ControlWrite(fe, DAC_DIN_A, 0); - - if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - status += MXL_SetGPIO(fe, 3, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 1); - } - if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 4, 1); - } - if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 4, 0); - } - if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 0); - } - if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_ControlWrite(fe, DAC_DIN_B, 29); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 0); - } - if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 0); - } - if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_ControlWrite(fe, DAC_DIN_B, 16); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 1); - } - if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_ControlWrite(fe, DAC_DIN_B, 7); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 1); - } - if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 1); - } - } - - if (state->TF_Type == MXL_TF_C_H) { - - /* Tracking Filter type C-H for Hauppauge only */ - status += MXL_ControlWrite(fe, DAC_DIN_A, 0); - - if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - } - if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 3, 0); - status += MXL_SetGPIO(fe, 1, 1); - } - if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 3, 0); - status += MXL_SetGPIO(fe, 1, 0); - } - if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 0); - } - if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 0); - } - if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 0); - } - if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - } - if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - } - if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - } - } - - if (state->TF_Type == MXL_TF_D) { /* Tracking Filter type D */ - - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - - if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - } - - if (state->TF_Type == MXL_TF_D_L) { - - /* Tracking Filter type D-L for Lumanate ONLY change 2.6.3 */ - status += MXL_ControlWrite(fe, DAC_DIN_A, 0); - - /* if UHF and terrestrial => Turn off Tracking Filter */ - if (state->RF_IN >= 471000000 && - (state->RF_IN - 471000000)%6000000 != 0) { - /* Turn off all the banks */ - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_ControlWrite(fe, AGC_IF, 10); - } else { - /* if VHF or cable => Turn on Tracking Filter */ - if (state->RF_IN >= 43000000 && - state->RF_IN < 140000000) { - - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 140000000 && - state->RF_IN < 240000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 240000000 && - state->RF_IN < 340000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 340000000 && - state->RF_IN < 430000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 430000000 && - state->RF_IN < 470000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 470000000 && - state->RF_IN < 570000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 570000000 && - state->RF_IN < 620000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 620000000 && - state->RF_IN < 760000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 760000000 && - state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - } - } - - if (state->TF_Type == MXL_TF_E) /* Tracking Filter type E */ { - - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - - if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - } - - if (state->TF_Type == MXL_TF_F) { - - /* Tracking Filter type F */ - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - - if (state->RF_IN >= 43000000 && state->RF_IN < 160000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 160000000 && state->RF_IN < 210000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 210000000 && state->RF_IN < 300000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 300000000 && state->RF_IN < 390000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 390000000 && state->RF_IN < 515000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 515000000 && state->RF_IN < 650000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 650000000 && state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - } - - if (state->TF_Type == MXL_TF_E_2) { - - /* Tracking Filter type E_2 */ - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - - if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - } - - if (state->TF_Type == MXL_TF_G) { - - /* Tracking Filter type G add for v2.6.8 */ - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - - if (state->RF_IN >= 50000000 && state->RF_IN < 190000000) { - - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 190000000 && state->RF_IN < 280000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 280000000 && state->RF_IN < 350000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 400000000 && state->RF_IN < 470000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 640000000 && state->RF_IN < 820000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 820000000 && state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - } - - if (state->TF_Type == MXL_TF_E_NA) { - - /* Tracking Filter type E-NA for Empia ONLY change for 2.6.8 */ - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - - /* if UHF and terrestrial=> Turn off Tracking Filter */ - if (state->RF_IN >= 471000000 && - (state->RF_IN - 471000000)%6000000 != 0) { - - /* Turn off all the banks */ - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - - /* 2.6.12 Turn on RSSI */ - status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); - status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); - status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); - - /* RSSI reference point */ - status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); - status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); - status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); - - /* following parameter is from analog OTA mode, - * can be change to seek better performance */ - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); - } else { - /* if VHF or Cable => Turn on Tracking Filter */ - - /* 2.6.12 Turn off RSSI */ - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); - - /* change back from above condition */ - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5); - - - if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { - - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - } - } - return status ; -} - -static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val) -{ - u16 status = 0; - - if (GPIO_Num == 1) - status += MXL_ControlWrite(fe, GPIO_1B, GPIO_Val ? 0 : 1); - - /* GPIO2 is not available */ - - if (GPIO_Num == 3) { - if (GPIO_Val == 1) { - status += MXL_ControlWrite(fe, GPIO_3, 0); - status += MXL_ControlWrite(fe, GPIO_3B, 0); - } - if (GPIO_Val == 0) { - status += MXL_ControlWrite(fe, GPIO_3, 1); - status += MXL_ControlWrite(fe, GPIO_3B, 1); - } - if (GPIO_Val == 3) { /* tri-state */ - status += MXL_ControlWrite(fe, GPIO_3, 0); - status += MXL_ControlWrite(fe, GPIO_3B, 1); - } - } - if (GPIO_Num == 4) { - if (GPIO_Val == 1) { - status += MXL_ControlWrite(fe, GPIO_4, 0); - status += MXL_ControlWrite(fe, GPIO_4B, 0); - } - if (GPIO_Val == 0) { - status += MXL_ControlWrite(fe, GPIO_4, 1); - status += MXL_ControlWrite(fe, GPIO_4B, 1); - } - if (GPIO_Val == 3) { /* tri-state */ - status += MXL_ControlWrite(fe, GPIO_4, 0); - status += MXL_ControlWrite(fe, GPIO_4B, 1); - } - } - - return status; -} - -static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value) -{ - u16 status = 0; - - /* Will write ALL Matching Control Name */ - /* Write Matching INIT Control */ - status += MXL_ControlWrite_Group(fe, ControlNum, value, 1); - /* Write Matching CH Control */ - status += MXL_ControlWrite_Group(fe, ControlNum, value, 2); -#ifdef _MXL_INTERNAL - /* Write Matching MXL Control */ - status += MXL_ControlWrite_Group(fe, ControlNum, value, 3); -#endif - return status; -} - -static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, - u32 value, u16 controlGroup) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u16 i, j, k; - u32 highLimit; - u32 ctrlVal; - - if (controlGroup == 1) /* Initial Control */ { - - for (i = 0; i < state->Init_Ctrl_Num; i++) { - - if (controlNum == state->Init_Ctrl[i].Ctrl_Num) { - - highLimit = 1 << state->Init_Ctrl[i].size; - if (value < highLimit) { - for (j = 0; j < state->Init_Ctrl[i].size; j++) { - state->Init_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); - MXL_RegWriteBit(fe, (u8)(state->Init_Ctrl[i].addr[j]), - (u8)(state->Init_Ctrl[i].bit[j]), - (u8)((value>>j) & 0x01)); - } - ctrlVal = 0; - for (k = 0; k < state->Init_Ctrl[i].size; k++) - ctrlVal += state->Init_Ctrl[i].val[k] * (1 << k); - } else - return -1; - } - } - } - if (controlGroup == 2) /* Chan change Control */ { - - for (i = 0; i < state->CH_Ctrl_Num; i++) { - - if (controlNum == state->CH_Ctrl[i].Ctrl_Num) { - - highLimit = 1 << state->CH_Ctrl[i].size; - if (value < highLimit) { - for (j = 0; j < state->CH_Ctrl[i].size; j++) { - state->CH_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); - MXL_RegWriteBit(fe, (u8)(state->CH_Ctrl[i].addr[j]), - (u8)(state->CH_Ctrl[i].bit[j]), - (u8)((value>>j) & 0x01)); - } - ctrlVal = 0; - for (k = 0; k < state->CH_Ctrl[i].size; k++) - ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k); - } else - return -1; - } - } - } -#ifdef _MXL_INTERNAL - if (controlGroup == 3) /* Maxlinear Control */ { - - for (i = 0; i < state->MXL_Ctrl_Num; i++) { - - if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) { - - highLimit = (1 << state->MXL_Ctrl[i].size); - if (value < highLimit) { - for (j = 0; j < state->MXL_Ctrl[i].size; j++) { - state->MXL_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); - MXL_RegWriteBit(fe, (u8)(state->MXL_Ctrl[i].addr[j]), - (u8)(state->MXL_Ctrl[i].bit[j]), - (u8)((value>>j) & 0x01)); - } - ctrlVal = 0; - for (k = 0; k < state->MXL_Ctrl[i].size; k++) - ctrlVal += state-> - MXL_Ctrl[i].val[k] * - (1 << k); - } else - return -1; - } - } - } -#endif - return 0 ; /* successful return */ -} - -static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal) -{ - struct mxl5005s_state *state = fe->tuner_priv; - int i ; - - for (i = 0; i < 104; i++) { - if (RegNum == state->TunerRegs[i].Reg_Num) { - *RegVal = (u8)(state->TunerRegs[i].Reg_Val); - return 0; - } - } - - return 1; -} - -static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u32 ctrlVal ; - u16 i, k ; - - for (i = 0; i < state->Init_Ctrl_Num ; i++) { - - if (controlNum == state->Init_Ctrl[i].Ctrl_Num) { - - ctrlVal = 0; - for (k = 0; k < state->Init_Ctrl[i].size; k++) - ctrlVal += state->Init_Ctrl[i].val[k] * (1<CH_Ctrl_Num ; i++) { - - if (controlNum == state->CH_Ctrl[i].Ctrl_Num) { - - ctrlVal = 0; - for (k = 0; k < state->CH_Ctrl[i].size; k++) - ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k); - *value = ctrlVal; - return 0; - - } - } - -#ifdef _MXL_INTERNAL - for (i = 0; i < state->MXL_Ctrl_Num ; i++) { - - if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) { - - ctrlVal = 0; - for (k = 0; k < state->MXL_Ctrl[i].size; k++) - ctrlVal += state->MXL_Ctrl[i].val[k] * (1<tuner_priv; - int i ; - - const u8 AND_MAP[8] = { - 0xFE, 0xFD, 0xFB, 0xF7, - 0xEF, 0xDF, 0xBF, 0x7F } ; - - const u8 OR_MAP[8] = { - 0x01, 0x02, 0x04, 0x08, - 0x10, 0x20, 0x40, 0x80 } ; - - for (i = 0; i < state->TunerRegs_Num; i++) { - if (state->TunerRegs[i].Reg_Num == address) { - if (bitVal) - state->TunerRegs[i].Reg_Val |= OR_MAP[bit]; - else - state->TunerRegs[i].Reg_Val &= AND_MAP[bit]; - break ; - } - } -} - -static u32 MXL_Ceiling(u32 value, u32 resolution) -{ - return value / resolution + (value % resolution > 0 ? 1 : 0); -} - -/* Retrieve the Initialzation Registers */ -static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum, - u8 *RegVal, int *count) -{ - u16 status = 0; - int i ; - - u8 RegAddr[] = { - 11, 12, 13, 22, 32, 43, 44, 53, 56, 59, 73, - 76, 77, 91, 134, 135, 137, 147, - 156, 166, 167, 168, 25 }; - - *count = ARRAY_SIZE(RegAddr); - - status += MXL_BlockInit(fe); - - for (i = 0 ; i < *count; i++) { - RegNum[i] = RegAddr[i]; - status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); - } - - return status; -} - -static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal, - int *count) -{ - u16 status = 0; - int i ; - -/* add 77, 166, 167, 168 register for 2.6.12 */ -#ifdef _MXL_PRODUCTION - u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 65, 68, 69, 70, 73, 92, 93, 106, - 107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ; -#else - u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 68, 69, 70, 73, 92, 93, 106, - 107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ; - /* - u8 RegAddr[171]; - for (i = 0; i <= 170; i++) - RegAddr[i] = i; - */ -#endif - - *count = ARRAY_SIZE(RegAddr); - - for (i = 0 ; i < *count; i++) { - RegNum[i] = RegAddr[i]; - status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); - } - - return status; -} - -static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum, - u8 *RegVal, int *count) -{ - u16 status = 0; - int i; - - u8 RegAddr[] = {43, 136}; - - *count = ARRAY_SIZE(RegAddr); - - for (i = 0; i < *count; i++) { - RegNum[i] = RegAddr[i]; - status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); - } - - return status; -} - -static u16 MXL_GetMasterControl(u8 *MasterReg, int state) -{ - if (state == 1) /* Load_Start */ - *MasterReg = 0xF3; - if (state == 2) /* Power_Down */ - *MasterReg = 0x41; - if (state == 3) /* Synth_Reset */ - *MasterReg = 0xB1; - if (state == 4) /* Seq_Off */ - *MasterReg = 0xF1; - - return 0; -} - -#ifdef _MXL_PRODUCTION -static u16 MXL_VCORange_Test(struct dvb_frontend *fe, int VCO_Range) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u16 status = 0 ; - - if (VCO_Range == 1) { - status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); - if (state->Mode == 0 && state->IF_Mode == 1) { - /* Analog Low IF Mode */ - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 180224); - } - if (state->Mode == 0 && state->IF_Mode == 0) { - /* Analog Zero IF Mode */ - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 222822); - } - if (state->Mode == 1) /* Digital Mode */ { - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 229376); - } - } - - if (VCO_Range == 2) { - status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41); - if (state->Mode == 0 && state->IF_Mode == 1) { - /* Analog Low IF Mode */ - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 206438); - } - if (state->Mode == 0 && state->IF_Mode == 0) { - /* Analog Zero IF Mode */ - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 206438); - } - if (state->Mode == 1) /* Digital Mode */ { - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 16384); - } - } - - if (VCO_Range == 3) { - status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); - if (state->Mode == 0 && state->IF_Mode == 1) { - /* Analog Low IF Mode */ - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 173670); - } - if (state->Mode == 0 && state->IF_Mode == 0) { - /* Analog Zero IF Mode */ - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 173670); - } - if (state->Mode == 1) /* Digital Mode */ { - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 245760); - } - } - - if (VCO_Range == 4) { - status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); - if (state->Mode == 0 && state->IF_Mode == 1) { - /* Analog Low IF Mode */ - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 206438); - } - if (state->Mode == 0 && state->IF_Mode == 0) { - /* Analog Zero IF Mode */ - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 206438); - } - if (state->Mode == 1) /* Digital Mode */ { - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 212992); - } - } - - return status; -} - -static u16 MXL_Hystersis_Test(struct dvb_frontend *fe, int Hystersis) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u16 status = 0; - - if (Hystersis == 1) - status += MXL_ControlWrite(fe, DN_BYPASS_AGC_I2C, 1); - - return status; -} -#endif -/* End: Reference driver code found in the Realtek driver that - * is copyright MaxLinear */ - -/* ---------------------------------------------------------------- - * Begin: Everything after here is new code to adapt the - * proprietary Realtek driver into a Linux API tuner. - * Copyright (C) 2008 Steven Toth - */ -static int mxl5005s_reset(struct dvb_frontend *fe) -{ - struct mxl5005s_state *state = fe->tuner_priv; - int ret = 0; - - u8 buf[2] = { 0xff, 0x00 }; - struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0, - .buf = buf, .len = 2 }; - - dprintk(2, "%s()\n", __func__); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (i2c_transfer(state->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "mxl5005s I2C reset failed\n"); - ret = -EREMOTEIO; - } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return ret; -} - -/* Write a single byte to a single reg, latch the value if required by - * following the transaction with the latch byte. - */ -static int mxl5005s_writereg(struct dvb_frontend *fe, u8 reg, u8 val, int latch) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u8 buf[3] = { reg, val, MXL5005S_LATCH_BYTE }; - struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0, - .buf = buf, .len = 3 }; - - if (latch == 0) - msg.len = 2; - - dprintk(2, "%s(0x%x, 0x%x, 0x%x)\n", __func__, reg, val, msg.addr); - - if (i2c_transfer(state->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "mxl5005s I2C write failed\n"); - return -EREMOTEIO; - } - return 0; -} - -static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable, - u8 *datatable, u8 len) -{ - int ret = 0, i; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - for (i = 0 ; i < len-1; i++) { - ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 0); - if (ret < 0) - break; - } - - ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 1); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return ret; -} - -static int mxl5005s_init(struct dvb_frontend *fe) -{ - struct mxl5005s_state *state = fe->tuner_priv; - - dprintk(1, "%s()\n", __func__); - state->current_mode = MXL_QAM; - return mxl5005s_reconfigure(fe, MXL_QAM, MXL5005S_BANDWIDTH_6MHZ); -} - -static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type, - u32 bandwidth) -{ - struct mxl5005s_state *state = fe->tuner_priv; - - u8 AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; - u8 ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; - int TableLen; - - dprintk(1, "%s(type=%d, bw=%d)\n", __func__, mod_type, bandwidth); - - mxl5005s_reset(fe); - - /* Tuner initialization stage 0 */ - MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET); - AddrTable[0] = MASTER_CONTROL_ADDR; - ByteTable[0] |= state->config->AgcMasterByte; - - mxl5005s_writeregs(fe, AddrTable, ByteTable, 1); - - mxl5005s_AssignTunerMode(fe, mod_type, bandwidth); - - /* Tuner initialization stage 1 */ - MXL_GetInitRegister(fe, AddrTable, ByteTable, &TableLen); - - mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); - - return 0; -} - -static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type, - u32 bandwidth) -{ - struct mxl5005s_state *state = fe->tuner_priv; - struct mxl5005s_config *c = state->config; - - InitTunerControls(fe); - - /* Set MxL5005S parameters. */ - MXL5005_TunerConfig( - fe, - c->mod_mode, - c->if_mode, - bandwidth, - c->if_freq, - c->xtal_freq, - c->agc_mode, - c->top, - c->output_load, - c->clock_out, - c->div_out, - c->cap_select, - c->rssi_enable, - mod_type, - c->tracking_filter); - - return 0; -} - -static int mxl5005s_set_params(struct dvb_frontend *fe) -{ - struct mxl5005s_state *state = fe->tuner_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u32 delsys = c->delivery_system; - u32 bw = c->bandwidth_hz; - u32 req_mode, req_bw = 0; - int ret; - - dprintk(1, "%s()\n", __func__); - - switch (delsys) { - case SYS_ATSC: - req_mode = MXL_ATSC; - req_bw = MXL5005S_BANDWIDTH_6MHZ; - break; - case SYS_DVBC_ANNEX_B: - req_mode = MXL_QAM; - req_bw = MXL5005S_BANDWIDTH_6MHZ; - break; - default: /* Assume DVB-T */ - req_mode = MXL_DVBT; - switch (bw) { - case 6000000: - req_bw = MXL5005S_BANDWIDTH_6MHZ; - break; - case 7000000: - req_bw = MXL5005S_BANDWIDTH_7MHZ; - break; - case 8000000: - case 0: - req_bw = MXL5005S_BANDWIDTH_8MHZ; - break; - default: - return -EINVAL; - } - } - - /* Change tuner for new modulation type if reqd */ - if (req_mode != state->current_mode || - req_bw != state->Chan_Bandwidth) { - state->current_mode = req_mode; - ret = mxl5005s_reconfigure(fe, req_mode, req_bw); - - } else - ret = 0; - - if (ret == 0) { - dprintk(1, "%s() freq=%d\n", __func__, c->frequency); - ret = mxl5005s_SetRfFreqHz(fe, c->frequency); - } - - return ret; -} - -static int mxl5005s_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct mxl5005s_state *state = fe->tuner_priv; - dprintk(1, "%s()\n", __func__); - - *frequency = state->RF_IN; - - return 0; -} - -static int mxl5005s_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct mxl5005s_state *state = fe->tuner_priv; - dprintk(1, "%s()\n", __func__); - - *bandwidth = state->Chan_Bandwidth; - - return 0; -} - -static int mxl5005s_release(struct dvb_frontend *fe) -{ - dprintk(1, "%s()\n", __func__); - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static const struct dvb_tuner_ops mxl5005s_tuner_ops = { - .info = { - .name = "MaxLinear MXL5005S", - .frequency_min = 48000000, - .frequency_max = 860000000, - .frequency_step = 50000, - }, - - .release = mxl5005s_release, - .init = mxl5005s_init, - - .set_params = mxl5005s_set_params, - .get_frequency = mxl5005s_get_frequency, - .get_bandwidth = mxl5005s_get_bandwidth, -}; - -struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct mxl5005s_config *config) -{ - struct mxl5005s_state *state = NULL; - dprintk(1, "%s()\n", __func__); - - state = kzalloc(sizeof(struct mxl5005s_state), GFP_KERNEL); - if (state == NULL) - return NULL; - - state->frontend = fe; - state->config = config; - state->i2c = i2c; - - printk(KERN_INFO "MXL5005S: Attached at address 0x%02x\n", - config->i2c_address); - - memcpy(&fe->ops.tuner_ops, &mxl5005s_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = state; - return fe; -} -EXPORT_SYMBOL(mxl5005s_attach); - -MODULE_DESCRIPTION("MaxLinear MXL5005S silicon tuner driver"); -MODULE_AUTHOR("Steven Toth"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/mxl5005s.h b/drivers/media/common/tuners/mxl5005s.h deleted file mode 100644 index fc8a1ffc53b4..000000000000 --- a/drivers/media/common/tuners/mxl5005s.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - MaxLinear MXL5005S VSB/QAM/DVBT tuner driver - - Copyright (C) 2008 MaxLinear - Copyright (C) 2008 Steven Toth - - 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 __MXL5005S_H -#define __MXL5005S_H - -#include -#include "dvb_frontend.h" - -struct mxl5005s_config { - - /* 7 bit i2c address */ - u8 i2c_address; - -#define IF_FREQ_4570000HZ 4570000 -#define IF_FREQ_4571429HZ 4571429 -#define IF_FREQ_5380000HZ 5380000 -#define IF_FREQ_36000000HZ 36000000 -#define IF_FREQ_36125000HZ 36125000 -#define IF_FREQ_36166667HZ 36166667 -#define IF_FREQ_44000000HZ 44000000 - u32 if_freq; - -#define CRYSTAL_FREQ_4000000HZ 4000000 -#define CRYSTAL_FREQ_16000000HZ 16000000 -#define CRYSTAL_FREQ_25000000HZ 25000000 -#define CRYSTAL_FREQ_28800000HZ 28800000 - u32 xtal_freq; - -#define MXL_DUAL_AGC 0 -#define MXL_SINGLE_AGC 1 - u8 agc_mode; - -#define MXL_TF_DEFAULT 0 -#define MXL_TF_OFF 1 -#define MXL_TF_C 2 -#define MXL_TF_C_H 3 -#define MXL_TF_D 4 -#define MXL_TF_D_L 5 -#define MXL_TF_E 6 -#define MXL_TF_F 7 -#define MXL_TF_E_2 8 -#define MXL_TF_E_NA 9 -#define MXL_TF_G 10 - u8 tracking_filter; - -#define MXL_RSSI_DISABLE 0 -#define MXL_RSSI_ENABLE 1 - u8 rssi_enable; - -#define MXL_CAP_SEL_DISABLE 0 -#define MXL_CAP_SEL_ENABLE 1 - u8 cap_select; - -#define MXL_DIV_OUT_1 0 -#define MXL_DIV_OUT_4 1 - u8 div_out; - -#define MXL_CLOCK_OUT_DISABLE 0 -#define MXL_CLOCK_OUT_ENABLE 1 - u8 clock_out; - -#define MXL5005S_IF_OUTPUT_LOAD_200_OHM 200 -#define MXL5005S_IF_OUTPUT_LOAD_300_OHM 300 - u32 output_load; - -#define MXL5005S_TOP_5P5 55 -#define MXL5005S_TOP_7P2 72 -#define MXL5005S_TOP_9P2 92 -#define MXL5005S_TOP_11P0 110 -#define MXL5005S_TOP_12P9 129 -#define MXL5005S_TOP_14P7 147 -#define MXL5005S_TOP_16P8 168 -#define MXL5005S_TOP_19P4 194 -#define MXL5005S_TOP_21P2 212 -#define MXL5005S_TOP_23P2 232 -#define MXL5005S_TOP_25P2 252 -#define MXL5005S_TOP_27P1 271 -#define MXL5005S_TOP_29P2 292 -#define MXL5005S_TOP_31P7 317 -#define MXL5005S_TOP_34P9 349 - u32 top; - -#define MXL_ANALOG_MODE 0 -#define MXL_DIGITAL_MODE 1 - u8 mod_mode; - -#define MXL_ZERO_IF 0 -#define MXL_LOW_IF 1 - u8 if_mode; - - /* Some boards need to override the built-in logic for determining - the gain when in QAM mode (the HVR-1600 is one such case) */ - u8 qam_gain; - - /* Stuff I don't know what to do with */ - u8 AgcMasterByte; -}; - -#if defined(CONFIG_MEDIA_TUNER_MXL5005S) || \ - (defined(CONFIG_MEDIA_TUNER_MXL5005S_MODULE) && defined(MODULE)) -extern struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct mxl5005s_config *config); -#else -static inline struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct mxl5005s_config *config) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_TUNER_MXL5005S */ - -#endif /* __MXL5005S_H */ - diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/common/tuners/mxl5007t.c deleted file mode 100644 index 69e453ef0a1a..000000000000 --- a/drivers/media/common/tuners/mxl5007t.c +++ /dev/null @@ -1,928 +0,0 @@ -/* - * mxl5007t.c - driver for the MaxLinear MxL5007T silicon tuner - * - * Copyright (C) 2008, 2009 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 -#include -#include -#include "tuner-i2c.h" -#include "mxl5007t.h" - -static DEFINE_MUTEX(mxl5007t_list_mutex); -static LIST_HEAD(hybrid_tuner_instance_list); - -static int mxl5007t_debug; -module_param_named(debug, mxl5007t_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debug level"); - -/* ------------------------------------------------------------------------- */ - -#define mxl_printk(kern, fmt, arg...) \ - printk(kern "%s: " fmt "\n", __func__, ##arg) - -#define mxl_err(fmt, arg...) \ - mxl_printk(KERN_ERR, "%d: " fmt, __LINE__, ##arg) - -#define mxl_warn(fmt, arg...) \ - mxl_printk(KERN_WARNING, fmt, ##arg) - -#define mxl_info(fmt, arg...) \ - mxl_printk(KERN_INFO, fmt, ##arg) - -#define mxl_debug(fmt, arg...) \ -({ \ - if (mxl5007t_debug) \ - mxl_printk(KERN_DEBUG, fmt, ##arg); \ -}) - -#define mxl_fail(ret) \ -({ \ - int __ret; \ - __ret = (ret < 0); \ - if (__ret) \ - mxl_printk(KERN_ERR, "error %d on line %d", \ - ret, __LINE__); \ - __ret; \ -}) - -/* ------------------------------------------------------------------------- */ - -#define MHz 1000000 - -enum mxl5007t_mode { - MxL_MODE_ISDBT = 0, - MxL_MODE_DVBT = 1, - MxL_MODE_ATSC = 2, - MxL_MODE_CABLE = 0x10, -}; - -enum mxl5007t_chip_version { - MxL_UNKNOWN_ID = 0x00, - MxL_5007_V1_F1 = 0x11, - MxL_5007_V1_F2 = 0x12, - MxL_5007_V4 = 0x14, - MxL_5007_V2_100_F1 = 0x21, - MxL_5007_V2_100_F2 = 0x22, - MxL_5007_V2_200_F1 = 0x23, - MxL_5007_V2_200_F2 = 0x24, -}; - -struct reg_pair_t { - u8 reg; - u8 val; -}; - -/* ------------------------------------------------------------------------- */ - -static struct reg_pair_t init_tab[] = { - { 0x02, 0x06 }, - { 0x03, 0x48 }, - { 0x05, 0x04 }, - { 0x06, 0x10 }, - { 0x2e, 0x15 }, /* OVERRIDE */ - { 0x30, 0x10 }, /* OVERRIDE */ - { 0x45, 0x58 }, /* OVERRIDE */ - { 0x48, 0x19 }, /* OVERRIDE */ - { 0x52, 0x03 }, /* OVERRIDE */ - { 0x53, 0x44 }, /* OVERRIDE */ - { 0x6a, 0x4b }, /* OVERRIDE */ - { 0x76, 0x00 }, /* OVERRIDE */ - { 0x78, 0x18 }, /* OVERRIDE */ - { 0x7a, 0x17 }, /* OVERRIDE */ - { 0x85, 0x06 }, /* OVERRIDE */ - { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ - { 0, 0 } -}; - -static struct reg_pair_t init_tab_cable[] = { - { 0x02, 0x06 }, - { 0x03, 0x48 }, - { 0x05, 0x04 }, - { 0x06, 0x10 }, - { 0x09, 0x3f }, - { 0x0a, 0x3f }, - { 0x0b, 0x3f }, - { 0x2e, 0x15 }, /* OVERRIDE */ - { 0x30, 0x10 }, /* OVERRIDE */ - { 0x45, 0x58 }, /* OVERRIDE */ - { 0x48, 0x19 }, /* OVERRIDE */ - { 0x52, 0x03 }, /* OVERRIDE */ - { 0x53, 0x44 }, /* OVERRIDE */ - { 0x6a, 0x4b }, /* OVERRIDE */ - { 0x76, 0x00 }, /* OVERRIDE */ - { 0x78, 0x18 }, /* OVERRIDE */ - { 0x7a, 0x17 }, /* OVERRIDE */ - { 0x85, 0x06 }, /* OVERRIDE */ - { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ - { 0, 0 } -}; - -/* ------------------------------------------------------------------------- */ - -static struct reg_pair_t reg_pair_rftune[] = { - { 0x0f, 0x00 }, /* abort tune */ - { 0x0c, 0x15 }, - { 0x0d, 0x40 }, - { 0x0e, 0x0e }, - { 0x1f, 0x87 }, /* OVERRIDE */ - { 0x20, 0x1f }, /* OVERRIDE */ - { 0x21, 0x87 }, /* OVERRIDE */ - { 0x22, 0x1f }, /* OVERRIDE */ - { 0x80, 0x01 }, /* freq dependent */ - { 0x0f, 0x01 }, /* start tune */ - { 0, 0 } -}; - -/* ------------------------------------------------------------------------- */ - -struct mxl5007t_state { - struct list_head hybrid_tuner_instance_list; - struct tuner_i2c_props i2c_props; - - struct mutex lock; - - struct mxl5007t_config *config; - - enum mxl5007t_chip_version chip_id; - - struct reg_pair_t tab_init[ARRAY_SIZE(init_tab)]; - struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)]; - struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)]; - - enum mxl5007t_if_freq if_freq; - - u32 frequency; - u32 bandwidth; -}; - -/* ------------------------------------------------------------------------- */ - -/* called by _init and _rftun to manipulate the register arrays */ - -static void set_reg_bits(struct reg_pair_t *reg_pair, u8 reg, u8 mask, u8 val) -{ - unsigned int i = 0; - - while (reg_pair[i].reg || reg_pair[i].val) { - if (reg_pair[i].reg == reg) { - reg_pair[i].val &= ~mask; - reg_pair[i].val |= val; - } - i++; - - } - return; -} - -static void copy_reg_bits(struct reg_pair_t *reg_pair1, - struct reg_pair_t *reg_pair2) -{ - unsigned int i, j; - - i = j = 0; - - while (reg_pair1[i].reg || reg_pair1[i].val) { - while (reg_pair2[j].reg || reg_pair2[j].val) { - if (reg_pair1[i].reg != reg_pair2[j].reg) { - j++; - continue; - } - reg_pair2[j].val = reg_pair1[i].val; - break; - } - i++; - } - return; -} - -/* ------------------------------------------------------------------------- */ - -static void mxl5007t_set_mode_bits(struct mxl5007t_state *state, - enum mxl5007t_mode mode, - s32 if_diff_out_level) -{ - switch (mode) { - case MxL_MODE_ATSC: - set_reg_bits(state->tab_init, 0x06, 0x1f, 0x12); - break; - case MxL_MODE_DVBT: - set_reg_bits(state->tab_init, 0x06, 0x1f, 0x11); - break; - case MxL_MODE_ISDBT: - set_reg_bits(state->tab_init, 0x06, 0x1f, 0x10); - break; - case MxL_MODE_CABLE: - set_reg_bits(state->tab_init_cable, 0x09, 0xff, 0xc1); - set_reg_bits(state->tab_init_cable, 0x0a, 0xff, - 8 - if_diff_out_level); - set_reg_bits(state->tab_init_cable, 0x0b, 0xff, 0x17); - break; - default: - mxl_fail(-EINVAL); - } - return; -} - -static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state, - enum mxl5007t_if_freq if_freq, - int invert_if) -{ - u8 val; - - switch (if_freq) { - case MxL_IF_4_MHZ: - val = 0x00; - break; - case MxL_IF_4_5_MHZ: - val = 0x02; - break; - case MxL_IF_4_57_MHZ: - val = 0x03; - break; - case MxL_IF_5_MHZ: - val = 0x04; - break; - case MxL_IF_5_38_MHZ: - val = 0x05; - break; - case MxL_IF_6_MHZ: - val = 0x06; - break; - case MxL_IF_6_28_MHZ: - val = 0x07; - break; - case MxL_IF_9_1915_MHZ: - val = 0x08; - break; - case MxL_IF_35_25_MHZ: - val = 0x09; - break; - case MxL_IF_36_15_MHZ: - val = 0x0a; - break; - case MxL_IF_44_MHZ: - val = 0x0b; - break; - default: - mxl_fail(-EINVAL); - return; - } - set_reg_bits(state->tab_init, 0x02, 0x0f, val); - - /* set inverted IF or normal IF */ - set_reg_bits(state->tab_init, 0x02, 0x10, invert_if ? 0x10 : 0x00); - - state->if_freq = if_freq; - - return; -} - -static void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state, - enum mxl5007t_xtal_freq xtal_freq) -{ - switch (xtal_freq) { - case MxL_XTAL_16_MHZ: - /* select xtal freq & ref freq */ - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x00); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x00); - break; - case MxL_XTAL_20_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x10); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x01); - break; - case MxL_XTAL_20_25_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x20); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x02); - break; - case MxL_XTAL_20_48_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x30); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x03); - break; - case MxL_XTAL_24_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x40); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x04); - break; - case MxL_XTAL_25_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x50); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x05); - break; - case MxL_XTAL_25_14_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x60); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x06); - break; - case MxL_XTAL_27_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x70); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x07); - break; - case MxL_XTAL_28_8_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x80); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x08); - break; - case MxL_XTAL_32_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x90); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x09); - break; - case MxL_XTAL_40_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0xa0); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0a); - break; - case MxL_XTAL_44_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0xb0); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0b); - break; - case MxL_XTAL_48_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0xc0); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0c); - break; - case MxL_XTAL_49_3811_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0xd0); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0d); - break; - default: - mxl_fail(-EINVAL); - return; - } - - return; -} - -static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state, - enum mxl5007t_mode mode) -{ - struct mxl5007t_config *cfg = state->config; - - memcpy(&state->tab_init, &init_tab, sizeof(init_tab)); - memcpy(&state->tab_init_cable, &init_tab_cable, sizeof(init_tab_cable)); - - mxl5007t_set_mode_bits(state, mode, cfg->if_diff_out_level); - mxl5007t_set_if_freq_bits(state, cfg->if_freq_hz, cfg->invert_if); - mxl5007t_set_xtal_freq_bits(state, cfg->xtal_freq_hz); - - set_reg_bits(state->tab_init, 0x04, 0x01, cfg->loop_thru_enable); - set_reg_bits(state->tab_init, 0x03, 0x08, cfg->clk_out_enable << 3); - set_reg_bits(state->tab_init, 0x03, 0x07, cfg->clk_out_amp); - - if (mode >= MxL_MODE_CABLE) { - copy_reg_bits(state->tab_init, state->tab_init_cable); - return state->tab_init_cable; - } else - return state->tab_init; -} - -/* ------------------------------------------------------------------------- */ - -enum mxl5007t_bw_mhz { - MxL_BW_6MHz = 6, - MxL_BW_7MHz = 7, - MxL_BW_8MHz = 8, -}; - -static void mxl5007t_set_bw_bits(struct mxl5007t_state *state, - enum mxl5007t_bw_mhz bw) -{ - u8 val; - - switch (bw) { - case MxL_BW_6MHz: - val = 0x15; /* set DIG_MODEINDEX, DIG_MODEINDEX_A, - * and DIG_MODEINDEX_CSF */ - break; - case MxL_BW_7MHz: - val = 0x2a; - break; - case MxL_BW_8MHz: - val = 0x3f; - break; - default: - mxl_fail(-EINVAL); - return; - } - set_reg_bits(state->tab_rftune, 0x0c, 0x3f, val); - - return; -} - -static struct -reg_pair_t *mxl5007t_calc_rf_tune_regs(struct mxl5007t_state *state, - u32 rf_freq, enum mxl5007t_bw_mhz bw) -{ - u32 dig_rf_freq = 0; - u32 temp; - u32 frac_divider = 1000000; - unsigned int i; - - memcpy(&state->tab_rftune, ®_pair_rftune, sizeof(reg_pair_rftune)); - - mxl5007t_set_bw_bits(state, bw); - - /* Convert RF frequency into 16 bits => - * 10 bit integer (MHz) + 6 bit fraction */ - dig_rf_freq = rf_freq / MHz; - - temp = rf_freq % MHz; - - for (i = 0; i < 6; i++) { - dig_rf_freq <<= 1; - frac_divider /= 2; - if (temp > frac_divider) { - temp -= frac_divider; - dig_rf_freq++; - } - } - - /* add to have shift center point by 7.8124 kHz */ - if (temp > 7812) - dig_rf_freq++; - - set_reg_bits(state->tab_rftune, 0x0d, 0xff, (u8) dig_rf_freq); - set_reg_bits(state->tab_rftune, 0x0e, 0xff, (u8) (dig_rf_freq >> 8)); - - if (rf_freq >= 333000000) - set_reg_bits(state->tab_rftune, 0x80, 0x40, 0x40); - - return state->tab_rftune; -} - -/* ------------------------------------------------------------------------- */ - -static int mxl5007t_write_reg(struct mxl5007t_state *state, u8 reg, u8 val) -{ - u8 buf[] = { reg, val }; - struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0, - .buf = buf, .len = 2 }; - int ret; - - ret = i2c_transfer(state->i2c_props.adap, &msg, 1); - if (ret != 1) { - mxl_err("failed!"); - return -EREMOTEIO; - } - return 0; -} - -static int mxl5007t_write_regs(struct mxl5007t_state *state, - struct reg_pair_t *reg_pair) -{ - unsigned int i = 0; - int ret = 0; - - while ((ret == 0) && (reg_pair[i].reg || reg_pair[i].val)) { - ret = mxl5007t_write_reg(state, - reg_pair[i].reg, reg_pair[i].val); - i++; - } - return ret; -} - -static int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val) -{ - u8 buf[2] = { 0xfb, reg }; - struct i2c_msg msg[] = { - { .addr = state->i2c_props.addr, .flags = 0, - .buf = buf, .len = 2 }, - { .addr = state->i2c_props.addr, .flags = I2C_M_RD, - .buf = val, .len = 1 }, - }; - int ret; - - ret = i2c_transfer(state->i2c_props.adap, msg, 2); - if (ret != 2) { - mxl_err("failed!"); - return -EREMOTEIO; - } - return 0; -} - -static int mxl5007t_soft_reset(struct mxl5007t_state *state) -{ - u8 d = 0xff; - struct i2c_msg msg = { - .addr = state->i2c_props.addr, .flags = 0, - .buf = &d, .len = 1 - }; - int ret = i2c_transfer(state->i2c_props.adap, &msg, 1); - - if (ret != 1) { - mxl_err("failed!"); - return -EREMOTEIO; - } - return 0; -} - -static int mxl5007t_tuner_init(struct mxl5007t_state *state, - enum mxl5007t_mode mode) -{ - struct reg_pair_t *init_regs; - int ret; - - ret = mxl5007t_soft_reset(state); - if (mxl_fail(ret)) - goto fail; - - /* calculate initialization reg array */ - init_regs = mxl5007t_calc_init_regs(state, mode); - - ret = mxl5007t_write_regs(state, init_regs); - if (mxl_fail(ret)) - goto fail; - mdelay(1); -fail: - return ret; -} - -static int mxl5007t_tuner_rf_tune(struct mxl5007t_state *state, u32 rf_freq_hz, - enum mxl5007t_bw_mhz bw) -{ - struct reg_pair_t *rf_tune_regs; - int ret; - - /* calculate channel change reg array */ - rf_tune_regs = mxl5007t_calc_rf_tune_regs(state, rf_freq_hz, bw); - - ret = mxl5007t_write_regs(state, rf_tune_regs); - if (mxl_fail(ret)) - goto fail; - msleep(3); -fail: - return ret; -} - -/* ------------------------------------------------------------------------- */ - -static int mxl5007t_synth_lock_status(struct mxl5007t_state *state, - int *rf_locked, int *ref_locked) -{ - u8 d; - int ret; - - *rf_locked = 0; - *ref_locked = 0; - - ret = mxl5007t_read_reg(state, 0xd8, &d); - if (mxl_fail(ret)) - goto fail; - - if ((d & 0x0c) == 0x0c) - *rf_locked = 1; - - if ((d & 0x03) == 0x03) - *ref_locked = 1; -fail: - return ret; -} - -/* ------------------------------------------------------------------------- */ - -static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct mxl5007t_state *state = fe->tuner_priv; - int rf_locked, ref_locked, ret; - - *status = 0; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - ret = mxl5007t_synth_lock_status(state, &rf_locked, &ref_locked); - if (mxl_fail(ret)) - goto fail; - mxl_debug("%s%s", rf_locked ? "rf locked " : "", - ref_locked ? "ref locked" : ""); - - if ((rf_locked) || (ref_locked)) - *status |= TUNER_STATUS_LOCKED; -fail: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return ret; -} - -/* ------------------------------------------------------------------------- */ - -static int mxl5007t_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u32 delsys = c->delivery_system; - struct mxl5007t_state *state = fe->tuner_priv; - enum mxl5007t_bw_mhz bw; - enum mxl5007t_mode mode; - int ret; - u32 freq = c->frequency; - - switch (delsys) { - case SYS_ATSC: - mode = MxL_MODE_ATSC; - bw = MxL_BW_6MHz; - break; - case SYS_DVBC_ANNEX_B: - mode = MxL_MODE_CABLE; - bw = MxL_BW_6MHz; - break; - case SYS_DVBT: - case SYS_DVBT2: - mode = MxL_MODE_DVBT; - switch (c->bandwidth_hz) { - case 6000000: - bw = MxL_BW_6MHz; - break; - case 7000000: - bw = MxL_BW_7MHz; - break; - case 8000000: - bw = MxL_BW_8MHz; - break; - default: - return -EINVAL; - } - break; - default: - mxl_err("modulation type not supported!"); - return -EINVAL; - } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - mutex_lock(&state->lock); - - ret = mxl5007t_tuner_init(state, mode); - if (mxl_fail(ret)) - goto fail; - - ret = mxl5007t_tuner_rf_tune(state, freq, bw); - if (mxl_fail(ret)) - goto fail; - - state->frequency = freq; - state->bandwidth = c->bandwidth_hz; -fail: - mutex_unlock(&state->lock); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return ret; -} - -/* ------------------------------------------------------------------------- */ - -static int mxl5007t_init(struct dvb_frontend *fe) -{ - struct mxl5007t_state *state = fe->tuner_priv; - int ret; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - /* wake from standby */ - ret = mxl5007t_write_reg(state, 0x01, 0x01); - mxl_fail(ret); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return ret; -} - -static int mxl5007t_sleep(struct dvb_frontend *fe) -{ - struct mxl5007t_state *state = fe->tuner_priv; - int ret; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - /* enter standby mode */ - ret = mxl5007t_write_reg(state, 0x01, 0x00); - mxl_fail(ret); - ret = mxl5007t_write_reg(state, 0x0f, 0x00); - mxl_fail(ret); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return ret; -} - -/* ------------------------------------------------------------------------- */ - -static int mxl5007t_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct mxl5007t_state *state = fe->tuner_priv; - *frequency = state->frequency; - return 0; -} - -static int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct mxl5007t_state *state = fe->tuner_priv; - *bandwidth = state->bandwidth; - return 0; -} - -static int mxl5007t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct mxl5007t_state *state = fe->tuner_priv; - - *frequency = 0; - - switch (state->if_freq) { - case MxL_IF_4_MHZ: - *frequency = 4000000; - break; - case MxL_IF_4_5_MHZ: - *frequency = 4500000; - break; - case MxL_IF_4_57_MHZ: - *frequency = 4570000; - break; - case MxL_IF_5_MHZ: - *frequency = 5000000; - break; - case MxL_IF_5_38_MHZ: - *frequency = 5380000; - break; - case MxL_IF_6_MHZ: - *frequency = 6000000; - break; - case MxL_IF_6_28_MHZ: - *frequency = 6280000; - break; - case MxL_IF_9_1915_MHZ: - *frequency = 9191500; - break; - case MxL_IF_35_25_MHZ: - *frequency = 35250000; - break; - case MxL_IF_36_15_MHZ: - *frequency = 36150000; - break; - case MxL_IF_44_MHZ: - *frequency = 44000000; - break; - } - return 0; -} - -static int mxl5007t_release(struct dvb_frontend *fe) -{ - struct mxl5007t_state *state = fe->tuner_priv; - - mutex_lock(&mxl5007t_list_mutex); - - if (state) - hybrid_tuner_release_state(state); - - mutex_unlock(&mxl5007t_list_mutex); - - fe->tuner_priv = NULL; - - return 0; -} - -/* ------------------------------------------------------------------------- */ - -static struct dvb_tuner_ops mxl5007t_tuner_ops = { - .info = { - .name = "MaxLinear MxL5007T", - }, - .init = mxl5007t_init, - .sleep = mxl5007t_sleep, - .set_params = mxl5007t_set_params, - .get_status = mxl5007t_get_status, - .get_frequency = mxl5007t_get_frequency, - .get_bandwidth = mxl5007t_get_bandwidth, - .release = mxl5007t_release, - .get_if_frequency = mxl5007t_get_if_frequency, -}; - -static int mxl5007t_get_chip_id(struct mxl5007t_state *state) -{ - char *name; - int ret; - u8 id; - - ret = mxl5007t_read_reg(state, 0xd9, &id); - if (mxl_fail(ret)) - goto fail; - - switch (id) { - case MxL_5007_V1_F1: - name = "MxL5007.v1.f1"; - break; - case MxL_5007_V1_F2: - name = "MxL5007.v1.f2"; - break; - case MxL_5007_V2_100_F1: - name = "MxL5007.v2.100.f1"; - break; - case MxL_5007_V2_100_F2: - name = "MxL5007.v2.100.f2"; - break; - case MxL_5007_V2_200_F1: - name = "MxL5007.v2.200.f1"; - break; - case MxL_5007_V2_200_F2: - name = "MxL5007.v2.200.f2"; - break; - case MxL_5007_V4: - name = "MxL5007T.v4"; - break; - default: - name = "MxL5007T"; - printk(KERN_WARNING "%s: unknown rev (%02x)\n", __func__, id); - id = MxL_UNKNOWN_ID; - } - state->chip_id = id; - mxl_info("%s detected @ %d-%04x", name, - i2c_adapter_id(state->i2c_props.adap), - state->i2c_props.addr); - return 0; -fail: - mxl_warn("unable to identify device @ %d-%04x", - i2c_adapter_id(state->i2c_props.adap), - state->i2c_props.addr); - - state->chip_id = MxL_UNKNOWN_ID; - return ret; -} - -struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, u8 addr, - struct mxl5007t_config *cfg) -{ - struct mxl5007t_state *state = NULL; - int instance, ret; - - mutex_lock(&mxl5007t_list_mutex); - instance = hybrid_tuner_request_state(struct mxl5007t_state, state, - hybrid_tuner_instance_list, - i2c, addr, "mxl5007t"); - switch (instance) { - case 0: - goto fail; - case 1: - /* new tuner instance */ - state->config = cfg; - - mutex_init(&state->lock); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - ret = mxl5007t_get_chip_id(state); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - /* check return value of mxl5007t_get_chip_id */ - if (mxl_fail(ret)) - goto fail; - break; - default: - /* existing tuner instance */ - break; - } - fe->tuner_priv = state; - mutex_unlock(&mxl5007t_list_mutex); - - memcpy(&fe->ops.tuner_ops, &mxl5007t_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - return fe; -fail: - mutex_unlock(&mxl5007t_list_mutex); - - mxl5007t_release(fe); - return NULL; -} -EXPORT_SYMBOL_GPL(mxl5007t_attach); -MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver"); -MODULE_AUTHOR("Michael Krufky "); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.2"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/common/tuners/mxl5007t.h b/drivers/media/common/tuners/mxl5007t.h deleted file mode 100644 index aa3eea0b5262..000000000000 --- a/drivers/media/common/tuners/mxl5007t.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * mxl5007t.h - driver for the MaxLinear MxL5007T silicon tuner - * - * Copyright (C) 2008 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 __MXL5007T_H__ -#define __MXL5007T_H__ - -#include "dvb_frontend.h" - -/* ------------------------------------------------------------------------- */ - -enum mxl5007t_if_freq { - MxL_IF_4_MHZ, /* 4000000 */ - MxL_IF_4_5_MHZ, /* 4500000 */ - MxL_IF_4_57_MHZ, /* 4570000 */ - MxL_IF_5_MHZ, /* 5000000 */ - MxL_IF_5_38_MHZ, /* 5380000 */ - MxL_IF_6_MHZ, /* 6000000 */ - MxL_IF_6_28_MHZ, /* 6280000 */ - MxL_IF_9_1915_MHZ, /* 9191500 */ - MxL_IF_35_25_MHZ, /* 35250000 */ - MxL_IF_36_15_MHZ, /* 36150000 */ - MxL_IF_44_MHZ, /* 44000000 */ -}; - -enum mxl5007t_xtal_freq { - MxL_XTAL_16_MHZ, /* 16000000 */ - MxL_XTAL_20_MHZ, /* 20000000 */ - MxL_XTAL_20_25_MHZ, /* 20250000 */ - MxL_XTAL_20_48_MHZ, /* 20480000 */ - MxL_XTAL_24_MHZ, /* 24000000 */ - MxL_XTAL_25_MHZ, /* 25000000 */ - MxL_XTAL_25_14_MHZ, /* 25140000 */ - MxL_XTAL_27_MHZ, /* 27000000 */ - MxL_XTAL_28_8_MHZ, /* 28800000 */ - MxL_XTAL_32_MHZ, /* 32000000 */ - MxL_XTAL_40_MHZ, /* 40000000 */ - MxL_XTAL_44_MHZ, /* 44000000 */ - MxL_XTAL_48_MHZ, /* 48000000 */ - MxL_XTAL_49_3811_MHZ, /* 49381100 */ -}; - -enum mxl5007t_clkout_amp { - MxL_CLKOUT_AMP_0_94V = 0, - MxL_CLKOUT_AMP_0_53V = 1, - MxL_CLKOUT_AMP_0_37V = 2, - MxL_CLKOUT_AMP_0_28V = 3, - MxL_CLKOUT_AMP_0_23V = 4, - MxL_CLKOUT_AMP_0_20V = 5, - MxL_CLKOUT_AMP_0_17V = 6, - MxL_CLKOUT_AMP_0_15V = 7, -}; - -struct mxl5007t_config { - s32 if_diff_out_level; - enum mxl5007t_clkout_amp clk_out_amp; - enum mxl5007t_xtal_freq xtal_freq_hz; - enum mxl5007t_if_freq if_freq_hz; - unsigned int invert_if:1; - unsigned int loop_thru_enable:1; - unsigned int clk_out_enable:1; -}; - -#if defined(CONFIG_MEDIA_TUNER_MXL5007T) || (defined(CONFIG_MEDIA_TUNER_MXL5007T_MODULE) && defined(MODULE)) -extern struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, u8 addr, - struct mxl5007t_config *cfg); -#else -static inline struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - u8 addr, - struct mxl5007t_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* __MXL5007T_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ - diff --git a/drivers/media/common/tuners/qt1010.c b/drivers/media/common/tuners/qt1010.c deleted file mode 100644 index bdc39e11030e..000000000000 --- a/drivers/media/common/tuners/qt1010.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Driver for Quantek QT1010 silicon tuner - * - * Copyright (C) 2006 Antti Palosaari - * Aapo Tahkola - * - * 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 "qt1010.h" -#include "qt1010_priv.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "QT1010: " args); \ - } while (0) - -/* read single register */ -static int qt1010_readreg(struct qt1010_priv *priv, u8 reg, u8 *val) -{ - struct i2c_msg msg[2] = { - { .addr = priv->cfg->i2c_address, - .flags = 0, .buf = ®, .len = 1 }, - { .addr = priv->cfg->i2c_address, - .flags = I2C_M_RD, .buf = val, .len = 1 }, - }; - - if (i2c_transfer(priv->i2c, msg, 2) != 2) { - printk(KERN_WARNING "qt1010 I2C read failed\n"); - return -EREMOTEIO; - } - return 0; -} - -/* write single register */ -static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val) -{ - u8 buf[2] = { reg, val }; - struct i2c_msg msg = { .addr = priv->cfg->i2c_address, - .flags = 0, .buf = buf, .len = 2 }; - - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "qt1010 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; -} - -/* dump all registers */ -static void qt1010_dump_regs(struct qt1010_priv *priv) -{ - u8 reg, val; - - for (reg = 0; ; reg++) { - if (reg % 16 == 0) { - if (reg) - printk(KERN_CONT "\n"); - printk(KERN_DEBUG "%02x:", reg); - } - if (qt1010_readreg(priv, reg, &val) == 0) - printk(KERN_CONT " %02x", val); - else - printk(KERN_CONT " --"); - if (reg == 0x2f) - break; - } - printk(KERN_CONT "\n"); -} - -static int qt1010_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct qt1010_priv *priv; - int err; - u32 freq, div, mod1, mod2; - u8 i, tmpval, reg05; - qt1010_i2c_oper_t rd[48] = { - { QT1010_WR, 0x01, 0x80 }, - { QT1010_WR, 0x02, 0x3f }, - { QT1010_WR, 0x05, 0xff }, /* 02 c write */ - { QT1010_WR, 0x06, 0x44 }, - { QT1010_WR, 0x07, 0xff }, /* 04 c write */ - { QT1010_WR, 0x08, 0x08 }, - { QT1010_WR, 0x09, 0xff }, /* 06 c write */ - { QT1010_WR, 0x0a, 0xff }, /* 07 c write */ - { QT1010_WR, 0x0b, 0xff }, /* 08 c write */ - { QT1010_WR, 0x0c, 0xe1 }, - { QT1010_WR, 0x1a, 0xff }, /* 10 c write */ - { QT1010_WR, 0x1b, 0x00 }, - { QT1010_WR, 0x1c, 0x89 }, - { QT1010_WR, 0x11, 0xff }, /* 13 c write */ - { QT1010_WR, 0x12, 0xff }, /* 14 c write */ - { QT1010_WR, 0x22, 0xff }, /* 15 c write */ - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_WR, 0x1e, 0xd0 }, - { QT1010_RD, 0x22, 0xff }, /* 16 c read */ - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_RD, 0x05, 0xff }, /* 20 c read */ - { QT1010_RD, 0x22, 0xff }, /* 21 c read */ - { QT1010_WR, 0x23, 0xd0 }, - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_WR, 0x1e, 0xe0 }, - { QT1010_RD, 0x23, 0xff }, /* 25 c read */ - { QT1010_RD, 0x23, 0xff }, /* 26 c read */ - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_WR, 0x24, 0xd0 }, - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_WR, 0x1e, 0xf0 }, - { QT1010_RD, 0x24, 0xff }, /* 31 c read */ - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_WR, 0x14, 0x7f }, - { QT1010_WR, 0x15, 0x7f }, - { QT1010_WR, 0x05, 0xff }, /* 35 c write */ - { QT1010_WR, 0x06, 0x00 }, - { QT1010_WR, 0x15, 0x1f }, - { QT1010_WR, 0x16, 0xff }, - { QT1010_WR, 0x18, 0xff }, - { QT1010_WR, 0x1f, 0xff }, /* 40 c write */ - { QT1010_WR, 0x20, 0xff }, /* 41 c write */ - { QT1010_WR, 0x21, 0x53 }, - { QT1010_WR, 0x25, 0xff }, /* 43 c write */ - { QT1010_WR, 0x26, 0x15 }, - { QT1010_WR, 0x00, 0xff }, /* 45 c write */ - { QT1010_WR, 0x02, 0x00 }, - { QT1010_WR, 0x01, 0x00 } - }; - -#define FREQ1 32000000 /* 32 MHz */ -#define FREQ2 4000000 /* 4 MHz Quartz oscillator in the stick? */ - - priv = fe->tuner_priv; - freq = c->frequency; - div = (freq + QT1010_OFFSET) / QT1010_STEP; - freq = (div * QT1010_STEP) - QT1010_OFFSET; - mod1 = (freq + QT1010_OFFSET) % FREQ1; - mod2 = (freq + QT1010_OFFSET) % FREQ2; - priv->frequency = freq; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - /* reg 05 base value */ - if (freq < 290000000) reg05 = 0x14; /* 290 MHz */ - else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */ - else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */ - else reg05 = 0x74; - - /* 0x5 */ - rd[2].val = reg05; - - /* 07 - set frequency: 32 MHz scale */ - rd[4].val = (freq + QT1010_OFFSET) / FREQ1; - - /* 09 - changes every 8/24 MHz */ - if (mod1 < 8000000) rd[6].val = 0x1d; - else rd[6].val = 0x1c; - - /* 0a - set frequency: 4 MHz scale (max 28 MHz) */ - if (mod1 < 1*FREQ2) rd[7].val = 0x09; /* +0 MHz */ - else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /* +4 MHz */ - else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /* +8 MHz */ - else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */ - else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */ - else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */ - else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */ - else rd[7].val = 0x0a; /* +28 MHz */ - - /* 0b - changes every 2/2 MHz */ - if (mod2 < 2000000) rd[8].val = 0x45; - else rd[8].val = 0x44; - - /* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/ - tmpval = 0x78; /* byte, overflows intentionally */ - rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08); - - /* 11 */ - rd[13].val = 0xfd; /* TODO: correct value calculation */ - - /* 12 */ - rd[14].val = 0x91; /* TODO: correct value calculation */ - - /* 22 */ - if (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */ - else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */ - else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */ - else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */ - else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */ - else rd[15].val = 0xd0; - - /* 05 */ - rd[35].val = (reg05 & 0xf0); - - /* 1f */ - if (mod1 < 8000000) tmpval = 0x00; - else if (mod1 < 12000000) tmpval = 0x01; - else if (mod1 < 16000000) tmpval = 0x02; - else if (mod1 < 24000000) tmpval = 0x03; - else if (mod1 < 28000000) tmpval = 0x04; - else tmpval = 0x05; - rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval); - - /* 20 */ - if (mod1 < 8000000) tmpval = 0x00; - else if (mod1 < 12000000) tmpval = 0x01; - else if (mod1 < 20000000) tmpval = 0x02; - else if (mod1 < 24000000) tmpval = 0x03; - else if (mod1 < 28000000) tmpval = 0x04; - else tmpval = 0x05; - rd[41].val = (priv->reg20_init_val + 0x0d + tmpval); - - /* 25 */ - rd[43].val = priv->reg25_init_val; - - /* 00 */ - rd[45].val = 0x92; /* TODO: correct value calculation */ - - dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \ - "1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \ - "20:%02x 25:%02x 00:%02x", \ - freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \ - rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \ - rd[40].val, rd[41].val, rd[43].val, rd[45].val); - - for (i = 0; i < ARRAY_SIZE(rd); i++) { - if (rd[i].oper == QT1010_WR) { - err = qt1010_writereg(priv, rd[i].reg, rd[i].val); - } else { /* read is required to proper locking */ - err = qt1010_readreg(priv, rd[i].reg, &tmpval); - } - if (err) return err; - } - - if (debug) - qt1010_dump_regs(priv); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - return 0; -} - -static int qt1010_init_meas1(struct qt1010_priv *priv, - u8 oper, u8 reg, u8 reg_init_val, u8 *retval) -{ - u8 i, val1, val2; - int err; - - qt1010_i2c_oper_t i2c_data[] = { - { QT1010_WR, reg, reg_init_val }, - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_WR, 0x1e, oper }, - { QT1010_RD, reg, 0xff } - }; - - for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { - if (i2c_data[i].oper == QT1010_WR) { - err = qt1010_writereg(priv, i2c_data[i].reg, - i2c_data[i].val); - } else { - err = qt1010_readreg(priv, i2c_data[i].reg, &val2); - } - if (err) return err; - } - - do { - val1 = val2; - err = qt1010_readreg(priv, reg, &val2); - if (err) return err; - dprintk("compare reg:%02x %02x %02x", reg, val1, val2); - } while (val1 != val2); - *retval = val1; - - return qt1010_writereg(priv, 0x1e, 0x00); -} - -static int qt1010_init_meas2(struct qt1010_priv *priv, - u8 reg_init_val, u8 *retval) -{ - u8 i, val; - int err; - qt1010_i2c_oper_t i2c_data[] = { - { QT1010_WR, 0x07, reg_init_val }, - { QT1010_WR, 0x22, 0xd0 }, - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_WR, 0x1e, 0xd0 }, - { QT1010_RD, 0x22, 0xff }, - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_WR, 0x22, 0xff } - }; - for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { - if (i2c_data[i].oper == QT1010_WR) { - err = qt1010_writereg(priv, i2c_data[i].reg, - i2c_data[i].val); - } else { - err = qt1010_readreg(priv, i2c_data[i].reg, &val); - } - if (err) return err; - } - *retval = val; - return 0; -} - -static int qt1010_init(struct dvb_frontend *fe) -{ - struct qt1010_priv *priv = fe->tuner_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int err = 0; - u8 i, tmpval, *valptr = NULL; - - qt1010_i2c_oper_t i2c_data[] = { - { QT1010_WR, 0x01, 0x80 }, - { QT1010_WR, 0x0d, 0x84 }, - { QT1010_WR, 0x0e, 0xb7 }, - { QT1010_WR, 0x2a, 0x23 }, - { QT1010_WR, 0x2c, 0xdc }, - { QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */ - { QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */ - { QT1010_WR, 0x2b, 0x70 }, - { QT1010_WR, 0x2a, 0x23 }, - { QT1010_M1, 0x26, 0x08 }, - { QT1010_M1, 0x82, 0xff }, - { QT1010_WR, 0x05, 0x14 }, - { QT1010_WR, 0x06, 0x44 }, - { QT1010_WR, 0x07, 0x28 }, - { QT1010_WR, 0x08, 0x0b }, - { QT1010_WR, 0x11, 0xfd }, - { QT1010_M1, 0x22, 0x0d }, - { QT1010_M1, 0xd0, 0xff }, - { QT1010_WR, 0x06, 0x40 }, - { QT1010_WR, 0x16, 0xf0 }, - { QT1010_WR, 0x02, 0x38 }, - { QT1010_WR, 0x03, 0x18 }, - { QT1010_WR, 0x20, 0xe0 }, - { QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */ - { QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */ - { QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */ - { QT1010_WR, 0x03, 0x19 }, - { QT1010_WR, 0x02, 0x3f }, - { QT1010_WR, 0x21, 0x53 }, - { QT1010_RD, 0x21, 0xff }, - { QT1010_WR, 0x11, 0xfd }, - { QT1010_WR, 0x05, 0x34 }, - { QT1010_WR, 0x06, 0x44 }, - { QT1010_WR, 0x08, 0x08 } - }; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { - switch (i2c_data[i].oper) { - case QT1010_WR: - err = qt1010_writereg(priv, i2c_data[i].reg, - i2c_data[i].val); - break; - case QT1010_RD: - if (i2c_data[i].val == 0x20) - valptr = &priv->reg20_init_val; - else - valptr = &tmpval; - err = qt1010_readreg(priv, i2c_data[i].reg, valptr); - break; - case QT1010_M1: - if (i2c_data[i].val == 0x25) - valptr = &priv->reg25_init_val; - else if (i2c_data[i].val == 0x1f) - valptr = &priv->reg1f_init_val; - else - valptr = &tmpval; - err = qt1010_init_meas1(priv, i2c_data[i+1].reg, - i2c_data[i].reg, - i2c_data[i].val, valptr); - i++; - break; - } - if (err) return err; - } - - for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */ - if ((err = qt1010_init_meas2(priv, i, &tmpval))) - return err; - - c->frequency = 545000000; /* Sigmatek DVB-110 545000000 */ - /* MSI Megasky 580 GL861 533000000 */ - return qt1010_set_params(fe); -} - -static int qt1010_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct qt1010_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int qt1010_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - *frequency = 36125000; - return 0; -} - -static const struct dvb_tuner_ops qt1010_tuner_ops = { - .info = { - .name = "Quantek QT1010", - .frequency_min = QT1010_MIN_FREQ, - .frequency_max = QT1010_MAX_FREQ, - .frequency_step = QT1010_STEP, - }, - - .release = qt1010_release, - .init = qt1010_init, - /* TODO: implement sleep */ - - .set_params = qt1010_set_params, - .get_frequency = qt1010_get_frequency, - .get_if_frequency = qt1010_get_if_frequency, -}; - -struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct qt1010_config *cfg) -{ - struct qt1010_priv *priv = NULL; - u8 id; - - priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->cfg = cfg; - priv->i2c = i2c; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - - /* Try to detect tuner chip. Probably this is not correct register. */ - if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) { - kfree(priv); - return NULL; - } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - printk(KERN_INFO "Quantek QT1010 successfully identified.\n"); - memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = priv; - return fe; -} -EXPORT_SYMBOL(qt1010_attach); - -MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver"); -MODULE_AUTHOR("Antti Palosaari "); -MODULE_AUTHOR("Aapo Tahkola "); -MODULE_VERSION("0.1"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/qt1010.h b/drivers/media/common/tuners/qt1010.h deleted file mode 100644 index 807fb7b6146b..000000000000 --- a/drivers/media/common/tuners/qt1010.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Driver for Quantek QT1010 silicon tuner - * - * Copyright (C) 2006 Antti Palosaari - * Aapo Tahkola - * - * 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 QT1010_H -#define QT1010_H - -#include "dvb_frontend.h" - -struct qt1010_config { - u8 i2c_address; -}; - -/** - * Attach a qt1010 tuner to the supplied frontend structure. - * - * @param fe frontend to attach to - * @param i2c i2c adapter to use - * @param cfg tuner hw based configuration - * @return fe pointer on success, NULL on failure - */ -#if defined(CONFIG_MEDIA_TUNER_QT1010) || (defined(CONFIG_MEDIA_TUNER_QT1010_MODULE) && defined(MODULE)) -extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct qt1010_config *cfg); -#else -static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct qt1010_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_MEDIA_TUNER_QT1010 - -#endif diff --git a/drivers/media/common/tuners/qt1010_priv.h b/drivers/media/common/tuners/qt1010_priv.h deleted file mode 100644 index 2c42d3f01636..000000000000 --- a/drivers/media/common/tuners/qt1010_priv.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Driver for Quantek QT1010 silicon tuner - * - * Copyright (C) 2006 Antti Palosaari - * Aapo Tahkola - * - * 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 QT1010_PRIV_H -#define QT1010_PRIV_H - -/* -reg def meaning -=== === ======= -00 00 ? -01 a0 ? operation start/stop; start=80, stop=00 -02 00 ? -03 19 ? -04 00 ? -05 00 ? maybe band selection -06 00 ? -07 2b set frequency: 32 MHz scale, n*32 MHz -08 0b ? -09 10 ? changes every 8/24 MHz; values 1d/1c -0a 08 set frequency: 4 MHz scale, n*4 MHz -0b 41 ? changes every 2/2 MHz; values 45/45 -0c e1 ? -0d 94 ? -0e b6 ? -0f 2c ? -10 10 ? -11 f1 ? maybe device specified adjustment -12 11 ? maybe device specified adjustment -13 3f ? -14 1f ? -15 3f ? -16 ff ? -17 ff ? -18 f7 ? -19 80 ? -1a d0 set frequency: 125 kHz scale, n*125 kHz -1b 00 ? -1c 89 ? -1d 00 ? -1e 00 ? looks like operation register; write cmd here, read result from 1f-26 -1f 20 ? chip initialization -20 e0 ? chip initialization -21 20 ? -22 d0 ? -23 d0 ? -24 d0 ? -25 40 ? chip initialization -26 08 ? -27 29 ? -28 55 ? -29 39 ? -2a 13 ? -2b 01 ? -2c ea ? -2d 00 ? -2e 00 ? not used? -2f 00 ? not used? -*/ - -#define QT1010_STEP 125000 /* 125 kHz used by Windows drivers, - hw could be more precise but we don't - know how to use */ -#define QT1010_MIN_FREQ 48000000 /* 48 MHz */ -#define QT1010_MAX_FREQ 860000000 /* 860 MHz */ -#define QT1010_OFFSET 1246000000 /* 1246 MHz */ - -#define QT1010_WR 0 -#define QT1010_RD 1 -#define QT1010_M1 3 - -typedef struct { - u8 oper, reg, val; -} qt1010_i2c_oper_t; - -struct qt1010_priv { - struct qt1010_config *cfg; - struct i2c_adapter *i2c; - - u8 reg1f_init_val; - u8 reg20_init_val; - u8 reg25_init_val; - - u32 frequency; -}; - -#endif diff --git a/drivers/media/common/tuners/tda18212.c b/drivers/media/common/tuners/tda18212.c deleted file mode 100644 index 5d9f02842501..000000000000 --- a/drivers/media/common/tuners/tda18212.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - * NXP TDA18212HN silicon tuner driver - * - * Copyright (C) 2011 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 "tda18212.h" - -struct tda18212_priv { - struct tda18212_config *cfg; - struct i2c_adapter *i2c; - - u32 if_frequency; -}; - -/* write multiple registers */ -static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, - int len) -{ - int ret; - u8 buf[len+1]; - struct i2c_msg msg[1] = { - { - .addr = priv->cfg->i2c_address, - .flags = 0, - .len = sizeof(buf), - .buf = buf, - } - }; - - buf[0] = reg; - memcpy(&buf[1], val, len); - - ret = i2c_transfer(priv->i2c, msg, 1); - if (ret == 1) { - ret = 0; - } else { - dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } - return ret; -} - -/* read multiple registers */ -static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val, - int len) -{ - int ret; - u8 buf[len]; - struct i2c_msg msg[2] = { - { - .addr = priv->cfg->i2c_address, - .flags = 0, - .len = 1, - .buf = ®, - }, { - .addr = priv->cfg->i2c_address, - .flags = I2C_M_RD, - .len = sizeof(buf), - .buf = buf, - } - }; - - ret = i2c_transfer(priv->i2c, msg, 2); - if (ret == 2) { - memcpy(val, buf, len); - ret = 0; - } else { - dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } - - return ret; -} - -/* write single register */ -static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val) -{ - return tda18212_wr_regs(priv, reg, &val, 1); -} - -/* read single register */ -static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val) -{ - return tda18212_rd_regs(priv, reg, val, 1); -} - -#if 0 /* keep, useful when developing driver */ -static void tda18212_dump_regs(struct tda18212_priv *priv) -{ - int i; - u8 buf[256]; - - #define TDA18212_RD_LEN 32 - for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN) - tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN); - - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf, - sizeof(buf), true); - - return; -} -#endif - -static int tda18212_set_params(struct dvb_frontend *fe) -{ - struct tda18212_priv *priv = fe->tuner_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret, i; - u32 if_khz; - u8 buf[9]; - #define DVBT_6 0 - #define DVBT_7 1 - #define DVBT_8 2 - #define DVBT2_6 3 - #define DVBT2_7 4 - #define DVBT2_8 5 - #define DVBC_6 6 - #define DVBC_8 7 - static const u8 bw_params[][3] = { - /* reg: 0f 13 23 */ - [DVBT_6] = { 0xb3, 0x20, 0x03 }, - [DVBT_7] = { 0xb3, 0x31, 0x01 }, - [DVBT_8] = { 0xb3, 0x22, 0x01 }, - [DVBT2_6] = { 0xbc, 0x20, 0x03 }, - [DVBT2_7] = { 0xbc, 0x72, 0x03 }, - [DVBT2_8] = { 0xbc, 0x22, 0x01 }, - [DVBC_6] = { 0x92, 0x50, 0x03 }, - [DVBC_8] = { 0x92, 0x53, 0x03 }, - }; - - dev_dbg(&priv->i2c->dev, - "%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", - __func__, c->delivery_system, c->frequency, - c->bandwidth_hz); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - switch (c->delivery_system) { - case SYS_DVBT: - switch (c->bandwidth_hz) { - case 6000000: - if_khz = priv->cfg->if_dvbt_6; - i = DVBT_6; - break; - case 7000000: - if_khz = priv->cfg->if_dvbt_7; - i = DVBT_7; - break; - case 8000000: - if_khz = priv->cfg->if_dvbt_8; - i = DVBT_8; - break; - default: - ret = -EINVAL; - goto error; - } - break; - case SYS_DVBT2: - switch (c->bandwidth_hz) { - case 6000000: - if_khz = priv->cfg->if_dvbt2_6; - i = DVBT2_6; - break; - case 7000000: - if_khz = priv->cfg->if_dvbt2_7; - i = DVBT2_7; - break; - case 8000000: - if_khz = priv->cfg->if_dvbt2_8; - i = DVBT2_8; - break; - default: - ret = -EINVAL; - goto error; - } - break; - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - if_khz = priv->cfg->if_dvbc; - i = DVBC_8; - break; - default: - ret = -EINVAL; - goto error; - } - - ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]); - if (ret) - goto error; - - ret = tda18212_wr_reg(priv, 0x06, 0x00); - if (ret) - goto error; - - ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]); - if (ret) - goto error; - - buf[0] = 0x02; - buf[1] = bw_params[i][1]; - buf[2] = 0x03; /* default value */ - buf[3] = DIV_ROUND_CLOSEST(if_khz, 50); - buf[4] = ((c->frequency / 1000) >> 16) & 0xff; - buf[5] = ((c->frequency / 1000) >> 8) & 0xff; - buf[6] = ((c->frequency / 1000) >> 0) & 0xff; - buf[7] = 0xc1; - buf[8] = 0x01; - ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf)); - if (ret) - goto error; - - /* actual IF rounded as it is on register */ - priv->if_frequency = buf[3] * 50 * 1000; - -exit: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - - return ret; - -error: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - goto exit; -} - -static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tda18212_priv *priv = fe->tuner_priv; - - *frequency = priv->if_frequency; - - return 0; -} - -static int tda18212_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static const struct dvb_tuner_ops tda18212_tuner_ops = { - .info = { - .name = "NXP TDA18212", - - .frequency_min = 48000000, - .frequency_max = 864000000, - .frequency_step = 1000, - }, - - .release = tda18212_release, - - .set_params = tda18212_set_params, - .get_if_frequency = tda18212_get_if_frequency, -}; - -struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tda18212_config *cfg) -{ - struct tda18212_priv *priv = NULL; - int ret; - u8 uninitialized_var(val); - - priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->cfg = cfg; - priv->i2c = i2c; - fe->tuner_priv = priv; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - /* check if the tuner is there */ - ret = tda18212_rd_reg(priv, 0x00, &val); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - - dev_dbg(&priv->i2c->dev, "%s: ret=%d chip id=%02x\n", __func__, ret, - val); - if (ret || val != 0xc7) { - kfree(priv); - return NULL; - } - - dev_info(&priv->i2c->dev, - "%s: NXP TDA18212HN successfully identified\n", - KBUILD_MODNAME); - - memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - return fe; -} -EXPORT_SYMBOL(tda18212_attach); - -MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver"); -MODULE_AUTHOR("Antti Palosaari "); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/tda18212.h b/drivers/media/common/tuners/tda18212.h deleted file mode 100644 index 9bd5da4aabb7..000000000000 --- a/drivers/media/common/tuners/tda18212.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * NXP TDA18212HN silicon tuner driver - * - * Copyright (C) 2011 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 TDA18212_H -#define TDA18212_H - -#include "dvb_frontend.h" - -struct tda18212_config { - u8 i2c_address; - - u16 if_dvbt_6; - u16 if_dvbt_7; - u16 if_dvbt_8; - u16 if_dvbt2_5; - u16 if_dvbt2_6; - u16 if_dvbt2_7; - u16 if_dvbt2_8; - u16 if_dvbc; -}; - -#if defined(CONFIG_MEDIA_TUNER_TDA18212) || \ - (defined(CONFIG_MEDIA_TUNER_TDA18212_MODULE) && defined(MODULE)) -extern struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tda18212_config *cfg); -#else -static inline struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tda18212_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff --git a/drivers/media/common/tuners/tda18218.c b/drivers/media/common/tuners/tda18218.c deleted file mode 100644 index 8a6f9ca788f0..000000000000 --- a/drivers/media/common/tuners/tda18218.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * NXP TDA18218HN silicon tuner driver - * - * Copyright (C) 2010 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 "tda18218.h" -#include "tda18218_priv.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -/* write multiple registers */ -static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len) -{ - int ret = 0; - u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max; - struct i2c_msg msg[1] = { - { - .addr = priv->cfg->i2c_address, - .flags = 0, - .buf = buf, - } - }; - - msg_len_max = priv->cfg->i2c_wr_max - 1; - quotient = len / msg_len_max; - remainder = len % msg_len_max; - msg_len = msg_len_max; - for (i = 0; (i <= quotient && remainder); i++) { - if (i == quotient) /* set len of the last msg */ - msg_len = remainder; - - msg[0].len = msg_len + 1; - buf[0] = reg + i * msg_len_max; - memcpy(&buf[1], &val[i * msg_len_max], msg_len); - - ret = i2c_transfer(priv->i2c, msg, 1); - if (ret != 1) - break; - } - - if (ret == 1) { - ret = 0; - } else { - warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len); - ret = -EREMOTEIO; - } - - return ret; -} - -/* read multiple registers */ -static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len) -{ - int ret; - u8 buf[reg+len]; /* we must start read always from reg 0x00 */ - struct i2c_msg msg[2] = { - { - .addr = priv->cfg->i2c_address, - .flags = 0, - .len = 1, - .buf = "\x00", - }, { - .addr = priv->cfg->i2c_address, - .flags = I2C_M_RD, - .len = sizeof(buf), - .buf = buf, - } - }; - - ret = i2c_transfer(priv->i2c, msg, 2); - if (ret == 2) { - memcpy(val, &buf[reg], len); - ret = 0; - } else { - warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len); - ret = -EREMOTEIO; - } - - return ret; -} - -/* write single register */ -static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val) -{ - return tda18218_wr_regs(priv, reg, &val, 1); -} - -/* read single register */ - -static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val) -{ - return tda18218_rd_regs(priv, reg, val, 1); -} - -static int tda18218_set_params(struct dvb_frontend *fe) -{ - struct tda18218_priv *priv = fe->tuner_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u32 bw = c->bandwidth_hz; - int ret; - u8 buf[3], i, BP_Filter, LP_Fc; - u32 LO_Frac; - /* TODO: find out correct AGC algorithm */ - u8 agc[][2] = { - { R20_AGC11, 0x60 }, - { R23_AGC21, 0x02 }, - { R20_AGC11, 0xa0 }, - { R23_AGC21, 0x09 }, - { R20_AGC11, 0xe0 }, - { R23_AGC21, 0x0c }, - { R20_AGC11, 0x40 }, - { R23_AGC21, 0x01 }, - { R20_AGC11, 0x80 }, - { R23_AGC21, 0x08 }, - { R20_AGC11, 0xc0 }, - { R23_AGC21, 0x0b }, - { R24_AGC22, 0x1c }, - { R24_AGC22, 0x0c }, - }; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - /* low-pass filter cut-off frequency */ - if (bw <= 6000000) { - LP_Fc = 0; - priv->if_frequency = 3000000; - } else if (bw <= 7000000) { - LP_Fc = 1; - priv->if_frequency = 3500000; - } else { - LP_Fc = 2; - priv->if_frequency = 4000000; - } - - LO_Frac = c->frequency + priv->if_frequency; - - /* band-pass filter */ - if (LO_Frac < 188000000) - BP_Filter = 3; - else if (LO_Frac < 253000000) - BP_Filter = 4; - else if (LO_Frac < 343000000) - BP_Filter = 5; - else - BP_Filter = 6; - - buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */ - buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */ - buf[2] = priv->regs[R1C_AGC2B]; - ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3); - if (ret) - goto error; - - buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */ - buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */ - buf[2] = (LO_Frac / 1000) << 4 | - (priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */ - ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3); - if (ret) - goto error; - - buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */ - ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1); - if (ret) - goto error; - - buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */ - ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1); - if (ret) - goto error; - - /* trigger AGC */ - for (i = 0; i < ARRAY_SIZE(agc); i++) { - ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]); - if (ret) - goto error; - } - -error: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - - if (ret) - dbg("%s: failed ret:%d", __func__, ret); - - return ret; -} - -static int tda18218_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tda18218_priv *priv = fe->tuner_priv; - *frequency = priv->if_frequency; - dbg("%s: if=%d", __func__, *frequency); - return 0; -} - -static int tda18218_sleep(struct dvb_frontend *fe) -{ - struct tda18218_priv *priv = fe->tuner_priv; - int ret; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - /* standby */ - ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0)); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - - if (ret) - dbg("%s: failed ret:%d", __func__, ret); - - return ret; -} - -static int tda18218_init(struct dvb_frontend *fe) -{ - struct tda18218_priv *priv = fe->tuner_priv; - int ret; - - /* TODO: calibrations */ - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - - if (ret) - dbg("%s: failed ret:%d", __func__, ret); - - return ret; -} - -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 = 174000000, - .frequency_max = 864000000, - .frequency_step = 1000, - }, - - .release = tda18218_release, - .init = tda18218_init, - .sleep = tda18218_sleep, - - .set_params = tda18218_set_params, - - .get_if_frequency = tda18218_get_if_frequency, -}; - -struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tda18218_config *cfg) -{ - struct tda18218_priv *priv = NULL; - u8 uninitialized_var(val); - int ret; - /* chip default registers values */ - static u8 def_regs[] = { - 0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40, - 0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00, - 0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01, - 0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9, - 0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00, - 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6 - }; - - priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->cfg = cfg; - priv->i2c = i2c; - fe->tuner_priv = priv; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - /* check if the tuner is there */ - ret = tda18218_rd_reg(priv, R00_ID, &val); - dbg("%s: ret:%d chip ID:%02x", __func__, ret, val); - if (ret || val != def_regs[R00_ID]) { - kfree(priv); - return NULL; - } - - info("NXP TDA18218HN successfully identified."); - - memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops, - sizeof(struct dvb_tuner_ops)); - memcpy(priv->regs, def_regs, sizeof(def_regs)); - - /* loop-through enabled chip default register values */ - if (priv->cfg->loop_through) { - priv->regs[R17_PD1] = 0xb0; - priv->regs[R18_PD2] = 0x59; - } - - /* standby */ - ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0)); - if (ret) - dbg("%s: failed ret:%d", __func__, ret); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - - return fe; -} -EXPORT_SYMBOL(tda18218_attach); - -MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver"); -MODULE_AUTHOR("Antti Palosaari "); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/tda18218.h b/drivers/media/common/tuners/tda18218.h deleted file mode 100644 index b4180d180029..000000000000 --- a/drivers/media/common/tuners/tda18218.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * NXP TDA18218HN silicon tuner driver - * - * Copyright (C) 2010 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 TDA18218_H -#define TDA18218_H - -#include "dvb_frontend.h" - -struct tda18218_config { - u8 i2c_address; - u8 i2c_wr_max; - u8 loop_through:1; -}; - -#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 - -#endif diff --git a/drivers/media/common/tuners/tda18218_priv.h b/drivers/media/common/tuners/tda18218_priv.h deleted file mode 100644 index dc52b72e1407..000000000000 --- a/drivers/media/common/tuners/tda18218_priv.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * NXP TDA18218HN silicon tuner driver - * - * Copyright (C) 2010 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 TDA18218_PRIV_H -#define TDA18218_PRIV_H - -#define LOG_PREFIX "tda18218" - -#undef dbg -#define dbg(f, arg...) \ - if (debug) \ - printk(KERN_DEBUG LOG_PREFIX": " f "\n" , ## arg) -#undef err -#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) -#undef info -#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) -#undef warn -#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) - -#define R00_ID 0x00 /* ID byte */ -#define R01_R1 0x01 /* Read byte 1 */ -#define R02_R2 0x02 /* Read byte 2 */ -#define R03_R3 0x03 /* Read byte 3 */ -#define R04_R4 0x04 /* Read byte 4 */ -#define R05_R5 0x05 /* Read byte 5 */ -#define R06_R6 0x06 /* Read byte 6 */ -#define R07_MD1 0x07 /* Main divider byte 1 */ -#define R08_PSM1 0x08 /* PSM byte 1 */ -#define R09_MD2 0x09 /* Main divider byte 2 */ -#define R0A_MD3 0x0a /* Main divider byte 1 */ -#define R0B_MD4 0x0b /* Main divider byte 4 */ -#define R0C_MD5 0x0c /* Main divider byte 5 */ -#define R0D_MD6 0x0d /* Main divider byte 6 */ -#define R0E_MD7 0x0e /* Main divider byte 7 */ -#define R0F_MD8 0x0f /* Main divider byte 8 */ -#define R10_CD1 0x10 /* Call divider byte 1 */ -#define R11_CD2 0x11 /* Call divider byte 2 */ -#define R12_CD3 0x12 /* Call divider byte 3 */ -#define R13_CD4 0x13 /* Call divider byte 4 */ -#define R14_CD5 0x14 /* Call divider byte 5 */ -#define R15_CD6 0x15 /* Call divider byte 6 */ -#define R16_CD7 0x16 /* Call divider byte 7 */ -#define R17_PD1 0x17 /* Power-down byte 1 */ -#define R18_PD2 0x18 /* Power-down byte 2 */ -#define R19_XTOUT 0x19 /* XTOUT byte */ -#define R1A_IF1 0x1a /* IF byte 1 */ -#define R1B_IF2 0x1b /* IF byte 2 */ -#define R1C_AGC2B 0x1c /* AGC2b byte */ -#define R1D_PSM2 0x1d /* PSM byte 2 */ -#define R1E_PSM3 0x1e /* PSM byte 3 */ -#define R1F_PSM4 0x1f /* PSM byte 4 */ -#define R20_AGC11 0x20 /* AGC1 byte 1 */ -#define R21_AGC12 0x21 /* AGC1 byte 2 */ -#define R22_AGC13 0x22 /* AGC1 byte 3 */ -#define R23_AGC21 0x23 /* AGC2 byte 1 */ -#define R24_AGC22 0x24 /* AGC2 byte 2 */ -#define R25_AAGC 0x25 /* Analog AGC byte */ -#define R26_RC 0x26 /* RC byte */ -#define R27_RSSI 0x27 /* RSSI byte */ -#define R28_IRCAL1 0x28 /* IR CAL byte 1 */ -#define R29_IRCAL2 0x29 /* IR CAL byte 2 */ -#define R2A_IRCAL3 0x2a /* IR CAL byte 3 */ -#define R2B_IRCAL4 0x2b /* IR CAL byte 4 */ -#define R2C_RFCAL1 0x2c /* RF CAL byte 1 */ -#define R2D_RFCAL2 0x2d /* RF CAL byte 2 */ -#define R2E_RFCAL3 0x2e /* RF CAL byte 3 */ -#define R2F_RFCAL4 0x2f /* RF CAL byte 4 */ -#define R30_RFCAL5 0x30 /* RF CAL byte 5 */ -#define R31_RFCAL6 0x31 /* RF CAL byte 6 */ -#define R32_RFCAL7 0x32 /* RF CAL byte 7 */ -#define R33_RFCAL8 0x33 /* RF CAL byte 8 */ -#define R34_RFCAL9 0x34 /* RF CAL byte 9 */ -#define R35_RFCAL10 0x35 /* RF CAL byte 10 */ -#define R36_RFCALRAM1 0x36 /* RF CAL RAM byte 1 */ -#define R37_RFCALRAM2 0x37 /* RF CAL RAM byte 2 */ -#define R38_MARGIN 0x38 /* Margin byte */ -#define R39_FMAX1 0x39 /* Fmax byte 1 */ -#define R3A_FMAX2 0x3a /* Fmax byte 2 */ - -#define TDA18218_NUM_REGS 59 - -struct tda18218_priv { - struct tda18218_config *cfg; - struct i2c_adapter *i2c; - - u32 if_frequency; - - u8 regs[TDA18218_NUM_REGS]; -}; - -#endif diff --git a/drivers/media/common/tuners/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c deleted file mode 100644 index 39c645787b62..000000000000 --- a/drivers/media/common/tuners/tda18271-common.c +++ /dev/null @@ -1,703 +0,0 @@ -/* - tda18271-common.c - driver for the Philips / NXP TDA18271 silicon tuner - - Copyright (C) 2007, 2008 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 "tda18271-priv.h" - -static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct tda18271_priv *priv = fe->tuner_priv; - enum tda18271_i2c_gate gate; - int ret = 0; - - switch (priv->gate) { - case TDA18271_GATE_DIGITAL: - case TDA18271_GATE_ANALOG: - gate = priv->gate; - break; - case TDA18271_GATE_AUTO: - default: - switch (priv->mode) { - case TDA18271_DIGITAL: - gate = TDA18271_GATE_DIGITAL; - break; - case TDA18271_ANALOG: - default: - gate = TDA18271_GATE_ANALOG; - break; - } - } - - switch (gate) { - case TDA18271_GATE_ANALOG: - if (fe->ops.analog_ops.i2c_gate_ctrl) - ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable); - break; - case TDA18271_GATE_DIGITAL: - if (fe->ops.i2c_gate_ctrl) - ret = fe->ops.i2c_gate_ctrl(fe, enable); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -}; - -/*---------------------------------------------------------------------*/ - -static void tda18271_dump_regs(struct dvb_frontend *fe, int extended) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - tda_reg("=== TDA18271 REG DUMP ===\n"); - tda_reg("ID_BYTE = 0x%02x\n", 0xff & regs[R_ID]); - tda_reg("THERMO_BYTE = 0x%02x\n", 0xff & regs[R_TM]); - tda_reg("POWER_LEVEL_BYTE = 0x%02x\n", 0xff & regs[R_PL]); - tda_reg("EASY_PROG_BYTE_1 = 0x%02x\n", 0xff & regs[R_EP1]); - tda_reg("EASY_PROG_BYTE_2 = 0x%02x\n", 0xff & regs[R_EP2]); - tda_reg("EASY_PROG_BYTE_3 = 0x%02x\n", 0xff & regs[R_EP3]); - tda_reg("EASY_PROG_BYTE_4 = 0x%02x\n", 0xff & regs[R_EP4]); - tda_reg("EASY_PROG_BYTE_5 = 0x%02x\n", 0xff & regs[R_EP5]); - tda_reg("CAL_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_CPD]); - tda_reg("CAL_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_CD1]); - tda_reg("CAL_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_CD2]); - tda_reg("CAL_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_CD3]); - tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]); - tda_reg("MAIN_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_MD1]); - tda_reg("MAIN_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_MD2]); - tda_reg("MAIN_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_MD3]); - - /* only dump extended regs if DBG_ADV is set */ - if (!(tda18271_debug & DBG_ADV)) - return; - - /* W indicates write-only registers. - * Register dump for write-only registers shows last value written. */ - - tda_reg("EXTENDED_BYTE_1 = 0x%02x\n", 0xff & regs[R_EB1]); - tda_reg("EXTENDED_BYTE_2 = 0x%02x\n", 0xff & regs[R_EB2]); - tda_reg("EXTENDED_BYTE_3 = 0x%02x\n", 0xff & regs[R_EB3]); - tda_reg("EXTENDED_BYTE_4 = 0x%02x\n", 0xff & regs[R_EB4]); - tda_reg("EXTENDED_BYTE_5 = 0x%02x\n", 0xff & regs[R_EB5]); - tda_reg("EXTENDED_BYTE_6 = 0x%02x\n", 0xff & regs[R_EB6]); - tda_reg("EXTENDED_BYTE_7 = 0x%02x\n", 0xff & regs[R_EB7]); - tda_reg("EXTENDED_BYTE_8 = 0x%02x\n", 0xff & regs[R_EB8]); - tda_reg("EXTENDED_BYTE_9 W = 0x%02x\n", 0xff & regs[R_EB9]); - tda_reg("EXTENDED_BYTE_10 = 0x%02x\n", 0xff & regs[R_EB10]); - tda_reg("EXTENDED_BYTE_11 = 0x%02x\n", 0xff & regs[R_EB11]); - tda_reg("EXTENDED_BYTE_12 = 0x%02x\n", 0xff & regs[R_EB12]); - tda_reg("EXTENDED_BYTE_13 = 0x%02x\n", 0xff & regs[R_EB13]); - tda_reg("EXTENDED_BYTE_14 = 0x%02x\n", 0xff & regs[R_EB14]); - tda_reg("EXTENDED_BYTE_15 = 0x%02x\n", 0xff & regs[R_EB15]); - tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]); - tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]); - tda_reg("EXTENDED_BYTE_18 = 0x%02x\n", 0xff & regs[R_EB18]); - tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]); - tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]); - tda_reg("EXTENDED_BYTE_21 = 0x%02x\n", 0xff & regs[R_EB21]); - tda_reg("EXTENDED_BYTE_22 = 0x%02x\n", 0xff & regs[R_EB22]); - tda_reg("EXTENDED_BYTE_23 = 0x%02x\n", 0xff & regs[R_EB23]); -} - -int tda18271_read_regs(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - unsigned char buf = 0x00; - int ret; - struct i2c_msg msg[] = { - { .addr = priv->i2c_props.addr, .flags = 0, - .buf = &buf, .len = 1 }, - { .addr = priv->i2c_props.addr, .flags = I2C_M_RD, - .buf = regs, .len = 16 } - }; - - tda18271_i2c_gate_ctrl(fe, 1); - - /* read all registers */ - ret = i2c_transfer(priv->i2c_props.adap, msg, 2); - - tda18271_i2c_gate_ctrl(fe, 0); - - if (ret != 2) - tda_err("ERROR: i2c_transfer returned: %d\n", ret); - - if (tda18271_debug & DBG_REG) - tda18271_dump_regs(fe, 0); - - return (ret == 2 ? 0 : ret); -} - -int tda18271_read_extended(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - unsigned char regdump[TDA18271_NUM_REGS]; - unsigned char buf = 0x00; - int ret, i; - struct i2c_msg msg[] = { - { .addr = priv->i2c_props.addr, .flags = 0, - .buf = &buf, .len = 1 }, - { .addr = priv->i2c_props.addr, .flags = I2C_M_RD, - .buf = regdump, .len = TDA18271_NUM_REGS } - }; - - tda18271_i2c_gate_ctrl(fe, 1); - - /* read all registers */ - ret = i2c_transfer(priv->i2c_props.adap, msg, 2); - - tda18271_i2c_gate_ctrl(fe, 0); - - if (ret != 2) - tda_err("ERROR: i2c_transfer returned: %d\n", ret); - - for (i = 0; i < TDA18271_NUM_REGS; i++) { - /* don't update write-only registers */ - if ((i != R_EB9) && - (i != R_EB16) && - (i != R_EB17) && - (i != R_EB19) && - (i != R_EB20)) - regs[i] = regdump[i]; - } - - if (tda18271_debug & DBG_REG) - tda18271_dump_regs(fe, 1); - - return (ret == 2 ? 0 : ret); -} - -int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - unsigned char buf[TDA18271_NUM_REGS + 1]; - struct i2c_msg msg = { .addr = priv->i2c_props.addr, .flags = 0, - .buf = buf }; - int i, ret = 1, max; - - BUG_ON((len == 0) || (idx + len > sizeof(buf))); - - - switch (priv->small_i2c) { - case TDA18271_03_BYTE_CHUNK_INIT: - max = 3; - break; - case TDA18271_08_BYTE_CHUNK_INIT: - max = 8; - break; - case TDA18271_16_BYTE_CHUNK_INIT: - max = 16; - break; - case TDA18271_39_BYTE_CHUNK_INIT: - default: - max = 39; - } - - tda18271_i2c_gate_ctrl(fe, 1); - while (len) { - if (max > len) - max = len; - - buf[0] = idx; - for (i = 1; i <= max; i++) - buf[i] = regs[idx - 1 + i]; - - msg.len = max + 1; - - /* write registers */ - ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - if (ret != 1) - break; - - idx += max; - len -= max; - } - tda18271_i2c_gate_ctrl(fe, 0); - - if (ret != 1) - tda_err("ERROR: idx = 0x%x, len = %d, " - "i2c_transfer returned: %d\n", idx, max, ret); - - return (ret == 1 ? 0 : ret); -} - -/*---------------------------------------------------------------------*/ - -int tda18271_charge_pump_source(struct dvb_frontend *fe, - enum tda18271_pll pll, int force) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - int r_cp = (pll == TDA18271_CAL_PLL) ? R_EB7 : R_EB4; - - regs[r_cp] &= ~0x20; - regs[r_cp] |= ((force & 1) << 5); - - return tda18271_write_regs(fe, r_cp, 1); -} - -int tda18271_init_regs(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - tda_dbg("initializing registers for device @ %d-%04x\n", - i2c_adapter_id(priv->i2c_props.adap), - priv->i2c_props.addr); - - /* initialize registers */ - switch (priv->id) { - case TDA18271HDC1: - regs[R_ID] = 0x83; - break; - case TDA18271HDC2: - regs[R_ID] = 0x84; - break; - }; - - regs[R_TM] = 0x08; - regs[R_PL] = 0x80; - regs[R_EP1] = 0xc6; - regs[R_EP2] = 0xdf; - regs[R_EP3] = 0x16; - regs[R_EP4] = 0x60; - regs[R_EP5] = 0x80; - regs[R_CPD] = 0x80; - regs[R_CD1] = 0x00; - regs[R_CD2] = 0x00; - regs[R_CD3] = 0x00; - regs[R_MPD] = 0x00; - regs[R_MD1] = 0x00; - regs[R_MD2] = 0x00; - regs[R_MD3] = 0x00; - - switch (priv->id) { - case TDA18271HDC1: - regs[R_EB1] = 0xff; - break; - case TDA18271HDC2: - regs[R_EB1] = 0xfc; - break; - }; - - regs[R_EB2] = 0x01; - regs[R_EB3] = 0x84; - regs[R_EB4] = 0x41; - regs[R_EB5] = 0x01; - regs[R_EB6] = 0x84; - regs[R_EB7] = 0x40; - regs[R_EB8] = 0x07; - regs[R_EB9] = 0x00; - regs[R_EB10] = 0x00; - regs[R_EB11] = 0x96; - - switch (priv->id) { - case TDA18271HDC1: - regs[R_EB12] = 0x0f; - break; - case TDA18271HDC2: - regs[R_EB12] = 0x33; - break; - }; - - regs[R_EB13] = 0xc1; - regs[R_EB14] = 0x00; - regs[R_EB15] = 0x8f; - regs[R_EB16] = 0x00; - regs[R_EB17] = 0x00; - - switch (priv->id) { - case TDA18271HDC1: - regs[R_EB18] = 0x00; - break; - case TDA18271HDC2: - regs[R_EB18] = 0x8c; - break; - }; - - regs[R_EB19] = 0x00; - regs[R_EB20] = 0x20; - - switch (priv->id) { - case TDA18271HDC1: - regs[R_EB21] = 0x33; - break; - case TDA18271HDC2: - regs[R_EB21] = 0xb3; - break; - }; - - regs[R_EB22] = 0x48; - regs[R_EB23] = 0xb0; - - tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); - - /* setup agc1 gain */ - regs[R_EB17] = 0x00; - tda18271_write_regs(fe, R_EB17, 1); - regs[R_EB17] = 0x03; - tda18271_write_regs(fe, R_EB17, 1); - regs[R_EB17] = 0x43; - tda18271_write_regs(fe, R_EB17, 1); - regs[R_EB17] = 0x4c; - tda18271_write_regs(fe, R_EB17, 1); - - /* setup agc2 gain */ - if ((priv->id) == TDA18271HDC1) { - regs[R_EB20] = 0xa0; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xa7; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xe7; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xec; - tda18271_write_regs(fe, R_EB20, 1); - } - - /* image rejection calibration */ - - /* low-band */ - regs[R_EP3] = 0x1f; - regs[R_EP4] = 0x66; - regs[R_EP5] = 0x81; - regs[R_CPD] = 0xcc; - regs[R_CD1] = 0x6c; - regs[R_CD2] = 0x00; - regs[R_CD3] = 0x00; - regs[R_MPD] = 0xcd; - regs[R_MD1] = 0x77; - regs[R_MD2] = 0x08; - regs[R_MD3] = 0x00; - - tda18271_write_regs(fe, R_EP3, 11); - - if ((priv->id) == TDA18271HDC2) { - /* main pll cp source on */ - tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1); - msleep(1); - - /* main pll cp source off */ - tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0); - } - - msleep(5); /* pll locking */ - - /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); - msleep(5); /* wanted low measurement */ - - regs[R_EP5] = 0x85; - regs[R_CPD] = 0xcb; - regs[R_CD1] = 0x66; - regs[R_CD2] = 0x70; - - tda18271_write_regs(fe, R_EP3, 7); - msleep(5); /* pll locking */ - - /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); - msleep(30); /* image low optimization completion */ - - /* mid-band */ - regs[R_EP5] = 0x82; - regs[R_CPD] = 0xa8; - regs[R_CD2] = 0x00; - regs[R_MPD] = 0xa9; - regs[R_MD1] = 0x73; - regs[R_MD2] = 0x1a; - - tda18271_write_regs(fe, R_EP3, 11); - msleep(5); /* pll locking */ - - /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); - msleep(5); /* wanted mid measurement */ - - regs[R_EP5] = 0x86; - regs[R_CPD] = 0xa8; - regs[R_CD1] = 0x66; - regs[R_CD2] = 0xa0; - - tda18271_write_regs(fe, R_EP3, 7); - msleep(5); /* pll locking */ - - /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); - msleep(30); /* image mid optimization completion */ - - /* high-band */ - regs[R_EP5] = 0x83; - regs[R_CPD] = 0x98; - regs[R_CD1] = 0x65; - regs[R_CD2] = 0x00; - regs[R_MPD] = 0x99; - regs[R_MD1] = 0x71; - regs[R_MD2] = 0xcd; - - tda18271_write_regs(fe, R_EP3, 11); - msleep(5); /* pll locking */ - - /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); - msleep(5); /* wanted high measurement */ - - regs[R_EP5] = 0x87; - regs[R_CD1] = 0x65; - regs[R_CD2] = 0x50; - - tda18271_write_regs(fe, R_EP3, 7); - msleep(5); /* pll locking */ - - /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); - msleep(30); /* image high optimization completion */ - - /* return to normal mode */ - regs[R_EP4] = 0x64; - tda18271_write_regs(fe, R_EP4, 1); - - /* synchronize */ - tda18271_write_regs(fe, R_EP1, 1); - - return 0; -} - -/*---------------------------------------------------------------------*/ - -/* - * Standby modes, EP3 [7:5] - * - * | SM || SM_LT || SM_XT || mode description - * |=====\\=======\\=======\\=================================== - * | 0 || 0 || 0 || normal mode - * |-----||-------||-------||----------------------------------- - * | || || || standby mode w/ slave tuner output - * | 1 || 0 || 0 || & loop thru & xtal oscillator on - * |-----||-------||-------||----------------------------------- - * | 1 || 1 || 0 || standby mode w/ xtal oscillator on - * |-----||-------||-------||----------------------------------- - * | 1 || 1 || 1 || power off - * - */ - -int tda18271_set_standby_mode(struct dvb_frontend *fe, - int sm, int sm_lt, int sm_xt) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - if (tda18271_debug & DBG_ADV) - tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt); - - regs[R_EP3] &= ~0xe0; /* clear sm, sm_lt, sm_xt */ - regs[R_EP3] |= (sm ? (1 << 7) : 0) | - (sm_lt ? (1 << 6) : 0) | - (sm_xt ? (1 << 5) : 0); - - return tda18271_write_regs(fe, R_EP3, 1); -} - -/*---------------------------------------------------------------------*/ - -int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) -{ - /* sets main post divider & divider bytes, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 d, pd; - u32 div; - - int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d); - if (tda_fail(ret)) - goto fail; - - regs[R_MPD] = (0x7f & pd); - - div = ((d * (freq / 1000)) << 7) / 125; - - regs[R_MD1] = 0x7f & (div >> 16); - regs[R_MD2] = 0xff & (div >> 8); - regs[R_MD3] = 0xff & div; -fail: - return ret; -} - -int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq) -{ - /* sets cal post divider & divider bytes, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 d, pd; - u32 div; - - int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d); - if (tda_fail(ret)) - goto fail; - - regs[R_CPD] = pd; - - div = ((d * (freq / 1000)) << 7) / 125; - - regs[R_CD1] = 0x7f & (div >> 16); - regs[R_CD2] = 0xff & (div >> 8); - regs[R_CD3] = 0xff & div; -fail: - return ret; -} - -/*---------------------------------------------------------------------*/ - -int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq) -{ - /* sets bp filter bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val); - if (tda_fail(ret)) - goto fail; - - regs[R_EP1] &= ~0x07; /* clear bp filter bits */ - regs[R_EP1] |= (0x07 & val); -fail: - return ret; -} - -int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq) -{ - /* sets K & M bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val); - if (tda_fail(ret)) - goto fail; - - regs[R_EB13] &= ~0x7c; /* clear k & m bits */ - regs[R_EB13] |= (0x7c & val); -fail: - return ret; -} - -int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq) -{ - /* sets rf band bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val); - if (tda_fail(ret)) - goto fail; - - regs[R_EP2] &= ~0xe0; /* clear rf band bits */ - regs[R_EP2] |= (0xe0 & (val << 5)); -fail: - return ret; -} - -int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq) -{ - /* sets gain taper bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val); - if (tda_fail(ret)) - goto fail; - - regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ - regs[R_EP2] |= (0x1f & val); -fail: - return ret; -} - -int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq) -{ - /* sets IR Meas bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val); - if (tda_fail(ret)) - goto fail; - - regs[R_EP5] &= ~0x07; - regs[R_EP5] |= (0x07 & val); -fail: - return ret; -} - -int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq) -{ - /* sets rf cal byte (RFC_Cprog), but does not write it */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, RF_CAL, freq, &val); - /* The TDA18271HD/C1 rf_cal map lookup is expected to go out of range - * for frequencies above 61.1 MHz. In these cases, the internal RF - * tracking filters calibration mechanism is used. - * - * There is no need to warn the user about this. - */ - if (ret < 0) - goto fail; - - regs[R_EB14] = val; -fail: - return ret; -} - -int _tda_printk(struct tda18271_priv *state, const char *level, - const char *func, const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - int rtn; - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - if (state) - rtn = printk("%s%s: [%d-%04x|%c] %pV", - level, func, i2c_adapter_id(state->i2c_props.adap), - state->i2c_props.addr, - (state->role == TDA18271_MASTER) ? 'M' : 'S', - &vaf); - else - rtn = printk("%s%s: %pV", level, func, &vaf); - - va_end(args); - - return rtn; -} diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c deleted file mode 100644 index 2e67f4459904..000000000000 --- a/drivers/media/common/tuners/tda18271-fe.c +++ /dev/null @@ -1,1345 +0,0 @@ -/* - tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner - - Copyright (C) 2007, 2008 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 -#include -#include "tda18271-priv.h" - -int tda18271_debug; -module_param_named(debug, tda18271_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debug level " - "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))"); - -static int tda18271_cal_on_startup = -1; -module_param_named(cal, tda18271_cal_on_startup, int, 0644); -MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup"); - -static DEFINE_MUTEX(tda18271_list_mutex); -static LIST_HEAD(hybrid_tuner_instance_list); - -/*---------------------------------------------------------------------*/ - -static int tda18271_toggle_output(struct dvb_frontend *fe, int standby) -{ - struct tda18271_priv *priv = fe->tuner_priv; - - int ret = tda18271_set_standby_mode(fe, standby ? 1 : 0, - priv->output_opt & TDA18271_OUTPUT_LT_OFF ? 1 : 0, - priv->output_opt & TDA18271_OUTPUT_XT_OFF ? 1 : 0); - - if (tda_fail(ret)) - goto fail; - - tda_dbg("%s mode: xtal oscillator %s, slave tuner loop thru %s\n", - standby ? "standby" : "active", - priv->output_opt & TDA18271_OUTPUT_XT_OFF ? "off" : "on", - priv->output_opt & TDA18271_OUTPUT_LT_OFF ? "off" : "on"); -fail: - return ret; -} - -/*---------------------------------------------------------------------*/ - -static inline int charge_pump_source(struct dvb_frontend *fe, int force) -{ - struct tda18271_priv *priv = fe->tuner_priv; - return tda18271_charge_pump_source(fe, - (priv->role == TDA18271_SLAVE) ? - TDA18271_CAL_PLL : - TDA18271_MAIN_PLL, force); -} - -static inline void tda18271_set_if_notch(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x80; /* IF notch = 0 */ - break; - case TDA18271_DIGITAL: - regs[R_MPD] |= 0x80; /* IF notch = 1 */ - break; - } -} - -static int tda18271_channel_configuration(struct dvb_frontend *fe, - struct tda18271_std_map_item *map, - u32 freq, u32 bw) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int ret; - u32 N; - - /* update TV broadcast parameters */ - - /* set standard */ - regs[R_EP3] &= ~0x1f; /* clear std bits */ - regs[R_EP3] |= (map->agc_mode << 3) | map->std; - - if (priv->id == TDA18271HDC2) { - /* set rfagc to high speed mode */ - regs[R_EP3] &= ~0x04; - } - - /* set cal mode to normal */ - regs[R_EP4] &= ~0x03; - - /* update IF output level */ - regs[R_EP4] &= ~0x1c; /* clear if level bits */ - regs[R_EP4] |= (map->if_lvl << 2); - - /* update FM_RFn */ - regs[R_EP4] &= ~0x80; - regs[R_EP4] |= map->fm_rfn << 7; - - /* update rf top / if top */ - regs[R_EB22] = 0x00; - regs[R_EB22] |= map->rfagc_top; - ret = tda18271_write_regs(fe, R_EB22, 1); - if (tda_fail(ret)) - goto fail; - - /* --------------------------------------------------------------- */ - - /* disable Power Level Indicator */ - regs[R_EP1] |= 0x40; - - /* make sure thermometer is off */ - regs[R_TM] &= ~0x10; - - /* frequency dependent parameters */ - - tda18271_calc_ir_measure(fe, &freq); - - tda18271_calc_bp_filter(fe, &freq); - - tda18271_calc_rf_band(fe, &freq); - - tda18271_calc_gain_taper(fe, &freq); - - /* --------------------------------------------------------------- */ - - /* dual tuner and agc1 extra configuration */ - - switch (priv->role) { - case TDA18271_MASTER: - regs[R_EB1] |= 0x04; /* main vco */ - break; - case TDA18271_SLAVE: - regs[R_EB1] &= ~0x04; /* cal vco */ - break; - } - - /* agc1 always active */ - regs[R_EB1] &= ~0x02; - - /* agc1 has priority on agc2 */ - regs[R_EB1] &= ~0x01; - - ret = tda18271_write_regs(fe, R_EB1, 1); - if (tda_fail(ret)) - goto fail; - - /* --------------------------------------------------------------- */ - - N = map->if_freq * 1000 + freq; - - switch (priv->role) { - case TDA18271_MASTER: - tda18271_calc_main_pll(fe, N); - tda18271_set_if_notch(fe); - tda18271_write_regs(fe, R_MPD, 4); - break; - case TDA18271_SLAVE: - tda18271_calc_cal_pll(fe, N); - tda18271_write_regs(fe, R_CPD, 4); - - regs[R_MPD] = regs[R_CPD] & 0x7f; - tda18271_set_if_notch(fe); - tda18271_write_regs(fe, R_MPD, 1); - break; - } - - ret = tda18271_write_regs(fe, R_TM, 7); - if (tda_fail(ret)) - goto fail; - - /* force charge pump source */ - charge_pump_source(fe, 1); - - msleep(1); - - /* return pll to normal operation */ - charge_pump_source(fe, 0); - - msleep(20); - - if (priv->id == TDA18271HDC2) { - /* set rfagc to normal speed mode */ - if (map->fm_rfn) - regs[R_EP3] &= ~0x04; - else - regs[R_EP3] |= 0x04; - ret = tda18271_write_regs(fe, R_EP3, 1); - } -fail: - return ret; -} - -static int tda18271_read_thermometer(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int tm; - - /* switch thermometer on */ - regs[R_TM] |= 0x10; - tda18271_write_regs(fe, R_TM, 1); - - /* read thermometer info */ - tda18271_read_regs(fe); - - if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) || - (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) { - - if ((regs[R_TM] & 0x20) == 0x20) - regs[R_TM] &= ~0x20; - else - regs[R_TM] |= 0x20; - - tda18271_write_regs(fe, R_TM, 1); - - msleep(10); /* temperature sensing */ - - /* read thermometer info */ - tda18271_read_regs(fe); - } - - tm = tda18271_lookup_thermometer(fe); - - /* switch thermometer off */ - regs[R_TM] &= ~0x10; - tda18271_write_regs(fe, R_TM, 1); - - /* set CAL mode to normal */ - regs[R_EP4] &= ~0x03; - tda18271_write_regs(fe, R_EP4, 1); - - return tm; -} - -/* ------------------------------------------------------------------ */ - -static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe, - u32 freq) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; - unsigned char *regs = priv->tda18271_regs; - int i, ret; - u8 tm_current, dc_over_dt, rf_tab; - s32 rfcal_comp, approx; - - /* power up */ - ret = tda18271_set_standby_mode(fe, 0, 0, 0); - if (tda_fail(ret)) - goto fail; - - /* read die current temperature */ - tm_current = tda18271_read_thermometer(fe); - - /* frequency dependent parameters */ - - tda18271_calc_rf_cal(fe, &freq); - rf_tab = regs[R_EB14]; - - i = tda18271_lookup_rf_band(fe, &freq, NULL); - if (tda_fail(i)) - return i; - - if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) { - approx = map[i].rf_a1 * (s32)(freq / 1000 - map[i].rf1) + - map[i].rf_b1 + rf_tab; - } else { - approx = map[i].rf_a2 * (s32)(freq / 1000 - map[i].rf2) + - map[i].rf_b2 + rf_tab; - } - - if (approx < 0) - approx = 0; - if (approx > 255) - approx = 255; - - tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt); - - /* calculate temperature compensation */ - rfcal_comp = dc_over_dt * (s32)(tm_current - priv->tm_rfcal) / 1000; - - regs[R_EB14] = (unsigned char)(approx + rfcal_comp); - ret = tda18271_write_regs(fe, R_EB14, 1); -fail: - return ret; -} - -static int tda18271_por(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int ret; - - /* power up detector 1 */ - regs[R_EB12] &= ~0x20; - ret = tda18271_write_regs(fe, R_EB12, 1); - if (tda_fail(ret)) - goto fail; - - regs[R_EB18] &= ~0x80; /* turn agc1 loop on */ - regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ - ret = tda18271_write_regs(fe, R_EB18, 1); - if (tda_fail(ret)) - goto fail; - - regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */ - - /* POR mode */ - ret = tda18271_set_standby_mode(fe, 1, 0, 0); - if (tda_fail(ret)) - goto fail; - - /* disable 1.5 MHz low pass filter */ - regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */ - regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */ - ret = tda18271_write_regs(fe, R_EB21, 3); -fail: - return ret; -} - -static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u32 N; - - /* set CAL mode to normal */ - regs[R_EP4] &= ~0x03; - tda18271_write_regs(fe, R_EP4, 1); - - /* switch off agc1 */ - regs[R_EP3] |= 0x40; /* sm_lt = 1 */ - - regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */ - tda18271_write_regs(fe, R_EB18, 1); - - /* frequency dependent parameters */ - - tda18271_calc_bp_filter(fe, &freq); - tda18271_calc_gain_taper(fe, &freq); - tda18271_calc_rf_band(fe, &freq); - tda18271_calc_km(fe, &freq); - - tda18271_write_regs(fe, R_EP1, 3); - tda18271_write_regs(fe, R_EB13, 1); - - /* main pll charge pump source */ - tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1); - - /* cal pll charge pump source */ - tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 1); - - /* force dcdc converter to 0 V */ - regs[R_EB14] = 0x00; - tda18271_write_regs(fe, R_EB14, 1); - - /* disable plls lock */ - regs[R_EB20] &= ~0x20; - tda18271_write_regs(fe, R_EB20, 1); - - /* set CAL mode to RF tracking filter calibration */ - regs[R_EP4] |= 0x03; - tda18271_write_regs(fe, R_EP4, 2); - - /* --------------------------------------------------------------- */ - - /* set the internal calibration signal */ - N = freq; - - tda18271_calc_cal_pll(fe, N); - tda18271_write_regs(fe, R_CPD, 4); - - /* downconvert internal calibration */ - N += 1000000; - - tda18271_calc_main_pll(fe, N); - tda18271_write_regs(fe, R_MPD, 4); - - msleep(5); - - tda18271_write_regs(fe, R_EP2, 1); - tda18271_write_regs(fe, R_EP1, 1); - tda18271_write_regs(fe, R_EP2, 1); - tda18271_write_regs(fe, R_EP1, 1); - - /* --------------------------------------------------------------- */ - - /* normal operation for the main pll */ - tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0); - - /* normal operation for the cal pll */ - tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 0); - - msleep(10); /* plls locking */ - - /* launch the rf tracking filters calibration */ - regs[R_EB20] |= 0x20; - tda18271_write_regs(fe, R_EB20, 1); - - msleep(60); /* calibration */ - - /* --------------------------------------------------------------- */ - - /* set CAL mode to normal */ - regs[R_EP4] &= ~0x03; - - /* switch on agc1 */ - regs[R_EP3] &= ~0x40; /* sm_lt = 0 */ - - regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ - tda18271_write_regs(fe, R_EB18, 1); - - tda18271_write_regs(fe, R_EP3, 2); - - /* synchronization */ - tda18271_write_regs(fe, R_EP1, 1); - - /* get calibration result */ - tda18271_read_extended(fe); - - return regs[R_EB14]; -} - -static int tda18271_powerscan(struct dvb_frontend *fe, - u32 *freq_in, u32 *freq_out) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int sgn, bcal, count, wait, ret; - u8 cid_target; - u16 count_limit; - u32 freq; - - freq = *freq_in; - - tda18271_calc_rf_band(fe, &freq); - tda18271_calc_rf_cal(fe, &freq); - tda18271_calc_gain_taper(fe, &freq); - tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit); - - tda18271_write_regs(fe, R_EP2, 1); - tda18271_write_regs(fe, R_EB14, 1); - - /* downconvert frequency */ - freq += 1000000; - - tda18271_calc_main_pll(fe, freq); - tda18271_write_regs(fe, R_MPD, 4); - - msleep(5); /* pll locking */ - - /* detection mode */ - regs[R_EP4] &= ~0x03; - regs[R_EP4] |= 0x01; - tda18271_write_regs(fe, R_EP4, 1); - - /* launch power detection measurement */ - tda18271_write_regs(fe, R_EP2, 1); - - /* read power detection info, stored in EB10 */ - ret = tda18271_read_extended(fe); - if (tda_fail(ret)) - return ret; - - /* algorithm initialization */ - sgn = 1; - *freq_out = *freq_in; - bcal = 0; - count = 0; - wait = false; - - while ((regs[R_EB10] & 0x3f) < cid_target) { - /* downconvert updated freq to 1 MHz */ - freq = *freq_in + (sgn * count) + 1000000; - - tda18271_calc_main_pll(fe, freq); - tda18271_write_regs(fe, R_MPD, 4); - - if (wait) { - msleep(5); /* pll locking */ - wait = false; - } else - udelay(100); /* pll locking */ - - /* launch power detection measurement */ - tda18271_write_regs(fe, R_EP2, 1); - - /* read power detection info, stored in EB10 */ - ret = tda18271_read_extended(fe); - if (tda_fail(ret)) - return ret; - - count += 200; - - if (count <= count_limit) - continue; - - if (sgn <= 0) - break; - - sgn = -1 * sgn; - count = 200; - wait = true; - } - - if ((regs[R_EB10] & 0x3f) >= cid_target) { - bcal = 1; - *freq_out = freq - 1000000; - } else - bcal = 0; - - tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n", - bcal, *freq_in, *freq_out, freq); - - return bcal; -} - -static int tda18271_powerscan_init(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int ret; - - /* set standard to digital */ - regs[R_EP3] &= ~0x1f; /* clear std bits */ - regs[R_EP3] |= 0x12; - - /* set cal mode to normal */ - regs[R_EP4] &= ~0x03; - - /* update IF output level */ - regs[R_EP4] &= ~0x1c; /* clear if level bits */ - - ret = tda18271_write_regs(fe, R_EP3, 2); - if (tda_fail(ret)) - goto fail; - - regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ - ret = tda18271_write_regs(fe, R_EB18, 1); - if (tda_fail(ret)) - goto fail; - - regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */ - - /* 1.5 MHz low pass filter */ - regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */ - regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */ - - ret = tda18271_write_regs(fe, R_EB21, 3); -fail: - return ret; -} - -static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; - unsigned char *regs = priv->tda18271_regs; - int bcal, rf, i; - s32 divisor, dividend; -#define RF1 0 -#define RF2 1 -#define RF3 2 - u32 rf_default[3]; - u32 rf_freq[3]; - s32 prog_cal[3]; - s32 prog_tab[3]; - - i = tda18271_lookup_rf_band(fe, &freq, NULL); - - if (tda_fail(i)) - return i; - - rf_default[RF1] = 1000 * map[i].rf1_def; - rf_default[RF2] = 1000 * map[i].rf2_def; - rf_default[RF3] = 1000 * map[i].rf3_def; - - for (rf = RF1; rf <= RF3; rf++) { - if (0 == rf_default[rf]) - return 0; - tda_cal("freq = %d, rf = %d\n", freq, rf); - - /* look for optimized calibration frequency */ - bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]); - if (tda_fail(bcal)) - return bcal; - - tda18271_calc_rf_cal(fe, &rf_freq[rf]); - prog_tab[rf] = (s32)regs[R_EB14]; - - if (1 == bcal) - prog_cal[rf] = - (s32)tda18271_calibrate_rf(fe, rf_freq[rf]); - else - prog_cal[rf] = prog_tab[rf]; - - switch (rf) { - case RF1: - map[i].rf_a1 = 0; - map[i].rf_b1 = (prog_cal[RF1] - prog_tab[RF1]); - map[i].rf1 = rf_freq[RF1] / 1000; - break; - case RF2: - dividend = (prog_cal[RF2] - prog_tab[RF2] - - prog_cal[RF1] + prog_tab[RF1]); - divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000; - map[i].rf_a1 = (dividend / divisor); - map[i].rf2 = rf_freq[RF2] / 1000; - break; - case RF3: - dividend = (prog_cal[RF3] - prog_tab[RF3] - - prog_cal[RF2] + prog_tab[RF2]); - divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000; - map[i].rf_a2 = (dividend / divisor); - map[i].rf_b2 = (prog_cal[RF2] - prog_tab[RF2]); - map[i].rf3 = rf_freq[RF3] / 1000; - break; - default: - BUG(); - } - } - - return 0; -} - -static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned int i; - int ret; - - tda_info("tda18271: performing RF tracking filter calibration\n"); - - /* wait for die temperature stabilization */ - msleep(200); - - ret = tda18271_powerscan_init(fe); - if (tda_fail(ret)) - goto fail; - - /* rf band calibration */ - for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++) { - ret = - tda18271_rf_tracking_filters_init(fe, 1000 * - priv->rf_cal_state[i].rfmax); - if (tda_fail(ret)) - goto fail; - } - - priv->tm_rfcal = tda18271_read_thermometer(fe); -fail: - return ret; -} - -/* ------------------------------------------------------------------ */ - -static int tda18271c2_rf_cal_init(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int ret; - - /* test RF_CAL_OK to see if we need init */ - if ((regs[R_EP1] & 0x10) == 0) - priv->cal_initialized = false; - - if (priv->cal_initialized) - return 0; - - ret = tda18271_calc_rf_filter_curve(fe); - if (tda_fail(ret)) - goto fail; - - ret = tda18271_por(fe); - if (tda_fail(ret)) - goto fail; - - tda_info("tda18271: RF tracking filter calibration complete\n"); - - priv->cal_initialized = true; - goto end; -fail: - tda_info("tda18271: RF tracking filter calibration failed!\n"); -end: - return ret; -} - -static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe, - u32 freq, u32 bw) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int ret; - u32 N = 0; - - /* calculate bp filter */ - tda18271_calc_bp_filter(fe, &freq); - tda18271_write_regs(fe, R_EP1, 1); - - regs[R_EB4] &= 0x07; - regs[R_EB4] |= 0x60; - tda18271_write_regs(fe, R_EB4, 1); - - regs[R_EB7] = 0x60; - tda18271_write_regs(fe, R_EB7, 1); - - regs[R_EB14] = 0x00; - tda18271_write_regs(fe, R_EB14, 1); - - regs[R_EB20] = 0xcc; - tda18271_write_regs(fe, R_EB20, 1); - - /* set cal mode to RF tracking filter calibration */ - regs[R_EP4] |= 0x03; - - /* calculate cal pll */ - - switch (priv->mode) { - case TDA18271_ANALOG: - N = freq - 1250000; - break; - case TDA18271_DIGITAL: - N = freq + bw / 2; - break; - } - - tda18271_calc_cal_pll(fe, N); - - /* calculate main pll */ - - switch (priv->mode) { - case TDA18271_ANALOG: - N = freq - 250000; - break; - case TDA18271_DIGITAL: - N = freq + bw / 2 + 1000000; - break; - } - - tda18271_calc_main_pll(fe, N); - - ret = tda18271_write_regs(fe, R_EP3, 11); - if (tda_fail(ret)) - return ret; - - msleep(5); /* RF tracking filter calibration initialization */ - - /* search for K,M,CO for RF calibration */ - tda18271_calc_km(fe, &freq); - tda18271_write_regs(fe, R_EB13, 1); - - /* search for rf band */ - tda18271_calc_rf_band(fe, &freq); - - /* search for gain taper */ - tda18271_calc_gain_taper(fe, &freq); - - tda18271_write_regs(fe, R_EP2, 1); - tda18271_write_regs(fe, R_EP1, 1); - tda18271_write_regs(fe, R_EP2, 1); - tda18271_write_regs(fe, R_EP1, 1); - - regs[R_EB4] &= 0x07; - regs[R_EB4] |= 0x40; - tda18271_write_regs(fe, R_EB4, 1); - - regs[R_EB7] = 0x40; - tda18271_write_regs(fe, R_EB7, 1); - msleep(10); /* pll locking */ - - regs[R_EB20] = 0xec; - tda18271_write_regs(fe, R_EB20, 1); - msleep(60); /* RF tracking filter calibration completion */ - - regs[R_EP4] &= ~0x03; /* set cal mode to normal */ - tda18271_write_regs(fe, R_EP4, 1); - - tda18271_write_regs(fe, R_EP1, 1); - - /* RF tracking filter correction for VHF_Low band */ - if (0 == tda18271_calc_rf_cal(fe, &freq)) - tda18271_write_regs(fe, R_EB14, 1); - - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int tda18271_ir_cal_init(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int ret; - - ret = tda18271_read_regs(fe); - if (tda_fail(ret)) - goto fail; - - /* test IR_CAL_OK to see if we need init */ - if ((regs[R_EP1] & 0x08) == 0) - ret = tda18271_init_regs(fe); -fail: - return ret; -} - -static int tda18271_init(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - int ret; - - mutex_lock(&priv->lock); - - /* full power up */ - ret = tda18271_set_standby_mode(fe, 0, 0, 0); - if (tda_fail(ret)) - goto fail; - - /* initialization */ - ret = tda18271_ir_cal_init(fe); - if (tda_fail(ret)) - goto fail; - - if (priv->id == TDA18271HDC2) - tda18271c2_rf_cal_init(fe); -fail: - mutex_unlock(&priv->lock); - - return ret; -} - -static int tda18271_sleep(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - int ret; - - mutex_lock(&priv->lock); - - /* enter standby mode, with required output features enabled */ - ret = tda18271_toggle_output(fe, 1); - - mutex_unlock(&priv->lock); - - return ret; -} - -/* ------------------------------------------------------------------ */ - -static int tda18271_agc(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - int ret = 0; - - switch (priv->config) { - case 0: - /* no external agc configuration required */ - if (tda18271_debug & DBG_ADV) - tda_dbg("no agc configuration provided\n"); - break; - case 3: - /* switch with GPIO of saa713x */ - tda_dbg("invoking callback\n"); - if (fe->callback) - ret = fe->callback(priv->i2c_props.adap->algo_data, - DVB_FRONTEND_COMPONENT_TUNER, - TDA18271_CALLBACK_CMD_AGC_ENABLE, - priv->mode); - break; - case 1: - case 2: - default: - /* n/a - currently not supported */ - tda_err("unsupported configuration: %d\n", priv->config); - ret = -EINVAL; - break; - } - return ret; -} - -static int tda18271_tune(struct dvb_frontend *fe, - struct tda18271_std_map_item *map, u32 freq, u32 bw) -{ - struct tda18271_priv *priv = fe->tuner_priv; - int ret; - - tda_dbg("freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d\n", - freq, map->if_freq, bw, map->agc_mode, map->std); - - ret = tda18271_agc(fe); - if (tda_fail(ret)) - tda_warn("failed to configure agc\n"); - - ret = tda18271_init(fe); - if (tda_fail(ret)) - goto fail; - - mutex_lock(&priv->lock); - - switch (priv->id) { - case TDA18271HDC1: - tda18271c1_rf_tracking_filter_calibration(fe, freq, bw); - break; - case TDA18271HDC2: - tda18271c2_rf_tracking_filters_correction(fe, freq); - break; - } - ret = tda18271_channel_configuration(fe, map, freq, bw); - - mutex_unlock(&priv->lock); -fail: - return ret; -} - -/* ------------------------------------------------------------------ */ - -static int tda18271_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u32 delsys = c->delivery_system; - u32 bw = c->bandwidth_hz; - u32 freq = c->frequency; - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_std_map *std_map = &priv->std; - struct tda18271_std_map_item *map; - int ret; - - priv->mode = TDA18271_DIGITAL; - - switch (delsys) { - case SYS_ATSC: - map = &std_map->atsc_6; - bw = 6000000; - break; - case SYS_ISDBT: - case SYS_DVBT: - case SYS_DVBT2: - if (bw <= 6000000) { - map = &std_map->dvbt_6; - } else if (bw <= 7000000) { - map = &std_map->dvbt_7; - } else { - map = &std_map->dvbt_8; - } - break; - case SYS_DVBC_ANNEX_B: - bw = 6000000; - /* falltrough */ - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - if (bw <= 6000000) { - map = &std_map->qam_6; - } else if (bw <= 7000000) { - map = &std_map->qam_7; - } else { - map = &std_map->qam_8; - } - break; - default: - tda_warn("modulation type not supported!\n"); - return -EINVAL; - } - - /* When tuning digital, the analog demod must be tri-stated */ - if (fe->ops.analog_ops.standby) - fe->ops.analog_ops.standby(fe); - - ret = tda18271_tune(fe, map, freq, bw); - - if (tda_fail(ret)) - goto fail; - - priv->if_freq = map->if_freq; - priv->frequency = freq; - priv->bandwidth = bw; -fail: - return ret; -} - -static int tda18271_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_std_map *std_map = &priv->std; - struct tda18271_std_map_item *map; - char *mode; - int ret; - u32 freq = params->frequency * 125 * - ((params->mode == V4L2_TUNER_RADIO) ? 1 : 1000) / 2; - - priv->mode = TDA18271_ANALOG; - - if (params->mode == V4L2_TUNER_RADIO) { - map = &std_map->fm_radio; - mode = "fm"; - } else if (params->std & V4L2_STD_MN) { - map = &std_map->atv_mn; - mode = "MN"; - } else if (params->std & V4L2_STD_B) { - map = &std_map->atv_b; - mode = "B"; - } else if (params->std & V4L2_STD_GH) { - map = &std_map->atv_gh; - mode = "GH"; - } else if (params->std & V4L2_STD_PAL_I) { - map = &std_map->atv_i; - mode = "I"; - } else if (params->std & V4L2_STD_DK) { - map = &std_map->atv_dk; - mode = "DK"; - } else if (params->std & V4L2_STD_SECAM_L) { - map = &std_map->atv_l; - mode = "L"; - } else if (params->std & V4L2_STD_SECAM_LC) { - map = &std_map->atv_lc; - mode = "L'"; - } else { - map = &std_map->atv_i; - mode = "xx"; - } - - tda_dbg("setting tda18271 to system %s\n", mode); - - ret = tda18271_tune(fe, map, freq, 0); - - if (tda_fail(ret)) - goto fail; - - priv->if_freq = map->if_freq; - priv->frequency = freq; - priv->bandwidth = 0; -fail: - return ret; -} - -static int tda18271_release(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - - mutex_lock(&tda18271_list_mutex); - - if (priv) - hybrid_tuner_release_state(priv); - - mutex_unlock(&tda18271_list_mutex); - - fe->tuner_priv = NULL; - - return 0; -} - -static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tda18271_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct tda18271_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; - return 0; -} - -static int tda18271_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tda18271_priv *priv = fe->tuner_priv; - *frequency = (u32)priv->if_freq * 1000; - return 0; -} - -/* ------------------------------------------------------------------ */ - -#define tda18271_update_std(std_cfg, name) do { \ - if (map->std_cfg.if_freq + \ - map->std_cfg.agc_mode + map->std_cfg.std + \ - map->std_cfg.if_lvl + map->std_cfg.rfagc_top > 0) { \ - tda_dbg("Using custom std config for %s\n", name); \ - memcpy(&std->std_cfg, &map->std_cfg, \ - sizeof(struct tda18271_std_map_item)); \ - } } while (0) - -#define tda18271_dump_std_item(std_cfg, name) do { \ - tda_dbg("(%s) if_freq = %d, agc_mode = %d, std = %d, " \ - "if_lvl = %d, rfagc_top = 0x%02x\n", \ - name, std->std_cfg.if_freq, \ - std->std_cfg.agc_mode, std->std_cfg.std, \ - std->std_cfg.if_lvl, std->std_cfg.rfagc_top); \ - } while (0) - -static int tda18271_dump_std_map(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_std_map *std = &priv->std; - - tda_dbg("========== STANDARD MAP SETTINGS ==========\n"); - tda18271_dump_std_item(fm_radio, " fm "); - tda18271_dump_std_item(atv_b, "atv b "); - tda18271_dump_std_item(atv_dk, "atv dk"); - tda18271_dump_std_item(atv_gh, "atv gh"); - tda18271_dump_std_item(atv_i, "atv i "); - tda18271_dump_std_item(atv_l, "atv l "); - tda18271_dump_std_item(atv_lc, "atv l'"); - tda18271_dump_std_item(atv_mn, "atv mn"); - tda18271_dump_std_item(atsc_6, "atsc 6"); - tda18271_dump_std_item(dvbt_6, "dvbt 6"); - tda18271_dump_std_item(dvbt_7, "dvbt 7"); - tda18271_dump_std_item(dvbt_8, "dvbt 8"); - tda18271_dump_std_item(qam_6, "qam 6 "); - tda18271_dump_std_item(qam_8, "qam 8 "); - - return 0; -} - -static int tda18271_update_std_map(struct dvb_frontend *fe, - struct tda18271_std_map *map) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_std_map *std = &priv->std; - - if (!map) - return -EINVAL; - - tda18271_update_std(fm_radio, "fm"); - tda18271_update_std(atv_b, "atv b"); - tda18271_update_std(atv_dk, "atv dk"); - tda18271_update_std(atv_gh, "atv gh"); - tda18271_update_std(atv_i, "atv i"); - tda18271_update_std(atv_l, "atv l"); - tda18271_update_std(atv_lc, "atv l'"); - tda18271_update_std(atv_mn, "atv mn"); - tda18271_update_std(atsc_6, "atsc 6"); - tda18271_update_std(dvbt_6, "dvbt 6"); - tda18271_update_std(dvbt_7, "dvbt 7"); - tda18271_update_std(dvbt_8, "dvbt 8"); - tda18271_update_std(qam_6, "qam 6"); - tda18271_update_std(qam_8, "qam 8"); - - return 0; -} - -static int tda18271_get_id(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - char *name; - - mutex_lock(&priv->lock); - tda18271_read_regs(fe); - mutex_unlock(&priv->lock); - - switch (regs[R_ID] & 0x7f) { - case 3: - name = "TDA18271HD/C1"; - priv->id = TDA18271HDC1; - break; - case 4: - name = "TDA18271HD/C2"; - priv->id = TDA18271HDC2; - break; - default: - tda_info("Unknown device (%i) detected @ %d-%04x, device not supported.\n", - regs[R_ID], i2c_adapter_id(priv->i2c_props.adap), - priv->i2c_props.addr); - return -EINVAL; - } - - tda_info("%s detected @ %d-%04x\n", name, - i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr); - - return 0; -} - -static int tda18271_setup_configuration(struct dvb_frontend *fe, - struct tda18271_config *cfg) -{ - struct tda18271_priv *priv = fe->tuner_priv; - - priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO; - priv->role = (cfg) ? cfg->role : TDA18271_MASTER; - priv->config = (cfg) ? cfg->config : 0; - priv->small_i2c = (cfg) ? - cfg->small_i2c : TDA18271_39_BYTE_CHUNK_INIT; - priv->output_opt = (cfg) ? - cfg->output_opt : TDA18271_OUTPUT_LT_XT_ON; - - return 0; -} - -static inline int tda18271_need_cal_on_startup(struct tda18271_config *cfg) -{ - /* tda18271_cal_on_startup == -1 when cal module option is unset */ - return ((tda18271_cal_on_startup == -1) ? - /* honor configuration setting */ - ((cfg) && (cfg->rf_cal_on_startup)) : - /* module option overrides configuration setting */ - (tda18271_cal_on_startup)) ? 1 : 0; -} - -static int tda18271_set_config(struct dvb_frontend *fe, void *priv_cfg) -{ - struct tda18271_config *cfg = (struct tda18271_config *) priv_cfg; - - tda18271_setup_configuration(fe, cfg); - - if (tda18271_need_cal_on_startup(cfg)) - tda18271_init(fe); - - /* override default std map with values in config struct */ - if ((cfg) && (cfg->std_map)) - tda18271_update_std_map(fe, cfg->std_map); - - return 0; -} - -static const struct dvb_tuner_ops tda18271_tuner_ops = { - .info = { - .name = "NXP TDA18271HD", - .frequency_min = 45000000, - .frequency_max = 864000000, - .frequency_step = 62500 - }, - .init = tda18271_init, - .sleep = tda18271_sleep, - .set_params = tda18271_set_params, - .set_analog_params = tda18271_set_analog_params, - .release = tda18271_release, - .set_config = tda18271_set_config, - .get_frequency = tda18271_get_frequency, - .get_bandwidth = tda18271_get_bandwidth, - .get_if_frequency = tda18271_get_if_frequency, -}; - -struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, - struct i2c_adapter *i2c, - struct tda18271_config *cfg) -{ - struct tda18271_priv *priv = NULL; - int instance, ret; - - mutex_lock(&tda18271_list_mutex); - - instance = hybrid_tuner_request_state(struct tda18271_priv, priv, - hybrid_tuner_instance_list, - i2c, addr, "tda18271"); - switch (instance) { - case 0: - goto fail; - case 1: - /* new tuner instance */ - fe->tuner_priv = priv; - - tda18271_setup_configuration(fe, cfg); - - priv->cal_initialized = false; - mutex_init(&priv->lock); - - ret = tda18271_get_id(fe); - if (tda_fail(ret)) - goto fail; - - ret = tda18271_assign_map_layout(fe); - if (tda_fail(ret)) - goto fail; - - mutex_lock(&priv->lock); - tda18271_init_regs(fe); - - if ((tda18271_need_cal_on_startup(cfg)) && - (priv->id == TDA18271HDC2)) - tda18271c2_rf_cal_init(fe); - - mutex_unlock(&priv->lock); - break; - default: - /* existing tuner instance */ - fe->tuner_priv = priv; - - /* allow dvb driver to override configuration settings */ - if (cfg) { - if (cfg->gate != TDA18271_GATE_ANALOG) - priv->gate = cfg->gate; - if (cfg->role) - priv->role = cfg->role; - if (cfg->config) - priv->config = cfg->config; - if (cfg->small_i2c) - priv->small_i2c = cfg->small_i2c; - if (cfg->output_opt) - priv->output_opt = cfg->output_opt; - if (cfg->std_map) - tda18271_update_std_map(fe, cfg->std_map); - } - if (tda18271_need_cal_on_startup(cfg)) - tda18271_init(fe); - break; - } - - /* override default std map with values in config struct */ - if ((cfg) && (cfg->std_map)) - tda18271_update_std_map(fe, cfg->std_map); - - mutex_unlock(&tda18271_list_mutex); - - memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - if (tda18271_debug & (DBG_MAP | DBG_ADV)) - tda18271_dump_std_map(fe); - - return fe; -fail: - mutex_unlock(&tda18271_list_mutex); - - tda18271_release(fe); - return NULL; -} -EXPORT_SYMBOL_GPL(tda18271_attach); -MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); -MODULE_AUTHOR("Michael Krufky "); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.4"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/common/tuners/tda18271-maps.c b/drivers/media/common/tuners/tda18271-maps.c deleted file mode 100644 index fb881c667c94..000000000000 --- a/drivers/media/common/tuners/tda18271-maps.c +++ /dev/null @@ -1,1317 +0,0 @@ -/* - tda18271-maps.c - driver for the Philips / NXP TDA18271 silicon tuner - - Copyright (C) 2007, 2008 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 "tda18271-priv.h" - -struct tda18271_pll_map { - u32 lomax; - u8 pd; /* post div */ - u8 d; /* div */ -}; - -struct tda18271_map { - u32 rfmax; - u8 val; -}; - -/*---------------------------------------------------------------------*/ - -static struct tda18271_pll_map tda18271c1_main_pll[] = { - { .lomax = 32000, .pd = 0x5f, .d = 0xf0 }, - { .lomax = 35000, .pd = 0x5e, .d = 0xe0 }, - { .lomax = 37000, .pd = 0x5d, .d = 0xd0 }, - { .lomax = 41000, .pd = 0x5c, .d = 0xc0 }, - { .lomax = 44000, .pd = 0x5b, .d = 0xb0 }, - { .lomax = 49000, .pd = 0x5a, .d = 0xa0 }, - { .lomax = 54000, .pd = 0x59, .d = 0x90 }, - { .lomax = 61000, .pd = 0x58, .d = 0x80 }, - { .lomax = 65000, .pd = 0x4f, .d = 0x78 }, - { .lomax = 70000, .pd = 0x4e, .d = 0x70 }, - { .lomax = 75000, .pd = 0x4d, .d = 0x68 }, - { .lomax = 82000, .pd = 0x4c, .d = 0x60 }, - { .lomax = 89000, .pd = 0x4b, .d = 0x58 }, - { .lomax = 98000, .pd = 0x4a, .d = 0x50 }, - { .lomax = 109000, .pd = 0x49, .d = 0x48 }, - { .lomax = 123000, .pd = 0x48, .d = 0x40 }, - { .lomax = 131000, .pd = 0x3f, .d = 0x3c }, - { .lomax = 141000, .pd = 0x3e, .d = 0x38 }, - { .lomax = 151000, .pd = 0x3d, .d = 0x34 }, - { .lomax = 164000, .pd = 0x3c, .d = 0x30 }, - { .lomax = 179000, .pd = 0x3b, .d = 0x2c }, - { .lomax = 197000, .pd = 0x3a, .d = 0x28 }, - { .lomax = 219000, .pd = 0x39, .d = 0x24 }, - { .lomax = 246000, .pd = 0x38, .d = 0x20 }, - { .lomax = 263000, .pd = 0x2f, .d = 0x1e }, - { .lomax = 282000, .pd = 0x2e, .d = 0x1c }, - { .lomax = 303000, .pd = 0x2d, .d = 0x1a }, - { .lomax = 329000, .pd = 0x2c, .d = 0x18 }, - { .lomax = 359000, .pd = 0x2b, .d = 0x16 }, - { .lomax = 395000, .pd = 0x2a, .d = 0x14 }, - { .lomax = 438000, .pd = 0x29, .d = 0x12 }, - { .lomax = 493000, .pd = 0x28, .d = 0x10 }, - { .lomax = 526000, .pd = 0x1f, .d = 0x0f }, - { .lomax = 564000, .pd = 0x1e, .d = 0x0e }, - { .lomax = 607000, .pd = 0x1d, .d = 0x0d }, - { .lomax = 658000, .pd = 0x1c, .d = 0x0c }, - { .lomax = 718000, .pd = 0x1b, .d = 0x0b }, - { .lomax = 790000, .pd = 0x1a, .d = 0x0a }, - { .lomax = 877000, .pd = 0x19, .d = 0x09 }, - { .lomax = 987000, .pd = 0x18, .d = 0x08 }, - { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ -}; - -static struct tda18271_pll_map tda18271c2_main_pll[] = { - { .lomax = 33125, .pd = 0x57, .d = 0xf0 }, - { .lomax = 35500, .pd = 0x56, .d = 0xe0 }, - { .lomax = 38188, .pd = 0x55, .d = 0xd0 }, - { .lomax = 41375, .pd = 0x54, .d = 0xc0 }, - { .lomax = 45125, .pd = 0x53, .d = 0xb0 }, - { .lomax = 49688, .pd = 0x52, .d = 0xa0 }, - { .lomax = 55188, .pd = 0x51, .d = 0x90 }, - { .lomax = 62125, .pd = 0x50, .d = 0x80 }, - { .lomax = 66250, .pd = 0x47, .d = 0x78 }, - { .lomax = 71000, .pd = 0x46, .d = 0x70 }, - { .lomax = 76375, .pd = 0x45, .d = 0x68 }, - { .lomax = 82750, .pd = 0x44, .d = 0x60 }, - { .lomax = 90250, .pd = 0x43, .d = 0x58 }, - { .lomax = 99375, .pd = 0x42, .d = 0x50 }, - { .lomax = 110375, .pd = 0x41, .d = 0x48 }, - { .lomax = 124250, .pd = 0x40, .d = 0x40 }, - { .lomax = 132500, .pd = 0x37, .d = 0x3c }, - { .lomax = 142000, .pd = 0x36, .d = 0x38 }, - { .lomax = 152750, .pd = 0x35, .d = 0x34 }, - { .lomax = 165500, .pd = 0x34, .d = 0x30 }, - { .lomax = 180500, .pd = 0x33, .d = 0x2c }, - { .lomax = 198750, .pd = 0x32, .d = 0x28 }, - { .lomax = 220750, .pd = 0x31, .d = 0x24 }, - { .lomax = 248500, .pd = 0x30, .d = 0x20 }, - { .lomax = 265000, .pd = 0x27, .d = 0x1e }, - { .lomax = 284000, .pd = 0x26, .d = 0x1c }, - { .lomax = 305500, .pd = 0x25, .d = 0x1a }, - { .lomax = 331000, .pd = 0x24, .d = 0x18 }, - { .lomax = 361000, .pd = 0x23, .d = 0x16 }, - { .lomax = 397500, .pd = 0x22, .d = 0x14 }, - { .lomax = 441500, .pd = 0x21, .d = 0x12 }, - { .lomax = 497000, .pd = 0x20, .d = 0x10 }, - { .lomax = 530000, .pd = 0x17, .d = 0x0f }, - { .lomax = 568000, .pd = 0x16, .d = 0x0e }, - { .lomax = 611000, .pd = 0x15, .d = 0x0d }, - { .lomax = 662000, .pd = 0x14, .d = 0x0c }, - { .lomax = 722000, .pd = 0x13, .d = 0x0b }, - { .lomax = 795000, .pd = 0x12, .d = 0x0a }, - { .lomax = 883000, .pd = 0x11, .d = 0x09 }, - { .lomax = 994000, .pd = 0x10, .d = 0x08 }, - { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ -}; - -static struct tda18271_pll_map tda18271c1_cal_pll[] = { - { .lomax = 33000, .pd = 0xdd, .d = 0xd0 }, - { .lomax = 36000, .pd = 0xdc, .d = 0xc0 }, - { .lomax = 40000, .pd = 0xdb, .d = 0xb0 }, - { .lomax = 44000, .pd = 0xda, .d = 0xa0 }, - { .lomax = 49000, .pd = 0xd9, .d = 0x90 }, - { .lomax = 55000, .pd = 0xd8, .d = 0x80 }, - { .lomax = 63000, .pd = 0xd3, .d = 0x70 }, - { .lomax = 67000, .pd = 0xcd, .d = 0x68 }, - { .lomax = 73000, .pd = 0xcc, .d = 0x60 }, - { .lomax = 80000, .pd = 0xcb, .d = 0x58 }, - { .lomax = 88000, .pd = 0xca, .d = 0x50 }, - { .lomax = 98000, .pd = 0xc9, .d = 0x48 }, - { .lomax = 110000, .pd = 0xc8, .d = 0x40 }, - { .lomax = 126000, .pd = 0xc3, .d = 0x38 }, - { .lomax = 135000, .pd = 0xbd, .d = 0x34 }, - { .lomax = 147000, .pd = 0xbc, .d = 0x30 }, - { .lomax = 160000, .pd = 0xbb, .d = 0x2c }, - { .lomax = 176000, .pd = 0xba, .d = 0x28 }, - { .lomax = 196000, .pd = 0xb9, .d = 0x24 }, - { .lomax = 220000, .pd = 0xb8, .d = 0x20 }, - { .lomax = 252000, .pd = 0xb3, .d = 0x1c }, - { .lomax = 271000, .pd = 0xad, .d = 0x1a }, - { .lomax = 294000, .pd = 0xac, .d = 0x18 }, - { .lomax = 321000, .pd = 0xab, .d = 0x16 }, - { .lomax = 353000, .pd = 0xaa, .d = 0x14 }, - { .lomax = 392000, .pd = 0xa9, .d = 0x12 }, - { .lomax = 441000, .pd = 0xa8, .d = 0x10 }, - { .lomax = 505000, .pd = 0xa3, .d = 0x0e }, - { .lomax = 543000, .pd = 0x9d, .d = 0x0d }, - { .lomax = 589000, .pd = 0x9c, .d = 0x0c }, - { .lomax = 642000, .pd = 0x9b, .d = 0x0b }, - { .lomax = 707000, .pd = 0x9a, .d = 0x0a }, - { .lomax = 785000, .pd = 0x99, .d = 0x09 }, - { .lomax = 883000, .pd = 0x98, .d = 0x08 }, - { .lomax = 1010000, .pd = 0x93, .d = 0x07 }, - { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ -}; - -static struct tda18271_pll_map tda18271c2_cal_pll[] = { - { .lomax = 33813, .pd = 0xdd, .d = 0xd0 }, - { .lomax = 36625, .pd = 0xdc, .d = 0xc0 }, - { .lomax = 39938, .pd = 0xdb, .d = 0xb0 }, - { .lomax = 43938, .pd = 0xda, .d = 0xa0 }, - { .lomax = 48813, .pd = 0xd9, .d = 0x90 }, - { .lomax = 54938, .pd = 0xd8, .d = 0x80 }, - { .lomax = 62813, .pd = 0xd3, .d = 0x70 }, - { .lomax = 67625, .pd = 0xcd, .d = 0x68 }, - { .lomax = 73250, .pd = 0xcc, .d = 0x60 }, - { .lomax = 79875, .pd = 0xcb, .d = 0x58 }, - { .lomax = 87875, .pd = 0xca, .d = 0x50 }, - { .lomax = 97625, .pd = 0xc9, .d = 0x48 }, - { .lomax = 109875, .pd = 0xc8, .d = 0x40 }, - { .lomax = 125625, .pd = 0xc3, .d = 0x38 }, - { .lomax = 135250, .pd = 0xbd, .d = 0x34 }, - { .lomax = 146500, .pd = 0xbc, .d = 0x30 }, - { .lomax = 159750, .pd = 0xbb, .d = 0x2c }, - { .lomax = 175750, .pd = 0xba, .d = 0x28 }, - { .lomax = 195250, .pd = 0xb9, .d = 0x24 }, - { .lomax = 219750, .pd = 0xb8, .d = 0x20 }, - { .lomax = 251250, .pd = 0xb3, .d = 0x1c }, - { .lomax = 270500, .pd = 0xad, .d = 0x1a }, - { .lomax = 293000, .pd = 0xac, .d = 0x18 }, - { .lomax = 319500, .pd = 0xab, .d = 0x16 }, - { .lomax = 351500, .pd = 0xaa, .d = 0x14 }, - { .lomax = 390500, .pd = 0xa9, .d = 0x12 }, - { .lomax = 439500, .pd = 0xa8, .d = 0x10 }, - { .lomax = 502500, .pd = 0xa3, .d = 0x0e }, - { .lomax = 541000, .pd = 0x9d, .d = 0x0d }, - { .lomax = 586000, .pd = 0x9c, .d = 0x0c }, - { .lomax = 639000, .pd = 0x9b, .d = 0x0b }, - { .lomax = 703000, .pd = 0x9a, .d = 0x0a }, - { .lomax = 781000, .pd = 0x99, .d = 0x09 }, - { .lomax = 879000, .pd = 0x98, .d = 0x08 }, - { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271_bp_filter[] = { - { .rfmax = 62000, .val = 0x00 }, - { .rfmax = 84000, .val = 0x01 }, - { .rfmax = 100000, .val = 0x02 }, - { .rfmax = 140000, .val = 0x03 }, - { .rfmax = 170000, .val = 0x04 }, - { .rfmax = 180000, .val = 0x05 }, - { .rfmax = 865000, .val = 0x06 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271c1_km[] = { - { .rfmax = 61100, .val = 0x74 }, - { .rfmax = 350000, .val = 0x40 }, - { .rfmax = 720000, .val = 0x30 }, - { .rfmax = 865000, .val = 0x40 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271c2_km[] = { - { .rfmax = 47900, .val = 0x38 }, - { .rfmax = 61100, .val = 0x44 }, - { .rfmax = 350000, .val = 0x30 }, - { .rfmax = 720000, .val = 0x24 }, - { .rfmax = 865000, .val = 0x3c }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271_rf_band[] = { - { .rfmax = 47900, .val = 0x00 }, - { .rfmax = 61100, .val = 0x01 }, - { .rfmax = 152600, .val = 0x02 }, - { .rfmax = 164700, .val = 0x03 }, - { .rfmax = 203500, .val = 0x04 }, - { .rfmax = 457800, .val = 0x05 }, - { .rfmax = 865000, .val = 0x06 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271_gain_taper[] = { - { .rfmax = 45400, .val = 0x1f }, - { .rfmax = 45800, .val = 0x1e }, - { .rfmax = 46200, .val = 0x1d }, - { .rfmax = 46700, .val = 0x1c }, - { .rfmax = 47100, .val = 0x1b }, - { .rfmax = 47500, .val = 0x1a }, - { .rfmax = 47900, .val = 0x19 }, - { .rfmax = 49600, .val = 0x17 }, - { .rfmax = 51200, .val = 0x16 }, - { .rfmax = 52900, .val = 0x15 }, - { .rfmax = 54500, .val = 0x14 }, - { .rfmax = 56200, .val = 0x13 }, - { .rfmax = 57800, .val = 0x12 }, - { .rfmax = 59500, .val = 0x11 }, - { .rfmax = 61100, .val = 0x10 }, - { .rfmax = 67600, .val = 0x0d }, - { .rfmax = 74200, .val = 0x0c }, - { .rfmax = 80700, .val = 0x0b }, - { .rfmax = 87200, .val = 0x0a }, - { .rfmax = 93800, .val = 0x09 }, - { .rfmax = 100300, .val = 0x08 }, - { .rfmax = 106900, .val = 0x07 }, - { .rfmax = 113400, .val = 0x06 }, - { .rfmax = 119900, .val = 0x05 }, - { .rfmax = 126500, .val = 0x04 }, - { .rfmax = 133000, .val = 0x03 }, - { .rfmax = 139500, .val = 0x02 }, - { .rfmax = 146100, .val = 0x01 }, - { .rfmax = 152600, .val = 0x00 }, - { .rfmax = 154300, .val = 0x1f }, - { .rfmax = 156100, .val = 0x1e }, - { .rfmax = 157800, .val = 0x1d }, - { .rfmax = 159500, .val = 0x1c }, - { .rfmax = 161200, .val = 0x1b }, - { .rfmax = 163000, .val = 0x1a }, - { .rfmax = 164700, .val = 0x19 }, - { .rfmax = 170200, .val = 0x17 }, - { .rfmax = 175800, .val = 0x16 }, - { .rfmax = 181300, .val = 0x15 }, - { .rfmax = 186900, .val = 0x14 }, - { .rfmax = 192400, .val = 0x13 }, - { .rfmax = 198000, .val = 0x12 }, - { .rfmax = 203500, .val = 0x11 }, - { .rfmax = 216200, .val = 0x14 }, - { .rfmax = 228900, .val = 0x13 }, - { .rfmax = 241600, .val = 0x12 }, - { .rfmax = 254400, .val = 0x11 }, - { .rfmax = 267100, .val = 0x10 }, - { .rfmax = 279800, .val = 0x0f }, - { .rfmax = 292500, .val = 0x0e }, - { .rfmax = 305200, .val = 0x0d }, - { .rfmax = 317900, .val = 0x0c }, - { .rfmax = 330700, .val = 0x0b }, - { .rfmax = 343400, .val = 0x0a }, - { .rfmax = 356100, .val = 0x09 }, - { .rfmax = 368800, .val = 0x08 }, - { .rfmax = 381500, .val = 0x07 }, - { .rfmax = 394200, .val = 0x06 }, - { .rfmax = 406900, .val = 0x05 }, - { .rfmax = 419700, .val = 0x04 }, - { .rfmax = 432400, .val = 0x03 }, - { .rfmax = 445100, .val = 0x02 }, - { .rfmax = 457800, .val = 0x01 }, - { .rfmax = 476300, .val = 0x19 }, - { .rfmax = 494800, .val = 0x18 }, - { .rfmax = 513300, .val = 0x17 }, - { .rfmax = 531800, .val = 0x16 }, - { .rfmax = 550300, .val = 0x15 }, - { .rfmax = 568900, .val = 0x14 }, - { .rfmax = 587400, .val = 0x13 }, - { .rfmax = 605900, .val = 0x12 }, - { .rfmax = 624400, .val = 0x11 }, - { .rfmax = 642900, .val = 0x10 }, - { .rfmax = 661400, .val = 0x0f }, - { .rfmax = 679900, .val = 0x0e }, - { .rfmax = 698400, .val = 0x0d }, - { .rfmax = 716900, .val = 0x0c }, - { .rfmax = 735400, .val = 0x0b }, - { .rfmax = 753900, .val = 0x0a }, - { .rfmax = 772500, .val = 0x09 }, - { .rfmax = 791000, .val = 0x08 }, - { .rfmax = 809500, .val = 0x07 }, - { .rfmax = 828000, .val = 0x06 }, - { .rfmax = 846500, .val = 0x05 }, - { .rfmax = 865000, .val = 0x04 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271c1_rf_cal[] = { - { .rfmax = 41000, .val = 0x1e }, - { .rfmax = 43000, .val = 0x30 }, - { .rfmax = 45000, .val = 0x43 }, - { .rfmax = 46000, .val = 0x4d }, - { .rfmax = 47000, .val = 0x54 }, - { .rfmax = 47900, .val = 0x64 }, - { .rfmax = 49100, .val = 0x20 }, - { .rfmax = 50000, .val = 0x22 }, - { .rfmax = 51000, .val = 0x2a }, - { .rfmax = 53000, .val = 0x32 }, - { .rfmax = 55000, .val = 0x35 }, - { .rfmax = 56000, .val = 0x3c }, - { .rfmax = 57000, .val = 0x3f }, - { .rfmax = 58000, .val = 0x48 }, - { .rfmax = 59000, .val = 0x4d }, - { .rfmax = 60000, .val = 0x58 }, - { .rfmax = 61100, .val = 0x5f }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271c2_rf_cal[] = { - { .rfmax = 41000, .val = 0x0f }, - { .rfmax = 43000, .val = 0x1c }, - { .rfmax = 45000, .val = 0x2f }, - { .rfmax = 46000, .val = 0x39 }, - { .rfmax = 47000, .val = 0x40 }, - { .rfmax = 47900, .val = 0x50 }, - { .rfmax = 49100, .val = 0x16 }, - { .rfmax = 50000, .val = 0x18 }, - { .rfmax = 51000, .val = 0x20 }, - { .rfmax = 53000, .val = 0x28 }, - { .rfmax = 55000, .val = 0x2b }, - { .rfmax = 56000, .val = 0x32 }, - { .rfmax = 57000, .val = 0x35 }, - { .rfmax = 58000, .val = 0x3e }, - { .rfmax = 59000, .val = 0x43 }, - { .rfmax = 60000, .val = 0x4e }, - { .rfmax = 61100, .val = 0x55 }, - { .rfmax = 63000, .val = 0x0f }, - { .rfmax = 64000, .val = 0x11 }, - { .rfmax = 65000, .val = 0x12 }, - { .rfmax = 66000, .val = 0x15 }, - { .rfmax = 67000, .val = 0x16 }, - { .rfmax = 68000, .val = 0x17 }, - { .rfmax = 70000, .val = 0x19 }, - { .rfmax = 71000, .val = 0x1c }, - { .rfmax = 72000, .val = 0x1d }, - { .rfmax = 73000, .val = 0x1f }, - { .rfmax = 74000, .val = 0x20 }, - { .rfmax = 75000, .val = 0x21 }, - { .rfmax = 76000, .val = 0x24 }, - { .rfmax = 77000, .val = 0x25 }, - { .rfmax = 78000, .val = 0x27 }, - { .rfmax = 80000, .val = 0x28 }, - { .rfmax = 81000, .val = 0x29 }, - { .rfmax = 82000, .val = 0x2d }, - { .rfmax = 83000, .val = 0x2e }, - { .rfmax = 84000, .val = 0x2f }, - { .rfmax = 85000, .val = 0x31 }, - { .rfmax = 86000, .val = 0x33 }, - { .rfmax = 87000, .val = 0x34 }, - { .rfmax = 88000, .val = 0x35 }, - { .rfmax = 89000, .val = 0x37 }, - { .rfmax = 90000, .val = 0x38 }, - { .rfmax = 91000, .val = 0x39 }, - { .rfmax = 93000, .val = 0x3c }, - { .rfmax = 94000, .val = 0x3e }, - { .rfmax = 95000, .val = 0x3f }, - { .rfmax = 96000, .val = 0x40 }, - { .rfmax = 97000, .val = 0x42 }, - { .rfmax = 99000, .val = 0x45 }, - { .rfmax = 100000, .val = 0x46 }, - { .rfmax = 102000, .val = 0x48 }, - { .rfmax = 103000, .val = 0x4a }, - { .rfmax = 105000, .val = 0x4d }, - { .rfmax = 106000, .val = 0x4e }, - { .rfmax = 107000, .val = 0x50 }, - { .rfmax = 108000, .val = 0x51 }, - { .rfmax = 110000, .val = 0x54 }, - { .rfmax = 111000, .val = 0x56 }, - { .rfmax = 112000, .val = 0x57 }, - { .rfmax = 113000, .val = 0x58 }, - { .rfmax = 114000, .val = 0x59 }, - { .rfmax = 115000, .val = 0x5c }, - { .rfmax = 116000, .val = 0x5d }, - { .rfmax = 117000, .val = 0x5f }, - { .rfmax = 119000, .val = 0x60 }, - { .rfmax = 120000, .val = 0x64 }, - { .rfmax = 121000, .val = 0x65 }, - { .rfmax = 122000, .val = 0x66 }, - { .rfmax = 123000, .val = 0x68 }, - { .rfmax = 124000, .val = 0x69 }, - { .rfmax = 125000, .val = 0x6c }, - { .rfmax = 126000, .val = 0x6d }, - { .rfmax = 127000, .val = 0x6e }, - { .rfmax = 128000, .val = 0x70 }, - { .rfmax = 129000, .val = 0x71 }, - { .rfmax = 130000, .val = 0x75 }, - { .rfmax = 131000, .val = 0x77 }, - { .rfmax = 132000, .val = 0x78 }, - { .rfmax = 133000, .val = 0x7b }, - { .rfmax = 134000, .val = 0x7e }, - { .rfmax = 135000, .val = 0x81 }, - { .rfmax = 136000, .val = 0x82 }, - { .rfmax = 137000, .val = 0x87 }, - { .rfmax = 138000, .val = 0x88 }, - { .rfmax = 139000, .val = 0x8d }, - { .rfmax = 140000, .val = 0x8e }, - { .rfmax = 141000, .val = 0x91 }, - { .rfmax = 142000, .val = 0x95 }, - { .rfmax = 143000, .val = 0x9a }, - { .rfmax = 144000, .val = 0x9d }, - { .rfmax = 145000, .val = 0xa1 }, - { .rfmax = 146000, .val = 0xa2 }, - { .rfmax = 147000, .val = 0xa4 }, - { .rfmax = 148000, .val = 0xa9 }, - { .rfmax = 149000, .val = 0xae }, - { .rfmax = 150000, .val = 0xb0 }, - { .rfmax = 151000, .val = 0xb1 }, - { .rfmax = 152000, .val = 0xb7 }, - { .rfmax = 152600, .val = 0xbd }, - { .rfmax = 154000, .val = 0x20 }, - { .rfmax = 155000, .val = 0x22 }, - { .rfmax = 156000, .val = 0x24 }, - { .rfmax = 157000, .val = 0x25 }, - { .rfmax = 158000, .val = 0x27 }, - { .rfmax = 159000, .val = 0x29 }, - { .rfmax = 160000, .val = 0x2c }, - { .rfmax = 161000, .val = 0x2d }, - { .rfmax = 163000, .val = 0x2e }, - { .rfmax = 164000, .val = 0x2f }, - { .rfmax = 164700, .val = 0x30 }, - { .rfmax = 166000, .val = 0x11 }, - { .rfmax = 167000, .val = 0x12 }, - { .rfmax = 168000, .val = 0x13 }, - { .rfmax = 169000, .val = 0x14 }, - { .rfmax = 170000, .val = 0x15 }, - { .rfmax = 172000, .val = 0x16 }, - { .rfmax = 173000, .val = 0x17 }, - { .rfmax = 174000, .val = 0x18 }, - { .rfmax = 175000, .val = 0x1a }, - { .rfmax = 176000, .val = 0x1b }, - { .rfmax = 178000, .val = 0x1d }, - { .rfmax = 179000, .val = 0x1e }, - { .rfmax = 180000, .val = 0x1f }, - { .rfmax = 181000, .val = 0x20 }, - { .rfmax = 182000, .val = 0x21 }, - { .rfmax = 183000, .val = 0x22 }, - { .rfmax = 184000, .val = 0x24 }, - { .rfmax = 185000, .val = 0x25 }, - { .rfmax = 186000, .val = 0x26 }, - { .rfmax = 187000, .val = 0x27 }, - { .rfmax = 188000, .val = 0x29 }, - { .rfmax = 189000, .val = 0x2a }, - { .rfmax = 190000, .val = 0x2c }, - { .rfmax = 191000, .val = 0x2d }, - { .rfmax = 192000, .val = 0x2e }, - { .rfmax = 193000, .val = 0x2f }, - { .rfmax = 194000, .val = 0x30 }, - { .rfmax = 195000, .val = 0x33 }, - { .rfmax = 196000, .val = 0x35 }, - { .rfmax = 198000, .val = 0x36 }, - { .rfmax = 200000, .val = 0x38 }, - { .rfmax = 201000, .val = 0x3c }, - { .rfmax = 202000, .val = 0x3d }, - { .rfmax = 203500, .val = 0x3e }, - { .rfmax = 206000, .val = 0x0e }, - { .rfmax = 208000, .val = 0x0f }, - { .rfmax = 212000, .val = 0x10 }, - { .rfmax = 216000, .val = 0x11 }, - { .rfmax = 217000, .val = 0x12 }, - { .rfmax = 218000, .val = 0x13 }, - { .rfmax = 220000, .val = 0x14 }, - { .rfmax = 222000, .val = 0x15 }, - { .rfmax = 225000, .val = 0x16 }, - { .rfmax = 228000, .val = 0x17 }, - { .rfmax = 231000, .val = 0x18 }, - { .rfmax = 234000, .val = 0x19 }, - { .rfmax = 235000, .val = 0x1a }, - { .rfmax = 236000, .val = 0x1b }, - { .rfmax = 237000, .val = 0x1c }, - { .rfmax = 240000, .val = 0x1d }, - { .rfmax = 242000, .val = 0x1e }, - { .rfmax = 244000, .val = 0x1f }, - { .rfmax = 247000, .val = 0x20 }, - { .rfmax = 249000, .val = 0x21 }, - { .rfmax = 252000, .val = 0x22 }, - { .rfmax = 253000, .val = 0x23 }, - { .rfmax = 254000, .val = 0x24 }, - { .rfmax = 256000, .val = 0x25 }, - { .rfmax = 259000, .val = 0x26 }, - { .rfmax = 262000, .val = 0x27 }, - { .rfmax = 264000, .val = 0x28 }, - { .rfmax = 267000, .val = 0x29 }, - { .rfmax = 269000, .val = 0x2a }, - { .rfmax = 271000, .val = 0x2b }, - { .rfmax = 273000, .val = 0x2c }, - { .rfmax = 275000, .val = 0x2d }, - { .rfmax = 277000, .val = 0x2e }, - { .rfmax = 279000, .val = 0x2f }, - { .rfmax = 282000, .val = 0x30 }, - { .rfmax = 284000, .val = 0x31 }, - { .rfmax = 286000, .val = 0x32 }, - { .rfmax = 287000, .val = 0x33 }, - { .rfmax = 290000, .val = 0x34 }, - { .rfmax = 293000, .val = 0x35 }, - { .rfmax = 295000, .val = 0x36 }, - { .rfmax = 297000, .val = 0x37 }, - { .rfmax = 300000, .val = 0x38 }, - { .rfmax = 303000, .val = 0x39 }, - { .rfmax = 305000, .val = 0x3a }, - { .rfmax = 306000, .val = 0x3b }, - { .rfmax = 307000, .val = 0x3c }, - { .rfmax = 310000, .val = 0x3d }, - { .rfmax = 312000, .val = 0x3e }, - { .rfmax = 315000, .val = 0x3f }, - { .rfmax = 318000, .val = 0x40 }, - { .rfmax = 320000, .val = 0x41 }, - { .rfmax = 323000, .val = 0x42 }, - { .rfmax = 324000, .val = 0x43 }, - { .rfmax = 325000, .val = 0x44 }, - { .rfmax = 327000, .val = 0x45 }, - { .rfmax = 331000, .val = 0x46 }, - { .rfmax = 334000, .val = 0x47 }, - { .rfmax = 337000, .val = 0x48 }, - { .rfmax = 339000, .val = 0x49 }, - { .rfmax = 340000, .val = 0x4a }, - { .rfmax = 341000, .val = 0x4b }, - { .rfmax = 343000, .val = 0x4c }, - { .rfmax = 345000, .val = 0x4d }, - { .rfmax = 349000, .val = 0x4e }, - { .rfmax = 352000, .val = 0x4f }, - { .rfmax = 353000, .val = 0x50 }, - { .rfmax = 355000, .val = 0x51 }, - { .rfmax = 357000, .val = 0x52 }, - { .rfmax = 359000, .val = 0x53 }, - { .rfmax = 361000, .val = 0x54 }, - { .rfmax = 362000, .val = 0x55 }, - { .rfmax = 364000, .val = 0x56 }, - { .rfmax = 368000, .val = 0x57 }, - { .rfmax = 370000, .val = 0x58 }, - { .rfmax = 372000, .val = 0x59 }, - { .rfmax = 375000, .val = 0x5a }, - { .rfmax = 376000, .val = 0x5b }, - { .rfmax = 377000, .val = 0x5c }, - { .rfmax = 379000, .val = 0x5d }, - { .rfmax = 382000, .val = 0x5e }, - { .rfmax = 384000, .val = 0x5f }, - { .rfmax = 385000, .val = 0x60 }, - { .rfmax = 386000, .val = 0x61 }, - { .rfmax = 388000, .val = 0x62 }, - { .rfmax = 390000, .val = 0x63 }, - { .rfmax = 393000, .val = 0x64 }, - { .rfmax = 394000, .val = 0x65 }, - { .rfmax = 396000, .val = 0x66 }, - { .rfmax = 397000, .val = 0x67 }, - { .rfmax = 398000, .val = 0x68 }, - { .rfmax = 400000, .val = 0x69 }, - { .rfmax = 402000, .val = 0x6a }, - { .rfmax = 403000, .val = 0x6b }, - { .rfmax = 407000, .val = 0x6c }, - { .rfmax = 408000, .val = 0x6d }, - { .rfmax = 409000, .val = 0x6e }, - { .rfmax = 410000, .val = 0x6f }, - { .rfmax = 411000, .val = 0x70 }, - { .rfmax = 412000, .val = 0x71 }, - { .rfmax = 413000, .val = 0x72 }, - { .rfmax = 414000, .val = 0x73 }, - { .rfmax = 417000, .val = 0x74 }, - { .rfmax = 418000, .val = 0x75 }, - { .rfmax = 420000, .val = 0x76 }, - { .rfmax = 422000, .val = 0x77 }, - { .rfmax = 423000, .val = 0x78 }, - { .rfmax = 424000, .val = 0x79 }, - { .rfmax = 427000, .val = 0x7a }, - { .rfmax = 428000, .val = 0x7b }, - { .rfmax = 429000, .val = 0x7d }, - { .rfmax = 432000, .val = 0x7f }, - { .rfmax = 434000, .val = 0x80 }, - { .rfmax = 435000, .val = 0x81 }, - { .rfmax = 436000, .val = 0x83 }, - { .rfmax = 437000, .val = 0x84 }, - { .rfmax = 438000, .val = 0x85 }, - { .rfmax = 439000, .val = 0x86 }, - { .rfmax = 440000, .val = 0x87 }, - { .rfmax = 441000, .val = 0x88 }, - { .rfmax = 442000, .val = 0x89 }, - { .rfmax = 445000, .val = 0x8a }, - { .rfmax = 446000, .val = 0x8b }, - { .rfmax = 447000, .val = 0x8c }, - { .rfmax = 448000, .val = 0x8e }, - { .rfmax = 449000, .val = 0x8f }, - { .rfmax = 450000, .val = 0x90 }, - { .rfmax = 452000, .val = 0x91 }, - { .rfmax = 453000, .val = 0x93 }, - { .rfmax = 454000, .val = 0x94 }, - { .rfmax = 456000, .val = 0x96 }, - { .rfmax = 457800, .val = 0x98 }, - { .rfmax = 461000, .val = 0x11 }, - { .rfmax = 468000, .val = 0x12 }, - { .rfmax = 472000, .val = 0x13 }, - { .rfmax = 473000, .val = 0x14 }, - { .rfmax = 474000, .val = 0x15 }, - { .rfmax = 481000, .val = 0x16 }, - { .rfmax = 486000, .val = 0x17 }, - { .rfmax = 491000, .val = 0x18 }, - { .rfmax = 498000, .val = 0x19 }, - { .rfmax = 499000, .val = 0x1a }, - { .rfmax = 501000, .val = 0x1b }, - { .rfmax = 506000, .val = 0x1c }, - { .rfmax = 511000, .val = 0x1d }, - { .rfmax = 516000, .val = 0x1e }, - { .rfmax = 520000, .val = 0x1f }, - { .rfmax = 521000, .val = 0x20 }, - { .rfmax = 525000, .val = 0x21 }, - { .rfmax = 529000, .val = 0x22 }, - { .rfmax = 533000, .val = 0x23 }, - { .rfmax = 539000, .val = 0x24 }, - { .rfmax = 541000, .val = 0x25 }, - { .rfmax = 547000, .val = 0x26 }, - { .rfmax = 549000, .val = 0x27 }, - { .rfmax = 551000, .val = 0x28 }, - { .rfmax = 556000, .val = 0x29 }, - { .rfmax = 561000, .val = 0x2a }, - { .rfmax = 563000, .val = 0x2b }, - { .rfmax = 565000, .val = 0x2c }, - { .rfmax = 569000, .val = 0x2d }, - { .rfmax = 571000, .val = 0x2e }, - { .rfmax = 577000, .val = 0x2f }, - { .rfmax = 580000, .val = 0x30 }, - { .rfmax = 582000, .val = 0x31 }, - { .rfmax = 584000, .val = 0x32 }, - { .rfmax = 588000, .val = 0x33 }, - { .rfmax = 591000, .val = 0x34 }, - { .rfmax = 596000, .val = 0x35 }, - { .rfmax = 598000, .val = 0x36 }, - { .rfmax = 603000, .val = 0x37 }, - { .rfmax = 604000, .val = 0x38 }, - { .rfmax = 606000, .val = 0x39 }, - { .rfmax = 612000, .val = 0x3a }, - { .rfmax = 615000, .val = 0x3b }, - { .rfmax = 617000, .val = 0x3c }, - { .rfmax = 621000, .val = 0x3d }, - { .rfmax = 622000, .val = 0x3e }, - { .rfmax = 625000, .val = 0x3f }, - { .rfmax = 632000, .val = 0x40 }, - { .rfmax = 633000, .val = 0x41 }, - { .rfmax = 634000, .val = 0x42 }, - { .rfmax = 642000, .val = 0x43 }, - { .rfmax = 643000, .val = 0x44 }, - { .rfmax = 647000, .val = 0x45 }, - { .rfmax = 650000, .val = 0x46 }, - { .rfmax = 652000, .val = 0x47 }, - { .rfmax = 657000, .val = 0x48 }, - { .rfmax = 661000, .val = 0x49 }, - { .rfmax = 662000, .val = 0x4a }, - { .rfmax = 665000, .val = 0x4b }, - { .rfmax = 667000, .val = 0x4c }, - { .rfmax = 670000, .val = 0x4d }, - { .rfmax = 673000, .val = 0x4e }, - { .rfmax = 676000, .val = 0x4f }, - { .rfmax = 677000, .val = 0x50 }, - { .rfmax = 681000, .val = 0x51 }, - { .rfmax = 683000, .val = 0x52 }, - { .rfmax = 686000, .val = 0x53 }, - { .rfmax = 688000, .val = 0x54 }, - { .rfmax = 689000, .val = 0x55 }, - { .rfmax = 691000, .val = 0x56 }, - { .rfmax = 695000, .val = 0x57 }, - { .rfmax = 698000, .val = 0x58 }, - { .rfmax = 703000, .val = 0x59 }, - { .rfmax = 704000, .val = 0x5a }, - { .rfmax = 705000, .val = 0x5b }, - { .rfmax = 707000, .val = 0x5c }, - { .rfmax = 710000, .val = 0x5d }, - { .rfmax = 712000, .val = 0x5e }, - { .rfmax = 717000, .val = 0x5f }, - { .rfmax = 718000, .val = 0x60 }, - { .rfmax = 721000, .val = 0x61 }, - { .rfmax = 722000, .val = 0x62 }, - { .rfmax = 723000, .val = 0x63 }, - { .rfmax = 725000, .val = 0x64 }, - { .rfmax = 727000, .val = 0x65 }, - { .rfmax = 730000, .val = 0x66 }, - { .rfmax = 732000, .val = 0x67 }, - { .rfmax = 735000, .val = 0x68 }, - { .rfmax = 740000, .val = 0x69 }, - { .rfmax = 741000, .val = 0x6a }, - { .rfmax = 742000, .val = 0x6b }, - { .rfmax = 743000, .val = 0x6c }, - { .rfmax = 745000, .val = 0x6d }, - { .rfmax = 747000, .val = 0x6e }, - { .rfmax = 748000, .val = 0x6f }, - { .rfmax = 750000, .val = 0x70 }, - { .rfmax = 752000, .val = 0x71 }, - { .rfmax = 754000, .val = 0x72 }, - { .rfmax = 757000, .val = 0x73 }, - { .rfmax = 758000, .val = 0x74 }, - { .rfmax = 760000, .val = 0x75 }, - { .rfmax = 763000, .val = 0x76 }, - { .rfmax = 764000, .val = 0x77 }, - { .rfmax = 766000, .val = 0x78 }, - { .rfmax = 767000, .val = 0x79 }, - { .rfmax = 768000, .val = 0x7a }, - { .rfmax = 773000, .val = 0x7b }, - { .rfmax = 774000, .val = 0x7c }, - { .rfmax = 776000, .val = 0x7d }, - { .rfmax = 777000, .val = 0x7e }, - { .rfmax = 778000, .val = 0x7f }, - { .rfmax = 779000, .val = 0x80 }, - { .rfmax = 781000, .val = 0x81 }, - { .rfmax = 783000, .val = 0x82 }, - { .rfmax = 784000, .val = 0x83 }, - { .rfmax = 785000, .val = 0x84 }, - { .rfmax = 786000, .val = 0x85 }, - { .rfmax = 793000, .val = 0x86 }, - { .rfmax = 794000, .val = 0x87 }, - { .rfmax = 795000, .val = 0x88 }, - { .rfmax = 797000, .val = 0x89 }, - { .rfmax = 799000, .val = 0x8a }, - { .rfmax = 801000, .val = 0x8b }, - { .rfmax = 802000, .val = 0x8c }, - { .rfmax = 803000, .val = 0x8d }, - { .rfmax = 804000, .val = 0x8e }, - { .rfmax = 810000, .val = 0x90 }, - { .rfmax = 811000, .val = 0x91 }, - { .rfmax = 812000, .val = 0x92 }, - { .rfmax = 814000, .val = 0x93 }, - { .rfmax = 816000, .val = 0x94 }, - { .rfmax = 817000, .val = 0x96 }, - { .rfmax = 818000, .val = 0x97 }, - { .rfmax = 820000, .val = 0x98 }, - { .rfmax = 821000, .val = 0x99 }, - { .rfmax = 822000, .val = 0x9a }, - { .rfmax = 828000, .val = 0x9b }, - { .rfmax = 829000, .val = 0x9d }, - { .rfmax = 830000, .val = 0x9f }, - { .rfmax = 831000, .val = 0xa0 }, - { .rfmax = 833000, .val = 0xa1 }, - { .rfmax = 835000, .val = 0xa2 }, - { .rfmax = 836000, .val = 0xa3 }, - { .rfmax = 837000, .val = 0xa4 }, - { .rfmax = 838000, .val = 0xa6 }, - { .rfmax = 840000, .val = 0xa8 }, - { .rfmax = 842000, .val = 0xa9 }, - { .rfmax = 845000, .val = 0xaa }, - { .rfmax = 846000, .val = 0xab }, - { .rfmax = 847000, .val = 0xad }, - { .rfmax = 848000, .val = 0xae }, - { .rfmax = 852000, .val = 0xaf }, - { .rfmax = 853000, .val = 0xb0 }, - { .rfmax = 858000, .val = 0xb1 }, - { .rfmax = 860000, .val = 0xb2 }, - { .rfmax = 861000, .val = 0xb3 }, - { .rfmax = 862000, .val = 0xb4 }, - { .rfmax = 863000, .val = 0xb6 }, - { .rfmax = 864000, .val = 0xb8 }, - { .rfmax = 865000, .val = 0xb9 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271_ir_measure[] = { - { .rfmax = 30000, .val = 4 }, - { .rfmax = 200000, .val = 5 }, - { .rfmax = 600000, .val = 6 }, - { .rfmax = 865000, .val = 7 }, - { .rfmax = 0, .val = 0 }, /* end */ -}; - -static struct tda18271_map tda18271_rf_cal_dc_over_dt[] = { - { .rfmax = 47900, .val = 0x00 }, - { .rfmax = 55000, .val = 0x00 }, - { .rfmax = 61100, .val = 0x0a }, - { .rfmax = 64000, .val = 0x0a }, - { .rfmax = 82000, .val = 0x14 }, - { .rfmax = 84000, .val = 0x19 }, - { .rfmax = 119000, .val = 0x1c }, - { .rfmax = 124000, .val = 0x20 }, - { .rfmax = 129000, .val = 0x2a }, - { .rfmax = 134000, .val = 0x32 }, - { .rfmax = 139000, .val = 0x39 }, - { .rfmax = 144000, .val = 0x3e }, - { .rfmax = 149000, .val = 0x3f }, - { .rfmax = 152600, .val = 0x40 }, - { .rfmax = 154000, .val = 0x40 }, - { .rfmax = 164700, .val = 0x41 }, - { .rfmax = 203500, .val = 0x32 }, - { .rfmax = 353000, .val = 0x19 }, - { .rfmax = 356000, .val = 0x1a }, - { .rfmax = 359000, .val = 0x1b }, - { .rfmax = 363000, .val = 0x1c }, - { .rfmax = 366000, .val = 0x1d }, - { .rfmax = 369000, .val = 0x1e }, - { .rfmax = 373000, .val = 0x1f }, - { .rfmax = 376000, .val = 0x20 }, - { .rfmax = 379000, .val = 0x21 }, - { .rfmax = 383000, .val = 0x22 }, - { .rfmax = 386000, .val = 0x23 }, - { .rfmax = 389000, .val = 0x24 }, - { .rfmax = 393000, .val = 0x25 }, - { .rfmax = 396000, .val = 0x26 }, - { .rfmax = 399000, .val = 0x27 }, - { .rfmax = 402000, .val = 0x28 }, - { .rfmax = 404000, .val = 0x29 }, - { .rfmax = 407000, .val = 0x2a }, - { .rfmax = 409000, .val = 0x2b }, - { .rfmax = 412000, .val = 0x2c }, - { .rfmax = 414000, .val = 0x2d }, - { .rfmax = 417000, .val = 0x2e }, - { .rfmax = 419000, .val = 0x2f }, - { .rfmax = 422000, .val = 0x30 }, - { .rfmax = 424000, .val = 0x31 }, - { .rfmax = 427000, .val = 0x32 }, - { .rfmax = 429000, .val = 0x33 }, - { .rfmax = 432000, .val = 0x34 }, - { .rfmax = 434000, .val = 0x35 }, - { .rfmax = 437000, .val = 0x36 }, - { .rfmax = 439000, .val = 0x37 }, - { .rfmax = 442000, .val = 0x38 }, - { .rfmax = 444000, .val = 0x39 }, - { .rfmax = 447000, .val = 0x3a }, - { .rfmax = 449000, .val = 0x3b }, - { .rfmax = 457800, .val = 0x3c }, - { .rfmax = 465000, .val = 0x0f }, - { .rfmax = 477000, .val = 0x12 }, - { .rfmax = 483000, .val = 0x14 }, - { .rfmax = 502000, .val = 0x19 }, - { .rfmax = 508000, .val = 0x1b }, - { .rfmax = 519000, .val = 0x1c }, - { .rfmax = 522000, .val = 0x1d }, - { .rfmax = 524000, .val = 0x1e }, - { .rfmax = 534000, .val = 0x1f }, - { .rfmax = 549000, .val = 0x20 }, - { .rfmax = 554000, .val = 0x22 }, - { .rfmax = 584000, .val = 0x24 }, - { .rfmax = 589000, .val = 0x26 }, - { .rfmax = 658000, .val = 0x27 }, - { .rfmax = 664000, .val = 0x2c }, - { .rfmax = 669000, .val = 0x2d }, - { .rfmax = 699000, .val = 0x2e }, - { .rfmax = 704000, .val = 0x30 }, - { .rfmax = 709000, .val = 0x31 }, - { .rfmax = 714000, .val = 0x32 }, - { .rfmax = 724000, .val = 0x33 }, - { .rfmax = 729000, .val = 0x36 }, - { .rfmax = 739000, .val = 0x38 }, - { .rfmax = 744000, .val = 0x39 }, - { .rfmax = 749000, .val = 0x3b }, - { .rfmax = 754000, .val = 0x3c }, - { .rfmax = 759000, .val = 0x3d }, - { .rfmax = 764000, .val = 0x3e }, - { .rfmax = 769000, .val = 0x3f }, - { .rfmax = 774000, .val = 0x40 }, - { .rfmax = 779000, .val = 0x41 }, - { .rfmax = 784000, .val = 0x43 }, - { .rfmax = 789000, .val = 0x46 }, - { .rfmax = 794000, .val = 0x48 }, - { .rfmax = 799000, .val = 0x4b }, - { .rfmax = 804000, .val = 0x4f }, - { .rfmax = 809000, .val = 0x54 }, - { .rfmax = 814000, .val = 0x59 }, - { .rfmax = 819000, .val = 0x5d }, - { .rfmax = 824000, .val = 0x61 }, - { .rfmax = 829000, .val = 0x68 }, - { .rfmax = 834000, .val = 0x6e }, - { .rfmax = 839000, .val = 0x75 }, - { .rfmax = 844000, .val = 0x7e }, - { .rfmax = 849000, .val = 0x82 }, - { .rfmax = 854000, .val = 0x84 }, - { .rfmax = 859000, .val = 0x8f }, - { .rfmax = 865000, .val = 0x9a }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -/*---------------------------------------------------------------------*/ - -struct tda18271_thermo_map { - u8 d; - u8 r0; - u8 r1; -}; - -static struct tda18271_thermo_map tda18271_thermometer[] = { - { .d = 0x00, .r0 = 60, .r1 = 92 }, - { .d = 0x01, .r0 = 62, .r1 = 94 }, - { .d = 0x02, .r0 = 66, .r1 = 98 }, - { .d = 0x03, .r0 = 64, .r1 = 96 }, - { .d = 0x04, .r0 = 74, .r1 = 106 }, - { .d = 0x05, .r0 = 72, .r1 = 104 }, - { .d = 0x06, .r0 = 68, .r1 = 100 }, - { .d = 0x07, .r0 = 70, .r1 = 102 }, - { .d = 0x08, .r0 = 90, .r1 = 122 }, - { .d = 0x09, .r0 = 88, .r1 = 120 }, - { .d = 0x0a, .r0 = 84, .r1 = 116 }, - { .d = 0x0b, .r0 = 86, .r1 = 118 }, - { .d = 0x0c, .r0 = 76, .r1 = 108 }, - { .d = 0x0d, .r0 = 78, .r1 = 110 }, - { .d = 0x0e, .r0 = 82, .r1 = 114 }, - { .d = 0x0f, .r0 = 80, .r1 = 112 }, - { .d = 0x00, .r0 = 0, .r1 = 0 }, /* end */ -}; - -int tda18271_lookup_thermometer(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int val, i = 0; - - while (tda18271_thermometer[i].d < (regs[R_TM] & 0x0f)) { - if (tda18271_thermometer[i + 1].d == 0) - break; - i++; - } - - if ((regs[R_TM] & 0x20) == 0x20) - val = tda18271_thermometer[i].r1; - else - val = tda18271_thermometer[i].r0; - - tda_map("(%d) tm = %d\n", i, val); - - return val; -} - -/*---------------------------------------------------------------------*/ - -struct tda18271_cid_target_map { - u32 rfmax; - u8 target; - u16 limit; -}; - -static struct tda18271_cid_target_map tda18271_cid_target[] = { - { .rfmax = 46000, .target = 0x04, .limit = 1800 }, - { .rfmax = 52200, .target = 0x0a, .limit = 1500 }, - { .rfmax = 70100, .target = 0x01, .limit = 4000 }, - { .rfmax = 136800, .target = 0x18, .limit = 4000 }, - { .rfmax = 156700, .target = 0x18, .limit = 4000 }, - { .rfmax = 186250, .target = 0x0a, .limit = 4000 }, - { .rfmax = 230000, .target = 0x0a, .limit = 4000 }, - { .rfmax = 345000, .target = 0x18, .limit = 4000 }, - { .rfmax = 426000, .target = 0x0e, .limit = 4000 }, - { .rfmax = 489500, .target = 0x1e, .limit = 4000 }, - { .rfmax = 697500, .target = 0x32, .limit = 4000 }, - { .rfmax = 842000, .target = 0x3a, .limit = 4000 }, - { .rfmax = 0, .target = 0x00, .limit = 0 }, /* end */ -}; - -int tda18271_lookup_cid_target(struct dvb_frontend *fe, - u32 *freq, u8 *cid_target, u16 *count_limit) -{ - struct tda18271_priv *priv = fe->tuner_priv; - int i = 0; - - while ((tda18271_cid_target[i].rfmax * 1000) < *freq) { - if (tda18271_cid_target[i + 1].rfmax == 0) - break; - i++; - } - *cid_target = tda18271_cid_target[i].target; - *count_limit = tda18271_cid_target[i].limit; - - tda_map("(%d) cid_target = %02x, count_limit = %d\n", i, - tda18271_cid_target[i].target, tda18271_cid_target[i].limit); - - return 0; -} - -/*---------------------------------------------------------------------*/ - -static struct tda18271_rf_tracking_filter_cal tda18271_rf_band_template[] = { - { .rfmax = 47900, .rfband = 0x00, - .rf1_def = 46000, .rf2_def = 0, .rf3_def = 0 }, - { .rfmax = 61100, .rfband = 0x01, - .rf1_def = 52200, .rf2_def = 0, .rf3_def = 0 }, - { .rfmax = 152600, .rfband = 0x02, - .rf1_def = 70100, .rf2_def = 136800, .rf3_def = 0 }, - { .rfmax = 164700, .rfband = 0x03, - .rf1_def = 156700, .rf2_def = 0, .rf3_def = 0 }, - { .rfmax = 203500, .rfband = 0x04, - .rf1_def = 186250, .rf2_def = 0, .rf3_def = 0 }, - { .rfmax = 457800, .rfband = 0x05, - .rf1_def = 230000, .rf2_def = 345000, .rf3_def = 426000 }, - { .rfmax = 865000, .rfband = 0x06, - .rf1_def = 489500, .rf2_def = 697500, .rf3_def = 842000 }, - { .rfmax = 0, .rfband = 0x00, - .rf1_def = 0, .rf2_def = 0, .rf3_def = 0 }, /* end */ -}; - -int tda18271_lookup_rf_band(struct dvb_frontend *fe, u32 *freq, u8 *rf_band) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; - int i = 0; - - while ((map[i].rfmax * 1000) < *freq) { - if (tda18271_debug & DBG_ADV) - tda_map("(%d) rfmax = %d < freq = %d, " - "rf1_def = %d, rf2_def = %d, rf3_def = %d, " - "rf1 = %d, rf2 = %d, rf3 = %d, " - "rf_a1 = %d, rf_a2 = %d, " - "rf_b1 = %d, rf_b2 = %d\n", - i, map[i].rfmax * 1000, *freq, - map[i].rf1_def, map[i].rf2_def, map[i].rf3_def, - map[i].rf1, map[i].rf2, map[i].rf3, - map[i].rf_a1, map[i].rf_a2, - map[i].rf_b1, map[i].rf_b2); - if (map[i].rfmax == 0) - return -EINVAL; - i++; - } - if (rf_band) - *rf_band = map[i].rfband; - - tda_map("(%d) rf_band = %02x\n", i, map[i].rfband); - - return i; -} - -/*---------------------------------------------------------------------*/ - -struct tda18271_map_layout { - struct tda18271_pll_map *main_pll; - struct tda18271_pll_map *cal_pll; - - struct tda18271_map *rf_cal; - struct tda18271_map *rf_cal_kmco; - struct tda18271_map *rf_cal_dc_over_dt; - - struct tda18271_map *bp_filter; - struct tda18271_map *rf_band; - struct tda18271_map *gain_taper; - struct tda18271_map *ir_measure; -}; - -/*---------------------------------------------------------------------*/ - -int tda18271_lookup_pll_map(struct dvb_frontend *fe, - enum tda18271_map_type map_type, - u32 *freq, u8 *post_div, u8 *div) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_pll_map *map = NULL; - unsigned int i = 0; - char *map_name; - int ret = 0; - - BUG_ON(!priv->maps); - - switch (map_type) { - case MAIN_PLL: - map = priv->maps->main_pll; - map_name = "main_pll"; - break; - case CAL_PLL: - map = priv->maps->cal_pll; - map_name = "cal_pll"; - break; - default: - /* we should never get here */ - map_name = "undefined"; - break; - } - - if (!map) { - tda_warn("%s map is not set!\n", map_name); - ret = -EINVAL; - goto fail; - } - - while ((map[i].lomax * 1000) < *freq) { - if (map[i + 1].lomax == 0) { - tda_map("%s: frequency (%d) out of range\n", - map_name, *freq); - ret = -ERANGE; - break; - } - i++; - } - *post_div = map[i].pd; - *div = map[i].d; - - tda_map("(%d) %s: post div = 0x%02x, div = 0x%02x\n", - i, map_name, *post_div, *div); -fail: - return ret; -} - -int tda18271_lookup_map(struct dvb_frontend *fe, - enum tda18271_map_type map_type, - u32 *freq, u8 *val) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_map *map = NULL; - unsigned int i = 0; - char *map_name; - int ret = 0; - - BUG_ON(!priv->maps); - - switch (map_type) { - case BP_FILTER: - map = priv->maps->bp_filter; - map_name = "bp_filter"; - break; - case RF_CAL_KMCO: - map = priv->maps->rf_cal_kmco; - map_name = "km"; - break; - case RF_BAND: - map = priv->maps->rf_band; - map_name = "rf_band"; - break; - case GAIN_TAPER: - map = priv->maps->gain_taper; - map_name = "gain_taper"; - break; - case RF_CAL: - map = priv->maps->rf_cal; - map_name = "rf_cal"; - break; - case IR_MEASURE: - map = priv->maps->ir_measure; - map_name = "ir_measure"; - break; - case RF_CAL_DC_OVER_DT: - map = priv->maps->rf_cal_dc_over_dt; - map_name = "rf_cal_dc_over_dt"; - break; - default: - /* we should never get here */ - map_name = "undefined"; - break; - } - - if (!map) { - tda_warn("%s map is not set!\n", map_name); - ret = -EINVAL; - goto fail; - } - - while ((map[i].rfmax * 1000) < *freq) { - if (map[i + 1].rfmax == 0) { - tda_map("%s: frequency (%d) out of range\n", - map_name, *freq); - ret = -ERANGE; - break; - } - i++; - } - *val = map[i].val; - - tda_map("(%d) %s: 0x%02x\n", i, map_name, *val); -fail: - return ret; -} - -/*---------------------------------------------------------------------*/ - -static struct tda18271_std_map tda18271c1_std_map = { - .fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */ - .atv_b = { .if_freq = 6750, .fm_rfn = 0, .agc_mode = 1, .std = 6, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ - .atv_dk = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ - .atv_gh = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ - .atv_i = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ - .atv_l = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ - .atv_lc = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 7, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ - .atv_mn = { .if_freq = 5750, .fm_rfn = 0, .agc_mode = 1, .std = 5, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */ - .atsc_6 = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ - .dvbt_6 = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ - .dvbt_7 = { .if_freq = 3800, .fm_rfn = 0, .agc_mode = 3, .std = 5, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ - .dvbt_8 = { .if_freq = 4300, .fm_rfn = 0, .agc_mode = 3, .std = 6, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ - .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ - .qam_7 = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ - .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */ -}; - -static struct tda18271_std_map tda18271c2_std_map = { - .fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */ - .atv_b = { .if_freq = 6000, .fm_rfn = 0, .agc_mode = 1, .std = 5, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */ - .atv_dk = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ - .atv_gh = { .if_freq = 7100, .fm_rfn = 0, .agc_mode = 1, .std = 6, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ - .atv_i = { .if_freq = 7250, .fm_rfn = 0, .agc_mode = 1, .std = 6, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ - .atv_l = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ - .atv_lc = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 6, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ - .atv_mn = { .if_freq = 5400, .fm_rfn = 0, .agc_mode = 1, .std = 4, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0c */ - .atsc_6 = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ - .dvbt_6 = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ - .dvbt_7 = { .if_freq = 3500, .fm_rfn = 0, .agc_mode = 3, .std = 4, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ - .dvbt_8 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ - .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ - .qam_7 = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ - .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */ -}; - -/*---------------------------------------------------------------------*/ - -static struct tda18271_map_layout tda18271c1_map_layout = { - .main_pll = tda18271c1_main_pll, - .cal_pll = tda18271c1_cal_pll, - - .rf_cal = tda18271c1_rf_cal, - .rf_cal_kmco = tda18271c1_km, - - .bp_filter = tda18271_bp_filter, - .rf_band = tda18271_rf_band, - .gain_taper = tda18271_gain_taper, - .ir_measure = tda18271_ir_measure, -}; - -static struct tda18271_map_layout tda18271c2_map_layout = { - .main_pll = tda18271c2_main_pll, - .cal_pll = tda18271c2_cal_pll, - - .rf_cal = tda18271c2_rf_cal, - .rf_cal_kmco = tda18271c2_km, - - .rf_cal_dc_over_dt = tda18271_rf_cal_dc_over_dt, - - .bp_filter = tda18271_bp_filter, - .rf_band = tda18271_rf_band, - .gain_taper = tda18271_gain_taper, - .ir_measure = tda18271_ir_measure, -}; - -int tda18271_assign_map_layout(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - int ret = 0; - - switch (priv->id) { - case TDA18271HDC1: - priv->maps = &tda18271c1_map_layout; - memcpy(&priv->std, &tda18271c1_std_map, - sizeof(struct tda18271_std_map)); - break; - case TDA18271HDC2: - priv->maps = &tda18271c2_map_layout; - memcpy(&priv->std, &tda18271c2_std_map, - sizeof(struct tda18271_std_map)); - break; - default: - ret = -EINVAL; - break; - } - memcpy(priv->rf_cal_state, &tda18271_rf_band_template, - sizeof(tda18271_rf_band_template)); - - return ret; -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/common/tuners/tda18271-priv.h b/drivers/media/common/tuners/tda18271-priv.h deleted file mode 100644 index 454c152ccaa0..000000000000 --- a/drivers/media/common/tuners/tda18271-priv.h +++ /dev/null @@ -1,236 +0,0 @@ -/* - tda18271-priv.h - private header for the NXP TDA18271 silicon tuner - - Copyright (C) 2007, 2008 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 __TDA18271_PRIV_H__ -#define __TDA18271_PRIV_H__ - -#include -#include -#include -#include "tuner-i2c.h" -#include "tda18271.h" - -#define R_ID 0x00 /* ID byte */ -#define R_TM 0x01 /* Thermo byte */ -#define R_PL 0x02 /* Power level byte */ -#define R_EP1 0x03 /* Easy Prog byte 1 */ -#define R_EP2 0x04 /* Easy Prog byte 2 */ -#define R_EP3 0x05 /* Easy Prog byte 3 */ -#define R_EP4 0x06 /* Easy Prog byte 4 */ -#define R_EP5 0x07 /* Easy Prog byte 5 */ -#define R_CPD 0x08 /* Cal Post-Divider byte */ -#define R_CD1 0x09 /* Cal Divider byte 1 */ -#define R_CD2 0x0a /* Cal Divider byte 2 */ -#define R_CD3 0x0b /* Cal Divider byte 3 */ -#define R_MPD 0x0c /* Main Post-Divider byte */ -#define R_MD1 0x0d /* Main Divider byte 1 */ -#define R_MD2 0x0e /* Main Divider byte 2 */ -#define R_MD3 0x0f /* Main Divider byte 3 */ -#define R_EB1 0x10 /* Extended byte 1 */ -#define R_EB2 0x11 /* Extended byte 2 */ -#define R_EB3 0x12 /* Extended byte 3 */ -#define R_EB4 0x13 /* Extended byte 4 */ -#define R_EB5 0x14 /* Extended byte 5 */ -#define R_EB6 0x15 /* Extended byte 6 */ -#define R_EB7 0x16 /* Extended byte 7 */ -#define R_EB8 0x17 /* Extended byte 8 */ -#define R_EB9 0x18 /* Extended byte 9 */ -#define R_EB10 0x19 /* Extended byte 10 */ -#define R_EB11 0x1a /* Extended byte 11 */ -#define R_EB12 0x1b /* Extended byte 12 */ -#define R_EB13 0x1c /* Extended byte 13 */ -#define R_EB14 0x1d /* Extended byte 14 */ -#define R_EB15 0x1e /* Extended byte 15 */ -#define R_EB16 0x1f /* Extended byte 16 */ -#define R_EB17 0x20 /* Extended byte 17 */ -#define R_EB18 0x21 /* Extended byte 18 */ -#define R_EB19 0x22 /* Extended byte 19 */ -#define R_EB20 0x23 /* Extended byte 20 */ -#define R_EB21 0x24 /* Extended byte 21 */ -#define R_EB22 0x25 /* Extended byte 22 */ -#define R_EB23 0x26 /* Extended byte 23 */ - -#define TDA18271_NUM_REGS 39 - -/*---------------------------------------------------------------------*/ - -struct tda18271_rf_tracking_filter_cal { - u32 rfmax; - u8 rfband; - u32 rf1_def; - u32 rf2_def; - u32 rf3_def; - u32 rf1; - u32 rf2; - u32 rf3; - s32 rf_a1; - s32 rf_b1; - s32 rf_a2; - s32 rf_b2; -}; - -enum tda18271_pll { - TDA18271_MAIN_PLL, - TDA18271_CAL_PLL, -}; - -struct tda18271_map_layout; - -enum tda18271_ver { - TDA18271HDC1, - TDA18271HDC2, -}; - -struct tda18271_priv { - unsigned char tda18271_regs[TDA18271_NUM_REGS]; - - struct list_head hybrid_tuner_instance_list; - struct tuner_i2c_props i2c_props; - - enum tda18271_mode mode; - enum tda18271_role role; - enum tda18271_i2c_gate gate; - enum tda18271_ver id; - enum tda18271_output_options output_opt; - enum tda18271_small_i2c small_i2c; - - unsigned int config; /* interface to saa713x / tda829x */ - unsigned int cal_initialized:1; - - u8 tm_rfcal; - - struct tda18271_map_layout *maps; - struct tda18271_std_map std; - struct tda18271_rf_tracking_filter_cal rf_cal_state[8]; - - struct mutex lock; - - u16 if_freq; - - u32 frequency; - u32 bandwidth; -}; - -/*---------------------------------------------------------------------*/ - -extern int tda18271_debug; - -#define DBG_INFO 1 -#define DBG_MAP 2 -#define DBG_REG 4 -#define DBG_ADV 8 -#define DBG_CAL 16 - -__attribute__((format(printf, 4, 5))) -int _tda_printk(struct tda18271_priv *state, const char *level, - const char *func, const char *fmt, ...); - -#define tda_printk(st, lvl, fmt, arg...) \ - _tda_printk(st, lvl, __func__, fmt, ##arg) - -#define tda_dprintk(st, lvl, fmt, arg...) \ -do { \ - if (tda18271_debug & lvl) \ - tda_printk(st, KERN_DEBUG, fmt, ##arg); \ -} while (0) - -#define tda_info(fmt, arg...) pr_info(fmt, ##arg) -#define tda_warn(fmt, arg...) tda_printk(priv, KERN_WARNING, fmt, ##arg) -#define tda_err(fmt, arg...) tda_printk(priv, KERN_ERR, fmt, ##arg) -#define tda_dbg(fmt, arg...) tda_dprintk(priv, DBG_INFO, fmt, ##arg) -#define tda_map(fmt, arg...) tda_dprintk(priv, DBG_MAP, fmt, ##arg) -#define tda_reg(fmt, arg...) tda_dprintk(priv, DBG_REG, fmt, ##arg) -#define tda_cal(fmt, arg...) tda_dprintk(priv, DBG_CAL, fmt, ##arg) - -#define tda_fail(ret) \ -({ \ - int __ret; \ - __ret = (ret < 0); \ - if (__ret) \ - tda_printk(priv, KERN_ERR, \ - "error %d on line %d\n", ret, __LINE__); \ - __ret; \ -}) - -/*---------------------------------------------------------------------*/ - -enum tda18271_map_type { - /* tda18271_pll_map */ - MAIN_PLL, - CAL_PLL, - /* tda18271_map */ - RF_CAL, - RF_CAL_KMCO, - RF_CAL_DC_OVER_DT, - BP_FILTER, - RF_BAND, - GAIN_TAPER, - IR_MEASURE, -}; - -extern int tda18271_lookup_pll_map(struct dvb_frontend *fe, - enum tda18271_map_type map_type, - u32 *freq, u8 *post_div, u8 *div); -extern int tda18271_lookup_map(struct dvb_frontend *fe, - enum tda18271_map_type map_type, - u32 *freq, u8 *val); - -extern int tda18271_lookup_thermometer(struct dvb_frontend *fe); - -extern int tda18271_lookup_rf_band(struct dvb_frontend *fe, - u32 *freq, u8 *rf_band); - -extern int tda18271_lookup_cid_target(struct dvb_frontend *fe, - u32 *freq, u8 *cid_target, - u16 *count_limit); - -extern int tda18271_assign_map_layout(struct dvb_frontend *fe); - -/*---------------------------------------------------------------------*/ - -extern int tda18271_read_regs(struct dvb_frontend *fe); -extern int tda18271_read_extended(struct dvb_frontend *fe); -extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len); -extern int tda18271_init_regs(struct dvb_frontend *fe); - -extern int tda18271_charge_pump_source(struct dvb_frontend *fe, - enum tda18271_pll pll, int force); -extern int tda18271_set_standby_mode(struct dvb_frontend *fe, - int sm, int sm_lt, int sm_xt); - -extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq); -extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq); - -extern int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq); -extern int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq); -extern int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq); -extern int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq); -extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq); -extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq); - -#endif /* __TDA18271_PRIV_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/common/tuners/tda18271.h b/drivers/media/common/tuners/tda18271.h deleted file mode 100644 index 640bae4e6a5a..000000000000 --- a/drivers/media/common/tuners/tda18271.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - tda18271.h - header for the Philips / NXP TDA18271 silicon tuner - - Copyright (C) 2007, 2008 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 __TDA18271_H__ -#define __TDA18271_H__ - -#include -#include "dvb_frontend.h" - -struct tda18271_std_map_item { - u16 if_freq; - - /* EP3[4:3] */ - unsigned int agc_mode:2; - /* EP3[2:0] */ - unsigned int std:3; - /* EP4[7] */ - unsigned int fm_rfn:1; - /* EP4[4:2] */ - unsigned int if_lvl:3; - /* EB22[6:0] */ - unsigned int rfagc_top:7; -}; - -struct tda18271_std_map { - struct tda18271_std_map_item fm_radio; - struct tda18271_std_map_item atv_b; - struct tda18271_std_map_item atv_dk; - struct tda18271_std_map_item atv_gh; - struct tda18271_std_map_item atv_i; - struct tda18271_std_map_item atv_l; - struct tda18271_std_map_item atv_lc; - struct tda18271_std_map_item atv_mn; - struct tda18271_std_map_item atsc_6; - struct tda18271_std_map_item dvbt_6; - struct tda18271_std_map_item dvbt_7; - struct tda18271_std_map_item dvbt_8; - struct tda18271_std_map_item qam_6; - struct tda18271_std_map_item qam_7; - struct tda18271_std_map_item qam_8; -}; - -enum tda18271_role { - TDA18271_MASTER = 0, - TDA18271_SLAVE, -}; - -enum tda18271_i2c_gate { - TDA18271_GATE_AUTO = 0, - TDA18271_GATE_ANALOG, - TDA18271_GATE_DIGITAL, -}; - -enum tda18271_output_options { - /* slave tuner output & loop thru & xtal oscillator always on */ - TDA18271_OUTPUT_LT_XT_ON = 0, - - /* slave tuner output loop thru off */ - TDA18271_OUTPUT_LT_OFF = 1, - - /* xtal oscillator off */ - TDA18271_OUTPUT_XT_OFF = 2, -}; - -enum tda18271_small_i2c { - TDA18271_39_BYTE_CHUNK_INIT = 0, - TDA18271_16_BYTE_CHUNK_INIT = 16, - TDA18271_08_BYTE_CHUNK_INIT = 8, - TDA18271_03_BYTE_CHUNK_INIT = 3, -}; - -struct tda18271_config { - /* override default if freq / std settings (optional) */ - struct tda18271_std_map *std_map; - - /* master / slave tuner: master uses main pll, slave uses cal pll */ - enum tda18271_role role; - - /* use i2c gate provided by analog or digital demod */ - enum tda18271_i2c_gate gate; - - /* output options that can be disabled */ - enum tda18271_output_options output_opt; - - /* some i2c providers can't write all 39 registers at once */ - enum tda18271_small_i2c small_i2c; - - /* force rf tracking filter calibration on startup */ - unsigned int rf_cal_on_startup:1; - - /* interface to saa713x / tda829x */ - unsigned int config; -}; - -#define TDA18271_CALLBACK_CMD_AGC_ENABLE 0 - -enum tda18271_mode { - TDA18271_ANALOG = 0, - TDA18271_DIGITAL, -}; - -#if defined(CONFIG_MEDIA_TUNER_TDA18271) || (defined(CONFIG_MEDIA_TUNER_TDA18271_MODULE) && defined(MODULE)) -extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, - struct i2c_adapter *i2c, - struct tda18271_config *cfg); -#else -static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, - u8 addr, - struct i2c_adapter *i2c, - struct tda18271_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* __TDA18271_H__ */ diff --git a/drivers/media/common/tuners/tda827x.c b/drivers/media/common/tuners/tda827x.c deleted file mode 100644 index a0d176267470..000000000000 --- a/drivers/media/common/tuners/tda827x.c +++ /dev/null @@ -1,917 +0,0 @@ -/* - * - * (c) 2005 Hartmut Hackmann - * (c) 2007 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 -#include -#include -#include -#include - -#include "tda827x.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "tda827x: " args); \ - } while (0) - -struct tda827x_priv { - int i2c_addr; - struct i2c_adapter *i2c_adap; - struct tda827x_config *cfg; - - unsigned int sgIF; - unsigned char lpsel; - - u32 frequency; - u32 bandwidth; -}; - -static void tda827x_set_std(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tda827x_priv *priv = fe->tuner_priv; - char *mode; - - priv->lpsel = 0; - if (params->std & V4L2_STD_MN) { - priv->sgIF = 92; - priv->lpsel = 1; - mode = "MN"; - } else if (params->std & V4L2_STD_B) { - priv->sgIF = 108; - mode = "B"; - } else if (params->std & V4L2_STD_GH) { - priv->sgIF = 124; - mode = "GH"; - } else if (params->std & V4L2_STD_PAL_I) { - priv->sgIF = 124; - mode = "I"; - } else if (params->std & V4L2_STD_DK) { - priv->sgIF = 124; - mode = "DK"; - } else if (params->std & V4L2_STD_SECAM_L) { - priv->sgIF = 124; - mode = "L"; - } else if (params->std & V4L2_STD_SECAM_LC) { - priv->sgIF = 20; - mode = "LC"; - } else { - priv->sgIF = 124; - mode = "xx"; - } - - if (params->mode == V4L2_TUNER_RADIO) { - priv->sgIF = 88; /* if frequency is 5.5 MHz */ - dprintk("setting tda827x to radio FM\n"); - } else - dprintk("setting tda827x to system %s\n", mode); -} - - -/* ------------------------------------------------------------------ */ - -struct tda827x_data { - u32 lomax; - u8 spd; - u8 bs; - u8 bp; - u8 cp; - u8 gc3; - u8 div1p5; -}; - -static const struct tda827x_data tda827x_table[] = { - { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, - { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, - { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, - { .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, - { .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, - { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, - { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, - { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, - { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, - { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, - { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} -}; - -static int tuner_transfer(struct dvb_frontend *fe, - struct i2c_msg *msg, - const int size) -{ - int rc; - struct tda827x_priv *priv = fe->tuner_priv; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - rc = i2c_transfer(priv->i2c_adap, msg, size); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - if (rc >= 0 && rc != size) - return -EIO; - - return rc; -} - -static int tda827xo_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct tda827x_priv *priv = fe->tuner_priv; - u8 buf[14]; - int rc; - - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = buf, .len = sizeof(buf) }; - int i, tuner_freq, if_freq; - u32 N; - - dprintk("%s:\n", __func__); - if (c->bandwidth_hz == 0) { - if_freq = 5000000; - } else if (c->bandwidth_hz <= 6000000) { - if_freq = 4000000; - } else if (c->bandwidth_hz <= 7000000) { - if_freq = 4500000; - } else { /* 8 MHz */ - if_freq = 5000000; - } - tuner_freq = c->frequency; - - i = 0; - while (tda827x_table[i].lomax < tuner_freq) { - if (tda827x_table[i + 1].lomax == 0) - break; - i++; - } - - tuner_freq += if_freq; - - N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2); - buf[0] = 0; - buf[1] = (N>>8) | 0x40; - buf[2] = N & 0xff; - buf[3] = 0; - buf[4] = 0x52; - buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) + - (tda827x_table[i].bs << 3) + - tda827x_table[i].bp; - buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f; - buf[7] = 0xbf; - buf[8] = 0x2a; - buf[9] = 0x05; - buf[10] = 0xff; - buf[11] = 0x00; - buf[12] = 0x00; - buf[13] = 0x40; - - msg.len = 14; - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - msleep(500); - /* correct CP value */ - buf[0] = 0x30; - buf[1] = 0x50 + tda827x_table[i].cp; - msg.len = 2; - - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - priv->frequency = c->frequency; - priv->bandwidth = c->bandwidth_hz; - - return 0; - -err: - printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n", - __func__, priv->i2c_addr << 1); - return rc; -} - -static int tda827xo_sleep(struct dvb_frontend *fe) -{ - struct tda827x_priv *priv = fe->tuner_priv; - static u8 buf[] = { 0x30, 0xd0 }; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = buf, .len = sizeof(buf) }; - - dprintk("%s:\n", __func__); - tuner_transfer(fe, &msg, 1); - - if (priv->cfg && priv->cfg->sleep) - priv->cfg->sleep(fe); - - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int tda827xo_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - unsigned char tuner_reg[8]; - unsigned char reg2[2]; - u32 N; - int i; - struct tda827x_priv *priv = fe->tuner_priv; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 }; - unsigned int freq = params->frequency; - - tda827x_set_std(fe, params); - - if (params->mode == V4L2_TUNER_RADIO) - freq = freq / 1000; - - N = freq + priv->sgIF; - - i = 0; - while (tda827x_table[i].lomax < N * 62500) { - if (tda827x_table[i + 1].lomax == 0) - break; - i++; - } - - N = N << tda827x_table[i].spd; - - tuner_reg[0] = 0; - tuner_reg[1] = (unsigned char)(N>>8); - tuner_reg[2] = (unsigned char) N; - tuner_reg[3] = 0x40; - tuner_reg[4] = 0x52 + (priv->lpsel << 5); - tuner_reg[5] = (tda827x_table[i].spd << 6) + - (tda827x_table[i].div1p5 << 5) + - (tda827x_table[i].bs << 3) + tda827x_table[i].bp; - tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4); - tuner_reg[7] = 0x8f; - - msg.buf = tuner_reg; - msg.len = 8; - tuner_transfer(fe, &msg, 1); - - msg.buf = reg2; - msg.len = 2; - reg2[0] = 0x80; - reg2[1] = 0; - tuner_transfer(fe, &msg, 1); - - reg2[0] = 0x60; - reg2[1] = 0xbf; - tuner_transfer(fe, &msg, 1); - - reg2[0] = 0x30; - reg2[1] = tuner_reg[4] + 0x80; - tuner_transfer(fe, &msg, 1); - - msleep(1); - reg2[0] = 0x30; - reg2[1] = tuner_reg[4] + 4; - tuner_transfer(fe, &msg, 1); - - msleep(1); - reg2[0] = 0x30; - reg2[1] = tuner_reg[4]; - tuner_transfer(fe, &msg, 1); - - msleep(550); - reg2[0] = 0x30; - reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp; - tuner_transfer(fe, &msg, 1); - - reg2[0] = 0x60; - reg2[1] = 0x3f; - tuner_transfer(fe, &msg, 1); - - reg2[0] = 0x80; - reg2[1] = 0x08; /* Vsync en */ - tuner_transfer(fe, &msg, 1); - - priv->frequency = params->frequency; - - return 0; -} - -static void tda827xo_agcf(struct dvb_frontend *fe) -{ - struct tda827x_priv *priv = fe->tuner_priv; - unsigned char data[] = { 0x80, 0x0c }; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = data, .len = 2}; - - tuner_transfer(fe, &msg, 1); -} - -/* ------------------------------------------------------------------ */ - -struct tda827xa_data { - u32 lomax; - u8 svco; - u8 spd; - u8 scr; - u8 sbs; - u8 gc3; -}; - -static struct tda827xa_data tda827xa_dvbt[] = { - { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1}, - { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, - { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, - { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, - { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, - { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, - { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} -}; - -static struct tda827xa_data tda827xa_dvbc[] = { - { .lomax = 50125000, .svco = 2, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3}, - { .lomax = 58500000, .svco = 3, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3}, - { .lomax = 69250000, .svco = 0, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, - { .lomax = 83625000, .svco = 1, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, - { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, - { .lomax = 100250000, .svco = 2, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1}, - { .lomax = 117000000, .svco = 3, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1}, - { .lomax = 138500000, .svco = 0, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, - { .lomax = 167250000, .svco = 1, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, - { .lomax = 187000000, .svco = 2, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, - { .lomax = 200500000, .svco = 2, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 1}, - { .lomax = 234000000, .svco = 3, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 3}, - { .lomax = 277000000, .svco = 0, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 3}, - { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 1}, - { .lomax = 334500000, .svco = 1, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3}, - { .lomax = 401000000, .svco = 2, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3}, - { .lomax = 468000000, .svco = 3, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 1}, - { .lomax = 535000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, - { .lomax = 554000000, .svco = 0, .spd = 0, .scr = 2, .sbs = 3, .gc3 = 1}, - { .lomax = 638000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, - { .lomax = 669000000, .svco = 1, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, - { .lomax = 720000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, - { .lomax = 802000000, .svco = 2, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, - { .lomax = 835000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, - { .lomax = 885000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, - { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, - { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} -}; - -static struct tda827xa_data tda827xa_analog[] = { - { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3}, - { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, - { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, - { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, - { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3}, - { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3}, - { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, - { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, - { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, - { .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, - { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} -}; - -static int tda827xa_sleep(struct dvb_frontend *fe) -{ - struct tda827x_priv *priv = fe->tuner_priv; - static u8 buf[] = { 0x30, 0x90 }; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = buf, .len = sizeof(buf) }; - - dprintk("%s:\n", __func__); - - tuner_transfer(fe, &msg, 1); - - if (priv->cfg && priv->cfg->sleep) - priv->cfg->sleep(fe); - - return 0; -} - -static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, - struct analog_parameters *params) -{ - struct tda827x_priv *priv = fe->tuner_priv; - unsigned char buf[] = {0x22, 0x01}; - int arg; - int gp_func; - struct i2c_msg msg = { .flags = 0, .buf = buf, .len = sizeof(buf) }; - - if (NULL == priv->cfg) { - dprintk("tda827x_config not defined, cannot set LNA gain!\n"); - return; - } - msg.addr = priv->cfg->switch_addr; - if (priv->cfg->config) { - if (high) - dprintk("setting LNA to high gain\n"); - else - dprintk("setting LNA to low gain\n"); - } - switch (priv->cfg->config) { - case 0: /* no LNA */ - break; - case 1: /* switch is GPIO 0 of tda8290 */ - case 2: - if (params == NULL) { - gp_func = 0; - arg = 0; - } else { - /* turn Vsync on */ - gp_func = 1; - if (params->std & V4L2_STD_MN) - arg = 1; - else - arg = 0; - } - if (fe->callback) - fe->callback(priv->i2c_adap->algo_data, - DVB_FRONTEND_COMPONENT_TUNER, - gp_func, arg); - buf[1] = high ? 0 : 1; - if (priv->cfg->config == 2) - buf[1] = high ? 1 : 0; - tuner_transfer(fe, &msg, 1); - break; - case 3: /* switch with GPIO of saa713x */ - if (fe->callback) - fe->callback(priv->i2c_adap->algo_data, - DVB_FRONTEND_COMPONENT_TUNER, 0, high); - break; - } -} - -static int tda827xa_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct tda827x_priv *priv = fe->tuner_priv; - struct tda827xa_data *frequency_map = tda827xa_dvbt; - u8 buf[11]; - - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = buf, .len = sizeof(buf) }; - - int i, tuner_freq, if_freq, rc; - u32 N; - - dprintk("%s:\n", __func__); - - tda827xa_lna_gain(fe, 1, NULL); - msleep(20); - - if (c->bandwidth_hz == 0) { - if_freq = 5000000; - } else if (c->bandwidth_hz <= 6000000) { - if_freq = 4000000; - } else if (c->bandwidth_hz <= 7000000) { - if_freq = 4500000; - } else { /* 8 MHz */ - if_freq = 5000000; - } - tuner_freq = c->frequency; - - switch (c->delivery_system) { - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - dprintk("%s select tda827xa_dvbc\n", __func__); - frequency_map = tda827xa_dvbc; - break; - default: - break; - } - - i = 0; - while (frequency_map[i].lomax < tuner_freq) { - if (frequency_map[i + 1].lomax == 0) - break; - i++; - } - - tuner_freq += if_freq; - - N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd; - buf[0] = 0; // subaddress - buf[1] = N >> 8; - buf[2] = N & 0xff; - buf[3] = 0; - buf[4] = 0x16; - buf[5] = (frequency_map[i].spd << 5) + (frequency_map[i].svco << 3) + - frequency_map[i].sbs; - buf[6] = 0x4b + (frequency_map[i].gc3 << 4); - buf[7] = 0x1c; - buf[8] = 0x06; - buf[9] = 0x24; - buf[10] = 0x00; - msg.len = 11; - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - buf[0] = 0x90; - buf[1] = 0xff; - buf[2] = 0x60; - buf[3] = 0x00; - buf[4] = 0x59; // lpsel, for 6MHz + 2 - msg.len = 5; - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - buf[0] = 0xa0; - buf[1] = 0x40; - msg.len = 2; - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - msleep(11); - msg.flags = I2C_M_RD; - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - msg.flags = 0; - - buf[1] >>= 4; - dprintk("tda8275a AGC2 gain is: %d\n", buf[1]); - if ((buf[1]) < 2) { - tda827xa_lna_gain(fe, 0, NULL); - buf[0] = 0x60; - buf[1] = 0x0c; - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - } - - buf[0] = 0xc0; - buf[1] = 0x99; // lpsel, for 6MHz + 2 - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - buf[0] = 0x60; - buf[1] = 0x3c; - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - /* correct CP value */ - buf[0] = 0x30; - buf[1] = 0x10 + frequency_map[i].scr; - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - msleep(163); - buf[0] = 0xc0; - buf[1] = 0x39; // lpsel, for 6MHz + 2 - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - msleep(3); - /* freeze AGC1 */ - buf[0] = 0x50; - buf[1] = 0x4f + (frequency_map[i].gc3 << 4); - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - priv->frequency = c->frequency; - priv->bandwidth = c->bandwidth_hz; - - return 0; - -err: - printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n", - __func__, priv->i2c_addr << 1); - return rc; -} - - -static int tda827xa_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - unsigned char tuner_reg[11]; - u32 N; - int i; - struct tda827x_priv *priv = fe->tuner_priv; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = tuner_reg, .len = sizeof(tuner_reg) }; - unsigned int freq = params->frequency; - - tda827x_set_std(fe, params); - - tda827xa_lna_gain(fe, 1, params); - msleep(10); - - if (params->mode == V4L2_TUNER_RADIO) - freq = freq / 1000; - - N = freq + priv->sgIF; - - i = 0; - while (tda827xa_analog[i].lomax < N * 62500) { - if (tda827xa_analog[i + 1].lomax == 0) - break; - i++; - } - - N = N << tda827xa_analog[i].spd; - - tuner_reg[0] = 0; - tuner_reg[1] = (unsigned char)(N>>8); - tuner_reg[2] = (unsigned char) N; - tuner_reg[3] = 0; - tuner_reg[4] = 0x16; - tuner_reg[5] = (tda827xa_analog[i].spd << 5) + - (tda827xa_analog[i].svco << 3) + - tda827xa_analog[i].sbs; - tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); - tuner_reg[7] = 0x1c; - tuner_reg[8] = 4; - tuner_reg[9] = 0x20; - tuner_reg[10] = 0x00; - msg.len = 11; - tuner_transfer(fe, &msg, 1); - - tuner_reg[0] = 0x90; - tuner_reg[1] = 0xff; - tuner_reg[2] = 0xe0; - tuner_reg[3] = 0; - tuner_reg[4] = 0x99 + (priv->lpsel << 1); - msg.len = 5; - tuner_transfer(fe, &msg, 1); - - tuner_reg[0] = 0xa0; - tuner_reg[1] = 0xc0; - msg.len = 2; - tuner_transfer(fe, &msg, 1); - - tuner_reg[0] = 0x30; - tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; - tuner_transfer(fe, &msg, 1); - - msg.flags = I2C_M_RD; - tuner_transfer(fe, &msg, 1); - msg.flags = 0; - tuner_reg[1] >>= 4; - dprintk("AGC2 gain is: %d\n", tuner_reg[1]); - if (tuner_reg[1] < 1) - tda827xa_lna_gain(fe, 0, params); - - msleep(100); - tuner_reg[0] = 0x60; - tuner_reg[1] = 0x3c; - tuner_transfer(fe, &msg, 1); - - msleep(163); - tuner_reg[0] = 0x50; - tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); - tuner_transfer(fe, &msg, 1); - - tuner_reg[0] = 0x80; - tuner_reg[1] = 0x28; - tuner_transfer(fe, &msg, 1); - - tuner_reg[0] = 0xb0; - tuner_reg[1] = 0x01; - tuner_transfer(fe, &msg, 1); - - tuner_reg[0] = 0xc0; - tuner_reg[1] = 0x19 + (priv->lpsel << 1); - tuner_transfer(fe, &msg, 1); - - priv->frequency = params->frequency; - - return 0; -} - -static void tda827xa_agcf(struct dvb_frontend *fe) -{ - struct tda827x_priv *priv = fe->tuner_priv; - unsigned char data[] = {0x80, 0x2c}; - struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0, - .buf = data, .len = 2}; - tuner_transfer(fe, &msg, 1); -} - -/* ------------------------------------------------------------------ */ - -static int tda827x_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tda827x_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct tda827x_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; - return 0; -} - -static int tda827x_init(struct dvb_frontend *fe) -{ - struct tda827x_priv *priv = fe->tuner_priv; - dprintk("%s:\n", __func__); - if (priv->cfg && priv->cfg->init) - priv->cfg->init(fe); - - return 0; -} - -static int tda827x_probe_version(struct dvb_frontend *fe); - -static int tda827x_initial_init(struct dvb_frontend *fe) -{ - int ret; - ret = tda827x_probe_version(fe); - if (ret) - return ret; - return fe->ops.tuner_ops.init(fe); -} - -static int tda827x_initial_sleep(struct dvb_frontend *fe) -{ - int ret; - ret = tda827x_probe_version(fe); - if (ret) - return ret; - return fe->ops.tuner_ops.sleep(fe); -} - -static struct dvb_tuner_ops tda827xo_tuner_ops = { - .info = { - .name = "Philips TDA827X", - .frequency_min = 55000000, - .frequency_max = 860000000, - .frequency_step = 250000 - }, - .release = tda827x_release, - .init = tda827x_initial_init, - .sleep = tda827x_initial_sleep, - .set_params = tda827xo_set_params, - .set_analog_params = tda827xo_set_analog_params, - .get_frequency = tda827x_get_frequency, - .get_bandwidth = tda827x_get_bandwidth, -}; - -static struct dvb_tuner_ops tda827xa_tuner_ops = { - .info = { - .name = "Philips TDA827XA", - .frequency_min = 44000000, - .frequency_max = 906000000, - .frequency_step = 62500 - }, - .release = tda827x_release, - .init = tda827x_init, - .sleep = tda827xa_sleep, - .set_params = tda827xa_set_params, - .set_analog_params = tda827xa_set_analog_params, - .get_frequency = tda827x_get_frequency, - .get_bandwidth = tda827x_get_bandwidth, -}; - -static int tda827x_probe_version(struct dvb_frontend *fe) -{ - u8 data; - int rc; - struct tda827x_priv *priv = fe->tuner_priv; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD, - .buf = &data, .len = 1 }; - - rc = tuner_transfer(fe, &msg, 1); - - if (rc < 0) { - printk("%s: could not read from tuner at addr: 0x%02x\n", - __func__, msg.addr << 1); - return rc; - } - if ((data & 0x3c) == 0) { - dprintk("tda827x tuner found\n"); - fe->ops.tuner_ops.init = tda827x_init; - fe->ops.tuner_ops.sleep = tda827xo_sleep; - if (priv->cfg) - priv->cfg->agcf = tda827xo_agcf; - } else { - dprintk("tda827xa tuner found\n"); - memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops)); - if (priv->cfg) - priv->cfg->agcf = tda827xa_agcf; - } - return 0; -} - -struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr, - struct i2c_adapter *i2c, - struct tda827x_config *cfg) -{ - struct tda827x_priv *priv = NULL; - - dprintk("%s:\n", __func__); - priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->i2c_addr = addr; - priv->i2c_adap = i2c; - priv->cfg = cfg; - memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = priv; - - dprintk("type set to %s\n", fe->ops.tuner_ops.info.name); - - return fe; -} -EXPORT_SYMBOL_GPL(tda827x_attach); - -MODULE_DESCRIPTION("DVB TDA827x driver"); -MODULE_AUTHOR("Hartmut Hackmann "); -MODULE_AUTHOR("Michael Krufky "); -MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/common/tuners/tda827x.h b/drivers/media/common/tuners/tda827x.h deleted file mode 100644 index 7d72ce0a0c2d..000000000000 --- a/drivers/media/common/tuners/tda827x.h +++ /dev/null @@ -1,68 +0,0 @@ - /* - DVB Driver for Philips tda827x / tda827xa Silicon tuners - - (c) 2005 Hartmut Hackmann - (c) 2007 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_TDA827X_H__ -#define __DVB_TDA827X_H__ - -#include -#include "dvb_frontend.h" - -struct tda827x_config -{ - /* saa7134 - provided callbacks */ - int (*init) (struct dvb_frontend *fe); - int (*sleep) (struct dvb_frontend *fe); - - /* interface to tda829x driver */ - unsigned int config; - int switch_addr; - - void (*agcf)(struct dvb_frontend *fe); -}; - - -/** - * Attach a tda827x tuner to the supplied frontend structure. - * - * @param fe Frontend to attach to. - * @param addr i2c address of the tuner. - * @param i2c i2c adapter to use. - * @param cfg optional callback function pointers. - * @return FE pointer on success, NULL on failure. - */ -#if defined(CONFIG_MEDIA_TUNER_TDA827X) || (defined(CONFIG_MEDIA_TUNER_TDA827X_MODULE) && defined(MODULE)) -extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr, - struct i2c_adapter *i2c, - struct tda827x_config *cfg); -#else -static inline struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, - int addr, - struct i2c_adapter *i2c, - struct tda827x_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_MEDIA_TUNER_TDA827X - -#endif // __DVB_TDA827X_H__ diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/common/tuners/tda8290.c deleted file mode 100644 index 8c4852114eeb..000000000000 --- a/drivers/media/common/tuners/tda8290.c +++ /dev/null @@ -1,874 +0,0 @@ -/* - - i2c tv tuner chip device driver - controls the philips tda8290+75 tuner chip combo. - - 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. - - This "tda8290" module was split apart from the original "tuner" module. -*/ - -#include -#include -#include -#include -#include "tuner-i2c.h" -#include "tda8290.h" -#include "tda827x.h" -#include "tda18271.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -static int deemphasis_50; -module_param(deemphasis_50, int, 0644); -MODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis"); - -/* ---------------------------------------------------------------------- */ - -struct tda8290_priv { - struct tuner_i2c_props i2c_props; - - unsigned char tda8290_easy_mode; - - unsigned char tda827x_addr; - - unsigned char ver; -#define TDA8290 1 -#define TDA8295 2 -#define TDA8275 4 -#define TDA8275A 8 -#define TDA18271 16 - - struct tda827x_config cfg; -}; - -/*---------------------------------------------------------------------*/ - -static int tda8290_i2c_bridge(struct dvb_frontend *fe, int close) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - unsigned char enable[2] = { 0x21, 0xC0 }; - unsigned char disable[2] = { 0x21, 0x00 }; - unsigned char *msg; - - if (close) { - msg = enable; - tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); - /* let the bridge stabilize */ - msleep(20); - } else { - msg = disable; - tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); - } - - return 0; -} - -static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - unsigned char enable[2] = { 0x45, 0xc1 }; - unsigned char disable[2] = { 0x46, 0x00 }; - unsigned char buf[3] = { 0x45, 0x01, 0x00 }; - unsigned char *msg; - - if (close) { - msg = enable; - tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); - /* let the bridge stabilize */ - msleep(20); - } else { - msg = disable; - tuner_i2c_xfer_send_recv(&priv->i2c_props, msg, 1, &msg[1], 1); - - buf[2] = msg[1]; - buf[2] &= ~0x04; - tuner_i2c_xfer_send(&priv->i2c_props, buf, 3); - msleep(5); - - msg[1] |= 0x04; - tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); - } - - return 0; -} - -/*---------------------------------------------------------------------*/ - -static void set_audio(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - char* mode; - - if (params->std & V4L2_STD_MN) { - priv->tda8290_easy_mode = 0x01; - mode = "MN"; - } else if (params->std & V4L2_STD_B) { - priv->tda8290_easy_mode = 0x02; - mode = "B"; - } else if (params->std & V4L2_STD_GH) { - priv->tda8290_easy_mode = 0x04; - mode = "GH"; - } else if (params->std & V4L2_STD_PAL_I) { - priv->tda8290_easy_mode = 0x08; - mode = "I"; - } else if (params->std & V4L2_STD_DK) { - priv->tda8290_easy_mode = 0x10; - mode = "DK"; - } else if (params->std & V4L2_STD_SECAM_L) { - priv->tda8290_easy_mode = 0x20; - mode = "L"; - } else if (params->std & V4L2_STD_SECAM_LC) { - priv->tda8290_easy_mode = 0x40; - mode = "LC"; - } else { - priv->tda8290_easy_mode = 0x10; - mode = "xx"; - } - - if (params->mode == V4L2_TUNER_RADIO) { - /* Set TDA8295 to FM radio; Start TDA8290 with MN values */ - priv->tda8290_easy_mode = (priv->ver & TDA8295) ? 0x80 : 0x01; - tuner_dbg("setting to radio FM\n"); - } else { - tuner_dbg("setting tda829x to system %s\n", mode); - } -} - -static struct { - unsigned char seq[2]; -} fm_mode[] = { - { { 0x01, 0x81} }, /* Put device into expert mode */ - { { 0x03, 0x48} }, /* Disable NOTCH and VIDEO filters */ - { { 0x04, 0x04} }, /* Disable color carrier filter (SSIF) */ - { { 0x05, 0x04} }, /* ADC headroom */ - { { 0x06, 0x10} }, /* group delay flat */ - - { { 0x07, 0x00} }, /* use the same radio DTO values as a tda8295 */ - { { 0x08, 0x00} }, - { { 0x09, 0x80} }, - { { 0x0a, 0xda} }, - { { 0x0b, 0x4b} }, - { { 0x0c, 0x68} }, - - { { 0x0d, 0x00} }, /* PLL off, no video carrier detect */ - { { 0x14, 0x00} }, /* disable auto mute if no video */ -}; - -static void tda8290_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - unsigned char soft_reset[] = { 0x00, 0x00 }; - unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; - unsigned char expert_mode[] = { 0x01, 0x80 }; - unsigned char agc_out_on[] = { 0x02, 0x00 }; - unsigned char gainset_off[] = { 0x28, 0x14 }; - unsigned char if_agc_spd[] = { 0x0f, 0x88 }; - unsigned char adc_head_6[] = { 0x05, 0x04 }; - unsigned char adc_head_9[] = { 0x05, 0x02 }; - unsigned char adc_head_12[] = { 0x05, 0x01 }; - unsigned char pll_bw_nom[] = { 0x0d, 0x47 }; - unsigned char pll_bw_low[] = { 0x0d, 0x27 }; - unsigned char gainset_2[] = { 0x28, 0x64 }; - unsigned char agc_rst_on[] = { 0x0e, 0x0b }; - unsigned char agc_rst_off[] = { 0x0e, 0x09 }; - unsigned char if_agc_set[] = { 0x0f, 0x81 }; - unsigned char addr_adc_sat = 0x1a; - unsigned char addr_agc_stat = 0x1d; - unsigned char addr_pll_stat = 0x1b; - unsigned char adc_sat, agc_stat, - pll_stat; - int i; - - set_audio(fe, params); - - if (priv->cfg.config) - tuner_dbg("tda827xa config is 0x%02x\n", priv->cfg.config); - tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); - tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); - tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); - msleep(1); - - if (params->mode == V4L2_TUNER_RADIO) { - unsigned char deemphasis[] = { 0x13, 1 }; - - /* FIXME: allow using a different deemphasis */ - - if (deemphasis_50) - deemphasis[1] = 2; - - for (i = 0; i < ARRAY_SIZE(fm_mode); i++) - tuner_i2c_xfer_send(&priv->i2c_props, fm_mode[i].seq, 2); - - tuner_i2c_xfer_send(&priv->i2c_props, deemphasis, 2); - } else { - expert_mode[1] = priv->tda8290_easy_mode + 0x80; - tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2); - tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2); - tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2); - if (priv->tda8290_easy_mode & 0x60) - tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2); - else - tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2); - tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); - } - - - tda8290_i2c_bridge(fe, 1); - - if (fe->ops.tuner_ops.set_analog_params) - fe->ops.tuner_ops.set_analog_params(fe, params); - - for (i = 0; i < 3; i++) { - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_pll_stat, 1, &pll_stat, 1); - if (pll_stat & 0x80) { - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_adc_sat, 1, - &adc_sat, 1); - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_agc_stat, 1, - &agc_stat, 1); - tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat); - break; - } else { - tuner_dbg("tda8290 not locked, no signal?\n"); - msleep(100); - } - } - /* adjust headroom resp. gain */ - if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) { - tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n", - agc_stat, adc_sat, pll_stat & 0x80); - tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2); - msleep(100); - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_agc_stat, 1, &agc_stat, 1); - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_pll_stat, 1, &pll_stat, 1); - if ((agc_stat > 115) || !(pll_stat & 0x80)) { - tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", - agc_stat, pll_stat & 0x80); - if (priv->cfg.agcf) - priv->cfg.agcf(fe); - msleep(100); - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_agc_stat, 1, - &agc_stat, 1); - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_pll_stat, 1, - &pll_stat, 1); - if((agc_stat > 115) || !(pll_stat & 0x80)) { - tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat); - tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2); - tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_low, 2); - msleep(100); - } - } - } - - /* l/ l' deadlock? */ - if(priv->tda8290_easy_mode & 0x60) { - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_adc_sat, 1, - &adc_sat, 1); - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_pll_stat, 1, - &pll_stat, 1); - if ((adc_sat > 20) || !(pll_stat & 0x80)) { - tuner_dbg("trying to resolve SECAM L deadlock\n"); - tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2); - msleep(40); - tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_off, 2); - } - } - - tda8290_i2c_bridge(fe, 0); - tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); -} - -/*---------------------------------------------------------------------*/ - -static void tda8295_power(struct dvb_frontend *fe, int enable) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */ - - tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); - - if (enable) - buf[1] = 0x01; - else - buf[1] = 0x03; - - tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); -} - -static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char buf[] = { 0x01, 0x00 }; - - tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); - - if (enable) - buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */ - else - buf[1] = 0x00; /* reset active bit */ - - tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); -} - -static void tda8295_set_video_std(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char buf[] = { 0x00, priv->tda8290_easy_mode }; - - tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); - - tda8295_set_easy_mode(fe, 1); - msleep(20); - tda8295_set_easy_mode(fe, 0); -} - -/*---------------------------------------------------------------------*/ - -static void tda8295_agc1_out(struct dvb_frontend *fe, int enable) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */ - - tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); - - if (enable) - buf[1] &= ~0x40; - else - buf[1] |= 0x40; - - tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); -} - -static void tda8295_agc2_out(struct dvb_frontend *fe, int enable) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char set_gpio_cf[] = { 0x44, 0x00 }; - unsigned char set_gpio_val[] = { 0x46, 0x00 }; - - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &set_gpio_cf[0], 1, &set_gpio_cf[1], 1); - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &set_gpio_val[0], 1, &set_gpio_val[1], 1); - - set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */ - - if (enable) { - set_gpio_cf[1] |= 0x01; /* config GPIO_0 as Open Drain Out */ - set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */ - } - tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2); -} - -static int tda8295_has_signal(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - unsigned char hvpll_stat = 0x26; - unsigned char ret; - - tuner_i2c_xfer_send_recv(&priv->i2c_props, &hvpll_stat, 1, &ret, 1); - return (ret & 0x01) ? 65535 : 0; -} - -/*---------------------------------------------------------------------*/ - -static void tda8295_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - unsigned char blanking_mode[] = { 0x1d, 0x00 }; - - set_audio(fe, params); - - tuner_dbg("%s: freq = %d\n", __func__, params->frequency); - - tda8295_power(fe, 1); - tda8295_agc1_out(fe, 1); - - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &blanking_mode[0], 1, &blanking_mode[1], 1); - - tda8295_set_video_std(fe); - - blanking_mode[1] = 0x03; - tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2); - msleep(20); - - tda8295_i2c_bridge(fe, 1); - - if (fe->ops.tuner_ops.set_analog_params) - fe->ops.tuner_ops.set_analog_params(fe, params); - - if (priv->cfg.agcf) - priv->cfg.agcf(fe); - - if (tda8295_has_signal(fe)) - tuner_dbg("tda8295 is locked\n"); - else - tuner_dbg("tda8295 not locked, no signal?\n"); - - tda8295_i2c_bridge(fe, 0); -} - -/*---------------------------------------------------------------------*/ - -static int tda8290_has_signal(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - unsigned char i2c_get_afc[1] = { 0x1B }; - unsigned char afc = 0; - - tuner_i2c_xfer_send_recv(&priv->i2c_props, - i2c_get_afc, ARRAY_SIZE(i2c_get_afc), &afc, 1); - return (afc & 0x80)? 65535:0; -} - -/*---------------------------------------------------------------------*/ - -static void tda8290_standby(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - unsigned char cb1[] = { 0x30, 0xD0 }; - unsigned char tda8290_standby[] = { 0x00, 0x02 }; - unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; - struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; - - tda8290_i2c_bridge(fe, 1); - if (priv->ver & TDA8275A) - cb1[1] = 0x90; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8290_i2c_bridge(fe, 0); - tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); - tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); -} - -static void tda8295_standby(struct dvb_frontend *fe) -{ - tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */ - - tda8295_power(fe, 0); -} - -static void tda8290_init_if(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - unsigned char set_VS[] = { 0x30, 0x6F }; - unsigned char set_GP00_CF[] = { 0x20, 0x01 }; - unsigned char set_GP01_CF[] = { 0x20, 0x0B }; - - if ((priv->cfg.config == 1) || (priv->cfg.config == 2)) - tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); - else - tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); -} - -static void tda8295_init_if(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - static unsigned char set_adc_ctl[] = { 0x33, 0x14 }; - static unsigned char set_adc_ctl2[] = { 0x34, 0x00 }; - static unsigned char set_pll_reg6[] = { 0x3e, 0x63 }; - static unsigned char set_pll_reg0[] = { 0x38, 0x23 }; - static unsigned char set_pll_reg7[] = { 0x3f, 0x01 }; - static unsigned char set_pll_reg10[] = { 0x42, 0x61 }; - static unsigned char set_gpio_reg0[] = { 0x44, 0x0b }; - - tda8295_power(fe, 1); - - tda8295_set_easy_mode(fe, 0); - tda8295_set_video_std(fe); - - tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2); - - tda8295_agc1_out(fe, 0); - tda8295_agc2_out(fe, 0); -} - -static void tda8290_init_tuner(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, - 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; - unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, - 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b }; - struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, - .buf=tda8275_init, .len = 14}; - if (priv->ver & TDA8275A) - msg.buf = tda8275a_init; - - tda8290_i2c_bridge(fe, 1); - i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8290_i2c_bridge(fe, 0); -} - -/*---------------------------------------------------------------------*/ - -static void tda829x_release(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - /* only try to release the tuner if we've - * attached it from within this module */ - if (priv->ver & (TDA18271 | TDA8275 | TDA8275A)) - if (fe->ops.tuner_ops.release) - fe->ops.tuner_ops.release(fe); - - kfree(fe->analog_demod_priv); - fe->analog_demod_priv = NULL; -} - -static struct tda18271_config tda829x_tda18271_config = { - .gate = TDA18271_GATE_ANALOG, -}; - -static int tda829x_find_tuner(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - struct analog_demod_ops *analog_ops = &fe->ops.analog_ops; - int i, ret, tuners_found; - u32 tuner_addrs; - u8 data; - struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; - - if (!analog_ops->i2c_gate_ctrl) { - printk(KERN_ERR "tda8290: no gate control were provided!\n"); - - return -EINVAL; - } - - analog_ops->i2c_gate_ctrl(fe, 1); - - /* probe for tuner chip */ - tuners_found = 0; - tuner_addrs = 0; - for (i = 0x60; i <= 0x63; i++) { - msg.addr = i; - ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - if (ret == 1) { - tuners_found++; - tuner_addrs = (tuner_addrs << 8) + i; - } - } - /* if there is more than one tuner, we expect the right one is - behind the bridge and we choose the highest address that doesn't - give a response now - */ - - analog_ops->i2c_gate_ctrl(fe, 0); - - if (tuners_found > 1) - for (i = 0; i < tuners_found; i++) { - msg.addr = tuner_addrs & 0xff; - ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - if (ret == 1) - tuner_addrs = tuner_addrs >> 8; - else - break; - } - - if (tuner_addrs == 0) { - tuner_addrs = 0x60; - tuner_info("could not clearly identify tuner address, " - "defaulting to %x\n", tuner_addrs); - } else { - tuner_addrs = tuner_addrs & 0xff; - tuner_info("setting tuner address to %x\n", tuner_addrs); - } - priv->tda827x_addr = tuner_addrs; - msg.addr = tuner_addrs; - - analog_ops->i2c_gate_ctrl(fe, 1); - ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - - if (ret != 1) { - tuner_warn("tuner access failed!\n"); - analog_ops->i2c_gate_ctrl(fe, 0); - return -EREMOTEIO; - } - - if ((data == 0x83) || (data == 0x84)) { - priv->ver |= TDA18271; - tda829x_tda18271_config.config = priv->cfg.config; - dvb_attach(tda18271_attach, fe, priv->tda827x_addr, - priv->i2c_props.adap, &tda829x_tda18271_config); - } else { - if ((data & 0x3c) == 0) - priv->ver |= TDA8275; - else - priv->ver |= TDA8275A; - - dvb_attach(tda827x_attach, fe, priv->tda827x_addr, - priv->i2c_props.adap, &priv->cfg); - priv->cfg.switch_addr = priv->i2c_props.addr; - } - if (fe->ops.tuner_ops.init) - fe->ops.tuner_ops.init(fe); - - if (fe->ops.tuner_ops.sleep) - fe->ops.tuner_ops.sleep(fe); - - analog_ops->i2c_gate_ctrl(fe, 0); - - return 0; -} - -static int tda8290_probe(struct tuner_i2c_props *i2c_props) -{ -#define TDA8290_ID 0x89 - u8 reg = 0x1f, id; - struct i2c_msg msg_read[] = { - { .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = ® }, - { .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id }, - }; - - /* detect tda8290 */ - if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) { - printk(KERN_WARNING "%s: couldn't read register 0x%02x\n", - __func__, reg); - return -ENODEV; - } - - if (id == TDA8290_ID) { - if (debug) - printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n", - __func__, i2c_adapter_id(i2c_props->adap), - i2c_props->addr); - return 0; - } - return -ENODEV; -} - -static int tda8295_probe(struct tuner_i2c_props *i2c_props) -{ -#define TDA8295_ID 0x8a -#define TDA8295C2_ID 0x8b - u8 reg = 0x2f, id; - struct i2c_msg msg_read[] = { - { .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = ® }, - { .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id }, - }; - - /* detect tda8295 */ - if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) { - printk(KERN_WARNING "%s: couldn't read register 0x%02x\n", - __func__, reg); - return -ENODEV; - } - - if ((id & 0xfe) == TDA8295_ID) { - if (debug) - printk(KERN_DEBUG "%s: %s detected @ %d-%04x\n", - __func__, (id == TDA8295_ID) ? - "tda8295c1" : "tda8295c2", - i2c_adapter_id(i2c_props->adap), - i2c_props->addr); - return 0; - } - - return -ENODEV; -} - -static struct analog_demod_ops tda8290_ops = { - .set_params = tda8290_set_params, - .has_signal = tda8290_has_signal, - .standby = tda8290_standby, - .release = tda829x_release, - .i2c_gate_ctrl = tda8290_i2c_bridge, -}; - -static struct analog_demod_ops tda8295_ops = { - .set_params = tda8295_set_params, - .has_signal = tda8295_has_signal, - .standby = tda8295_standby, - .release = tda829x_release, - .i2c_gate_ctrl = tda8295_i2c_bridge, -}; - -struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, u8 i2c_addr, - struct tda829x_config *cfg) -{ - struct tda8290_priv *priv = NULL; - char *name; - - priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - fe->analog_demod_priv = priv; - - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; - priv->i2c_props.name = "tda829x"; - if (cfg) - priv->cfg.config = cfg->lna_cfg; - - if (tda8290_probe(&priv->i2c_props) == 0) { - priv->ver = TDA8290; - memcpy(&fe->ops.analog_ops, &tda8290_ops, - sizeof(struct analog_demod_ops)); - } - - if (tda8295_probe(&priv->i2c_props) == 0) { - priv->ver = TDA8295; - memcpy(&fe->ops.analog_ops, &tda8295_ops, - sizeof(struct analog_demod_ops)); - } - - if (!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) { - tda8295_power(fe, 1); - if (tda829x_find_tuner(fe) < 0) - goto fail; - } - - switch (priv->ver) { - case TDA8290: - name = "tda8290"; - break; - case TDA8295: - name = "tda8295"; - break; - case TDA8290 | TDA8275: - name = "tda8290+75"; - break; - case TDA8295 | TDA8275: - name = "tda8295+75"; - break; - case TDA8290 | TDA8275A: - name = "tda8290+75a"; - break; - case TDA8295 | TDA8275A: - name = "tda8295+75a"; - break; - case TDA8290 | TDA18271: - name = "tda8290+18271"; - break; - case TDA8295 | TDA18271: - name = "tda8295+18271"; - break; - default: - goto fail; - } - tuner_info("type set to %s\n", name); - - fe->ops.analog_ops.info.name = name; - - if (priv->ver & TDA8290) { - if (priv->ver & (TDA8275 | TDA8275A)) - tda8290_init_tuner(fe); - tda8290_init_if(fe); - } else if (priv->ver & TDA8295) - tda8295_init_if(fe); - - return fe; - -fail: - memset(&fe->ops.analog_ops, 0, sizeof(struct analog_demod_ops)); - - tda829x_release(fe); - return NULL; -} -EXPORT_SYMBOL_GPL(tda829x_attach); - -int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) -{ - struct tuner_i2c_props i2c_props = { - .adap = i2c_adap, - .addr = i2c_addr, - }; - - unsigned char soft_reset[] = { 0x00, 0x00 }; - unsigned char easy_mode_b[] = { 0x01, 0x02 }; - unsigned char easy_mode_g[] = { 0x01, 0x04 }; - unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 }; - unsigned char addr_dto_lsb = 0x07; - unsigned char data; -#define PROBE_BUFFER_SIZE 8 - unsigned char buf[PROBE_BUFFER_SIZE]; - int i; - - /* rule out tda9887, which would return the same byte repeatedly */ - tuner_i2c_xfer_send_recv(&i2c_props, - soft_reset, 1, buf, PROBE_BUFFER_SIZE); - for (i = 1; i < PROBE_BUFFER_SIZE; i++) { - if (buf[i] != buf[0]) - break; - } - - /* all bytes are equal, not a tda829x - probably a tda9887 */ - if (i == PROBE_BUFFER_SIZE) - return -ENODEV; - - if ((tda8290_probe(&i2c_props) == 0) || - (tda8295_probe(&i2c_props) == 0)) - return 0; - - /* fall back to old probing method */ - tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2); - tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); - tuner_i2c_xfer_send_recv(&i2c_props, &addr_dto_lsb, 1, &data, 1); - if (data == 0) { - tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2); - tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); - tuner_i2c_xfer_send_recv(&i2c_props, - &addr_dto_lsb, 1, &data, 1); - if (data == 0x7b) { - return 0; - } - } - tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); - return -ENODEV; -} -EXPORT_SYMBOL_GPL(tda829x_probe); - -MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver"); -MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); -MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/common/tuners/tda8290.h b/drivers/media/common/tuners/tda8290.h deleted file mode 100644 index 7e288b26fcc3..000000000000 --- a/drivers/media/common/tuners/tda8290.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - 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 __TDA8290_H__ -#define __TDA8290_H__ - -#include -#include "dvb_frontend.h" - -struct tda829x_config { - unsigned int lna_cfg; - - unsigned int probe_tuner:1; -#define TDA829X_PROBE_TUNER 0 -#define TDA829X_DONT_PROBE 1 -}; - -#if defined(CONFIG_MEDIA_TUNER_TDA8290) || (defined(CONFIG_MEDIA_TUNER_TDA8290_MODULE) && defined(MODULE)) -extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr); - -extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr, - struct tda829x_config *cfg); -#else -static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -EINVAL; -} - -static inline struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr, - struct tda829x_config *cfg) -{ - printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", - __func__); - return NULL; -} -#endif - -#endif /* __TDA8290_H__ */ diff --git a/drivers/media/common/tuners/tda9887.c b/drivers/media/common/tuners/tda9887.c deleted file mode 100644 index cdb645d57438..000000000000 --- a/drivers/media/common/tuners/tda9887.c +++ /dev/null @@ -1,717 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "tuner-i2c.h" -#include "tda9887.h" - - -/* Chips: - TDA9885 (PAL, NTSC) - TDA9886 (PAL, SECAM, NTSC) - TDA9887 (PAL, SECAM, NTSC, FM Radio) - - Used as part of several tuners -*/ - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -static DEFINE_MUTEX(tda9887_list_mutex); -static LIST_HEAD(hybrid_tuner_instance_list); - -struct tda9887_priv { - struct tuner_i2c_props i2c_props; - struct list_head hybrid_tuner_instance_list; - - unsigned char data[4]; - unsigned int config; - unsigned int mode; - unsigned int audmode; - v4l2_std_id std; - - bool standby; -}; - -/* ---------------------------------------------------------------------- */ - -#define UNSET (-1U) - -struct tvnorm { - v4l2_std_id std; - char *name; - unsigned char b; - unsigned char c; - unsigned char e; -}; - -/* ---------------------------------------------------------------------- */ - -// -// TDA defines -// - -//// first reg (b) -#define cVideoTrapBypassOFF 0x00 // bit b0 -#define cVideoTrapBypassON 0x01 // bit b0 - -#define cAutoMuteFmInactive 0x00 // bit b1 -#define cAutoMuteFmActive 0x02 // bit b1 - -#define cIntercarrier 0x00 // bit b2 -#define cQSS 0x04 // bit b2 - -#define cPositiveAmTV 0x00 // bit b3:4 -#define cFmRadio 0x08 // bit b3:4 -#define cNegativeFmTV 0x10 // bit b3:4 - - -#define cForcedMuteAudioON 0x20 // bit b5 -#define cForcedMuteAudioOFF 0x00 // bit b5 - -#define cOutputPort1Active 0x00 // bit b6 -#define cOutputPort1Inactive 0x40 // bit b6 - -#define cOutputPort2Active 0x00 // bit b7 -#define cOutputPort2Inactive 0x80 // bit b7 - - -//// second reg (c) -#define cDeemphasisOFF 0x00 // bit c5 -#define cDeemphasisON 0x20 // bit c5 - -#define cDeemphasis75 0x00 // bit c6 -#define cDeemphasis50 0x40 // bit c6 - -#define cAudioGain0 0x00 // bit c7 -#define cAudioGain6 0x80 // bit c7 - -#define cTopMask 0x1f // bit c0:4 -#define cTopDefault 0x10 // bit c0:4 - -//// third reg (e) -#define cAudioIF_4_5 0x00 // bit e0:1 -#define cAudioIF_5_5 0x01 // bit e0:1 -#define cAudioIF_6_0 0x02 // bit e0:1 -#define cAudioIF_6_5 0x03 // bit e0:1 - - -#define cVideoIFMask 0x1c // bit e2:4 -/* Video IF selection in TV Mode (bit B3=0) */ -#define cVideoIF_58_75 0x00 // bit e2:4 -#define cVideoIF_45_75 0x04 // bit e2:4 -#define cVideoIF_38_90 0x08 // bit e2:4 -#define cVideoIF_38_00 0x0C // bit e2:4 -#define cVideoIF_33_90 0x10 // bit e2:4 -#define cVideoIF_33_40 0x14 // bit e2:4 -#define cRadioIF_45_75 0x18 // bit e2:4 -#define cRadioIF_38_90 0x1C // bit e2:4 - -/* IF1 selection in Radio Mode (bit B3=1) */ -#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14) -#define cRadioIF_41_30 0x04 // bit e2,4 - -/* Output of AFC pin in radio mode when bit E7=1 */ -#define cRadioAGC_SIF 0x00 // bit e3 -#define cRadioAGC_FM 0x08 // bit e3 - -#define cTunerGainNormal 0x00 // bit e5 -#define cTunerGainLow 0x20 // bit e5 - -#define cGating_18 0x00 // bit e6 -#define cGating_36 0x40 // bit e6 - -#define cAgcOutON 0x80 // bit e7 -#define cAgcOutOFF 0x00 // bit e7 - -/* ---------------------------------------------------------------------- */ - -static struct tvnorm tvnorms[] = { - { - .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N, - .name = "PAL-BGHN", - .b = ( cNegativeFmTV | - cQSS ), - .c = ( cDeemphasisON | - cDeemphasis50 | - cTopDefault), - .e = ( cGating_36 | - cAudioIF_5_5 | - cVideoIF_38_90 ), - },{ - .std = V4L2_STD_PAL_I, - .name = "PAL-I", - .b = ( cNegativeFmTV | - cQSS ), - .c = ( cDeemphasisON | - cDeemphasis50 | - cTopDefault), - .e = ( cGating_36 | - cAudioIF_6_0 | - cVideoIF_38_90 ), - },{ - .std = V4L2_STD_PAL_DK, - .name = "PAL-DK", - .b = ( cNegativeFmTV | - cQSS ), - .c = ( cDeemphasisON | - cDeemphasis50 | - cTopDefault), - .e = ( cGating_36 | - cAudioIF_6_5 | - cVideoIF_38_90 ), - },{ - .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc, - .name = "PAL-M/Nc", - .b = ( cNegativeFmTV | - cQSS ), - .c = ( cDeemphasisON | - cDeemphasis75 | - cTopDefault), - .e = ( cGating_36 | - cAudioIF_4_5 | - cVideoIF_45_75 ), - },{ - .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, - .name = "SECAM-BGH", - .b = ( cNegativeFmTV | - cQSS ), - .c = ( cTopDefault), - .e = ( cAudioIF_5_5 | - cVideoIF_38_90 ), - },{ - .std = V4L2_STD_SECAM_L, - .name = "SECAM-L", - .b = ( cPositiveAmTV | - cQSS ), - .c = ( cTopDefault), - .e = ( cGating_36 | - cAudioIF_6_5 | - cVideoIF_38_90 ), - },{ - .std = V4L2_STD_SECAM_LC, - .name = "SECAM-L'", - .b = ( cOutputPort2Inactive | - cPositiveAmTV | - cQSS ), - .c = ( cTopDefault), - .e = ( cGating_36 | - cAudioIF_6_5 | - cVideoIF_33_90 ), - },{ - .std = V4L2_STD_SECAM_DK, - .name = "SECAM-DK", - .b = ( cNegativeFmTV | - cQSS ), - .c = ( cDeemphasisON | - cDeemphasis50 | - cTopDefault), - .e = ( cGating_36 | - cAudioIF_6_5 | - cVideoIF_38_90 ), - },{ - .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR, - .name = "NTSC-M", - .b = ( cNegativeFmTV | - cQSS ), - .c = ( cDeemphasisON | - cDeemphasis75 | - cTopDefault), - .e = ( cGating_36 | - cAudioIF_4_5 | - cVideoIF_45_75 ), - },{ - .std = V4L2_STD_NTSC_M_JP, - .name = "NTSC-M-JP", - .b = ( cNegativeFmTV | - cQSS ), - .c = ( cDeemphasisON | - cDeemphasis50 | - cTopDefault), - .e = ( cGating_36 | - cAudioIF_4_5 | - cVideoIF_58_75 ), - } -}; - -static struct tvnorm radio_stereo = { - .name = "Radio Stereo", - .b = ( cFmRadio | - cQSS ), - .c = ( cDeemphasisOFF | - cAudioGain6 | - cTopDefault), - .e = ( cTunerGainLow | - cAudioIF_5_5 | - cRadioIF_38_90 ), -}; - -static struct tvnorm radio_mono = { - .name = "Radio Mono", - .b = ( cFmRadio | - cQSS ), - .c = ( cDeemphasisON | - cDeemphasis75 | - cTopDefault), - .e = ( cTunerGainLow | - cAudioIF_5_5 | - cRadioIF_38_90 ), -}; - -/* ---------------------------------------------------------------------- */ - -static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - - static char *afc[16] = { - "- 12.5 kHz", - "- 37.5 kHz", - "- 62.5 kHz", - "- 87.5 kHz", - "-112.5 kHz", - "-137.5 kHz", - "-162.5 kHz", - "-187.5 kHz [min]", - "+187.5 kHz [max]", - "+162.5 kHz", - "+137.5 kHz", - "+112.5 kHz", - "+ 87.5 kHz", - "+ 62.5 kHz", - "+ 37.5 kHz", - "+ 12.5 kHz", - }; - tuner_info("read: 0x%2x\n", buf[0]); - tuner_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no"); - tuner_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]); - tuner_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low"); - tuner_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out"); - tuner_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); -} - -static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - - static char *sound[4] = { - "AM/TV", - "FM/radio", - "FM/TV", - "FM/radio" - }; - static char *adjust[32] = { - "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9", - "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1", - "0", "+1", "+2", "+3", "+4", "+5", "+6", "+7", - "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15" - }; - static char *deemph[4] = { - "no", "no", "75", "50" - }; - static char *carrier[4] = { - "4.5 MHz", - "5.5 MHz", - "6.0 MHz", - "6.5 MHz / AM" - }; - static char *vif[8] = { - "58.75 MHz", - "45.75 MHz", - "38.9 MHz", - "38.0 MHz", - "33.9 MHz", - "33.4 MHz", - "45.75 MHz + pin13", - "38.9 MHz + pin13", - }; - static char *rif[4] = { - "44 MHz", - "52 MHz", - "52 MHz", - "44 MHz", - }; - - tuner_info("write: byte B 0x%02x\n", buf[1]); - tuner_info(" B0 video mode : %s\n", - (buf[1] & 0x01) ? "video trap" : "sound trap"); - tuner_info(" B1 auto mute fm : %s\n", - (buf[1] & 0x02) ? "yes" : "no"); - tuner_info(" B2 carrier mode : %s\n", - (buf[1] & 0x04) ? "QSS" : "Intercarrier"); - tuner_info(" B3-4 tv sound/radio : %s\n", - sound[(buf[1] & 0x18) >> 3]); - tuner_info(" B5 force mute audio: %s\n", - (buf[1] & 0x20) ? "yes" : "no"); - tuner_info(" B6 output port 1 : %s\n", - (buf[1] & 0x40) ? "high (inactive)" : "low (active)"); - tuner_info(" B7 output port 2 : %s\n", - (buf[1] & 0x80) ? "high (inactive)" : "low (active)"); - - tuner_info("write: byte C 0x%02x\n", buf[2]); - tuner_info(" C0-4 top adjustment : %s dB\n", - adjust[buf[2] & 0x1f]); - tuner_info(" C5-6 de-emphasis : %s\n", - deemph[(buf[2] & 0x60) >> 5]); - tuner_info(" C7 audio gain : %s\n", - (buf[2] & 0x80) ? "-6" : "0"); - - tuner_info("write: byte E 0x%02x\n", buf[3]); - tuner_info(" E0-1 sound carrier : %s\n", - carrier[(buf[3] & 0x03)]); - tuner_info(" E6 l pll gating : %s\n", - (buf[3] & 0x40) ? "36" : "13"); - - if (buf[1] & 0x08) { - /* radio */ - tuner_info(" E2-4 video if : %s\n", - rif[(buf[3] & 0x0c) >> 2]); - tuner_info(" E7 vif agc output : %s\n", - (buf[3] & 0x80) - ? ((buf[3] & 0x10) ? "fm-agc radio" : - "sif-agc radio") - : "fm radio carrier afc"); - } else { - /* video */ - tuner_info(" E2-4 video if : %s\n", - vif[(buf[3] & 0x1c) >> 2]); - tuner_info(" E5 tuner gain : %s\n", - (buf[3] & 0x80) - ? ((buf[3] & 0x20) ? "external" : "normal") - : ((buf[3] & 0x20) ? "minimum" : "normal")); - tuner_info(" E7 vif agc output : %s\n", - (buf[3] & 0x80) ? ((buf[3] & 0x20) - ? "pin3 port, pin22 vif agc out" - : "pin22 port, pin3 vif acg ext in") - : "pin3+pin22 port"); - } - tuner_info("--\n"); -} - -/* ---------------------------------------------------------------------- */ - -static int tda9887_set_tvnorm(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - struct tvnorm *norm = NULL; - char *buf = priv->data; - int i; - - if (priv->mode == V4L2_TUNER_RADIO) { - if (priv->audmode == V4L2_TUNER_MODE_MONO) - norm = &radio_mono; - else - norm = &radio_stereo; - } else { - for (i = 0; i < ARRAY_SIZE(tvnorms); i++) { - if (tvnorms[i].std & priv->std) { - norm = tvnorms+i; - break; - } - } - } - if (NULL == norm) { - tuner_dbg("Unsupported tvnorm entry - audio muted\n"); - return -1; - } - - tuner_dbg("configure for: %s\n", norm->name); - buf[1] = norm->b; - buf[2] = norm->c; - buf[3] = norm->e; - return 0; -} - -static unsigned int port1 = UNSET; -static unsigned int port2 = UNSET; -static unsigned int qss = UNSET; -static unsigned int adjust = UNSET; - -module_param(port1, int, 0644); -module_param(port2, int, 0644); -module_param(qss, int, 0644); -module_param(adjust, int, 0644); - -static int tda9887_set_insmod(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - char *buf = priv->data; - - if (UNSET != port1) { - if (port1) - buf[1] |= cOutputPort1Inactive; - else - buf[1] &= ~cOutputPort1Inactive; - } - if (UNSET != port2) { - if (port2) - buf[1] |= cOutputPort2Inactive; - else - buf[1] &= ~cOutputPort2Inactive; - } - - if (UNSET != qss) { - if (qss) - buf[1] |= cQSS; - else - buf[1] &= ~cQSS; - } - - if (adjust < 0x20) { - buf[2] &= ~cTopMask; - buf[2] |= adjust; - } - return 0; -} - -static int tda9887_do_config(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - char *buf = priv->data; - - if (priv->config & TDA9887_PORT1_ACTIVE) - buf[1] &= ~cOutputPort1Inactive; - if (priv->config & TDA9887_PORT1_INACTIVE) - buf[1] |= cOutputPort1Inactive; - if (priv->config & TDA9887_PORT2_ACTIVE) - buf[1] &= ~cOutputPort2Inactive; - if (priv->config & TDA9887_PORT2_INACTIVE) - buf[1] |= cOutputPort2Inactive; - - if (priv->config & TDA9887_QSS) - buf[1] |= cQSS; - if (priv->config & TDA9887_INTERCARRIER) - buf[1] &= ~cQSS; - - if (priv->config & TDA9887_AUTOMUTE) - buf[1] |= cAutoMuteFmActive; - if (priv->config & TDA9887_DEEMPHASIS_MASK) { - buf[2] &= ~0x60; - switch (priv->config & TDA9887_DEEMPHASIS_MASK) { - case TDA9887_DEEMPHASIS_NONE: - buf[2] |= cDeemphasisOFF; - break; - case TDA9887_DEEMPHASIS_50: - buf[2] |= cDeemphasisON | cDeemphasis50; - break; - case TDA9887_DEEMPHASIS_75: - buf[2] |= cDeemphasisON | cDeemphasis75; - break; - } - } - if (priv->config & TDA9887_TOP_SET) { - buf[2] &= ~cTopMask; - buf[2] |= (priv->config >> 8) & cTopMask; - } - if ((priv->config & TDA9887_INTERCARRIER_NTSC) && - (priv->std & V4L2_STD_NTSC)) - buf[1] &= ~cQSS; - if (priv->config & TDA9887_GATING_18) - buf[3] &= ~cGating_36; - - if (priv->mode == V4L2_TUNER_RADIO) { - if (priv->config & TDA9887_RIF_41_3) { - buf[3] &= ~cVideoIFMask; - buf[3] |= cRadioIF_41_30; - } - if (priv->config & TDA9887_GAIN_NORMAL) - buf[3] &= ~cTunerGainLow; - } - - return 0; -} - -/* ---------------------------------------------------------------------- */ - -static int tda9887_status(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - unsigned char buf[1]; - int rc; - - memset(buf,0,sizeof(buf)); - if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1))) - tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc); - dump_read_message(fe, buf); - return 0; -} - -static void tda9887_configure(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - int rc; - - memset(priv->data,0,sizeof(priv->data)); - tda9887_set_tvnorm(fe); - - /* A note on the port settings: - These settings tend to depend on the specifics of the board. - By default they are set to inactive (bit value 1) by this driver, - overwriting any changes made by the tvnorm. This means that it - is the responsibility of the module using the tda9887 to set - these values in case of changes in the tvnorm. - In many cases port 2 should be made active (0) when selecting - SECAM-L, and port 2 should remain inactive (1) for SECAM-L'. - - For the other standards the tda9887 application note says that - the ports should be set to active (0), but, again, that may - differ depending on the precise hardware configuration. - */ - priv->data[1] |= cOutputPort1Inactive; - priv->data[1] |= cOutputPort2Inactive; - - tda9887_do_config(fe); - tda9887_set_insmod(fe); - - if (priv->standby) - priv->data[1] |= cForcedMuteAudioON; - - tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", - priv->data[1], priv->data[2], priv->data[3]); - if (debug > 1) - dump_write_message(fe, priv->data); - - if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4))) - tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc); - - if (debug > 2) { - msleep_interruptible(1000); - tda9887_status(fe); - } -} - -/* ---------------------------------------------------------------------- */ - -static void tda9887_tuner_status(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", - priv->data[1], priv->data[2], priv->data[3]); -} - -static int tda9887_get_afc(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - static int AFC_BITS_2_kHz[] = { - -12500, -37500, -62500, -97500, - -112500, -137500, -162500, -187500, - 187500, 162500, 137500, 112500, - 97500 , 62500, 37500 , 12500 - }; - int afc=0; - __u8 reg = 0; - - if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,®,1)) - afc = AFC_BITS_2_kHz[(reg>>1)&0x0f]; - - return afc; -} - -static void tda9887_standby(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - - priv->standby = true; - - tda9887_configure(fe); -} - -static void tda9887_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - - priv->standby = false; - priv->mode = params->mode; - priv->audmode = params->audmode; - priv->std = params->std; - tda9887_configure(fe); -} - -static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - - priv->config = *(unsigned int *)priv_cfg; - tda9887_configure(fe); - - return 0; -} - -static void tda9887_release(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - - mutex_lock(&tda9887_list_mutex); - - if (priv) - hybrid_tuner_release_state(priv); - - mutex_unlock(&tda9887_list_mutex); - - fe->analog_demod_priv = NULL; -} - -static struct analog_demod_ops tda9887_ops = { - .info = { - .name = "tda9887", - }, - .set_params = tda9887_set_params, - .standby = tda9887_standby, - .tuner_status = tda9887_tuner_status, - .get_afc = tda9887_get_afc, - .release = tda9887_release, - .set_config = tda9887_set_config, -}; - -struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr) -{ - struct tda9887_priv *priv = NULL; - int instance; - - mutex_lock(&tda9887_list_mutex); - - instance = hybrid_tuner_request_state(struct tda9887_priv, priv, - hybrid_tuner_instance_list, - i2c_adap, i2c_addr, "tda9887"); - switch (instance) { - case 0: - mutex_unlock(&tda9887_list_mutex); - return NULL; - case 1: - fe->analog_demod_priv = priv; - priv->standby = true; - tuner_info("tda988[5/6/7] found\n"); - break; - default: - fe->analog_demod_priv = priv; - break; - } - - mutex_unlock(&tda9887_list_mutex); - - memcpy(&fe->ops.analog_ops, &tda9887_ops, - sizeof(struct analog_demod_ops)); - - return fe; -} -EXPORT_SYMBOL_GPL(tda9887_attach); - -MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/common/tuners/tda9887.h b/drivers/media/common/tuners/tda9887.h deleted file mode 100644 index acc419e8c4fc..000000000000 --- a/drivers/media/common/tuners/tda9887.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - 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 __TDA9887_H__ -#define __TDA9887_H__ - -#include -#include "dvb_frontend.h" - -/* ------------------------------------------------------------------------ */ -#if defined(CONFIG_MEDIA_TUNER_TDA9887) || (defined(CONFIG_MEDIA_TUNER_TDA9887_MODULE) && defined(MODULE)) -extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr); -#else -static inline struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* __TDA9887_H__ */ diff --git a/drivers/media/common/tuners/tea5761.c b/drivers/media/common/tuners/tea5761.c deleted file mode 100644 index bf78cb9fc52c..000000000000 --- a/drivers/media/common/tuners/tea5761.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * For Philips TEA5761 FM Chip - * I2C address is allways 0x20 (0x10 at 7-bit mode). - * - * Copyright (c) 2005-2007 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNUv2 General Public License - * - */ - -#include -#include -#include -#include -#include -#include "tuner-i2c.h" -#include "tea5761.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -struct tea5761_priv { - struct tuner_i2c_props i2c_props; - - u32 frequency; - bool standby; -}; - -/*****************************************************************************/ - -/*************************** - * TEA5761HN I2C registers * - ***************************/ - -/* INTREG - Read: bytes 0 and 1 / Write: byte 0 */ - - /* first byte for reading */ -#define TEA5761_INTREG_IFFLAG 0x10 -#define TEA5761_INTREG_LEVFLAG 0x8 -#define TEA5761_INTREG_FRRFLAG 0x2 -#define TEA5761_INTREG_BLFLAG 0x1 - - /* second byte for reading / byte for writing */ -#define TEA5761_INTREG_IFMSK 0x10 -#define TEA5761_INTREG_LEVMSK 0x8 -#define TEA5761_INTREG_FRMSK 0x2 -#define TEA5761_INTREG_BLMSK 0x1 - -/* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */ - - /* First byte */ -#define TEA5761_FRQSET_SEARCH_UP 0x80 /* 1=Station search from botton to up */ -#define TEA5761_FRQSET_SEARCH_MODE 0x40 /* 1=Search mode */ - - /* Bits 0-5 for divider MSB */ - - /* Second byte */ - /* Bits 0-7 for divider LSB */ - -/* TNCTRL - Read: bytes 4 and 5 / Write: Bytes 3 and 4 */ - - /* first byte */ - -#define TEA5761_TNCTRL_PUPD_0 0x40 /* Power UP/Power Down MSB */ -#define TEA5761_TNCTRL_BLIM 0X20 /* 1= Japan Frequencies, 0= European frequencies */ -#define TEA5761_TNCTRL_SWPM 0x10 /* 1= software port is FRRFLAG */ -#define TEA5761_TNCTRL_IFCTC 0x08 /* 1= IF count time 15.02 ms, 0= IF count time 2.02 ms */ -#define TEA5761_TNCTRL_AFM 0x04 -#define TEA5761_TNCTRL_SMUTE 0x02 /* 1= Soft mute */ -#define TEA5761_TNCTRL_SNC 0x01 - - /* second byte */ - -#define TEA5761_TNCTRL_MU 0x80 /* 1=Hard mute */ -#define TEA5761_TNCTRL_SSL_1 0x40 -#define TEA5761_TNCTRL_SSL_0 0x20 -#define TEA5761_TNCTRL_HLSI 0x10 -#define TEA5761_TNCTRL_MST 0x08 /* 1 = mono */ -#define TEA5761_TNCTRL_SWP 0x04 -#define TEA5761_TNCTRL_DTC 0x02 /* 1 = deemphasis 50 us, 0 = deemphasis 75 us */ -#define TEA5761_TNCTRL_AHLSI 0x01 - -/* FRQCHECK - Read: bytes 6 and 7 */ - /* First byte */ - - /* Bits 0-5 for divider MSB */ - - /* Second byte */ - /* Bits 0-7 for divider LSB */ - -/* TUNCHECK - Read: bytes 8 and 9 */ - - /* First byte */ -#define TEA5761_TUNCHECK_IF_MASK 0x7e /* IF count */ -#define TEA5761_TUNCHECK_TUNTO 0x01 - - /* Second byte */ -#define TEA5761_TUNCHECK_LEV_MASK 0xf0 /* Level Count */ -#define TEA5761_TUNCHECK_LD 0x08 -#define TEA5761_TUNCHECK_STEREO 0x04 - -/* TESTREG - Read: bytes 10 and 11 / Write: bytes 5 and 6 */ - - /* All zero = no test mode */ - -/* MANID - Read: bytes 12 and 13 */ - - /* First byte - should be 0x10 */ -#define TEA5767_MANID_VERSION_MASK 0xf0 /* Version = 1 */ -#define TEA5767_MANID_ID_MSB_MASK 0x0f /* Manufacurer ID - should be 0 */ - - /* Second byte - Should be 0x2b */ - -#define TEA5767_MANID_ID_LSB_MASK 0xfe /* Manufacturer ID - should be 0x15 */ -#define TEA5767_MANID_IDAV 0x01 /* 1 = Chip has ID, 0 = Chip has no ID */ - -/* Chip ID - Read: bytes 14 and 15 */ - - /* First byte - should be 0x57 */ - - /* Second byte - should be 0x61 */ - -/*****************************************************************************/ - -#define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */ -static void tea5761_status_dump(unsigned char *buffer) -{ - unsigned int div, frq; - - div = ((buffer[2] & 0x3f) << 8) | buffer[3]; - - frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4; /* Freq in KHz */ - - printk(KERN_INFO "tea5761: Frequency %d.%03d KHz (divider = 0x%04x)\n", - frq / 1000, frq % 1000, div); -} - -/* Freq should be specifyed at 62.5 Hz */ -static int __set_radio_freq(struct dvb_frontend *fe, - unsigned int freq, - bool mono) -{ - struct tea5761_priv *priv = fe->tuner_priv; - unsigned int frq = freq; - unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 }; - unsigned div; - int rc; - - tuner_dbg("radio freq counter %d\n", frq); - - if (priv->standby) { - tuner_dbg("TEA5761 set to standby mode\n"); - buffer[5] |= TEA5761_TNCTRL_MU; - } else { - buffer[4] |= TEA5761_TNCTRL_PUPD_0; - } - - - if (mono) { - tuner_dbg("TEA5761 set to mono\n"); - buffer[5] |= TEA5761_TNCTRL_MST; - } else { - tuner_dbg("TEA5761 set to stereo\n"); - } - - div = (1000 * (frq * 4 / 16 + 700 + 225) ) >> 15; - buffer[1] = (div >> 8) & 0x3f; - buffer[2] = div & 0xff; - - if (debug) - tea5761_status_dump(buffer); - - if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); - - priv->frequency = frq * 125 / 2; - - return 0; -} - -static int set_radio_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tea5761_priv *priv = fe->analog_demod_priv; - - priv->standby = false; - - return __set_radio_freq(fe, params->frequency, - params->audmode == V4L2_TUNER_MODE_MONO); -} - -static int set_radio_sleep(struct dvb_frontend *fe) -{ - struct tea5761_priv *priv = fe->analog_demod_priv; - - priv->standby = true; - - return __set_radio_freq(fe, priv->frequency, false); -} - -static int tea5761_read_status(struct dvb_frontend *fe, char *buffer) -{ - struct tea5761_priv *priv = fe->tuner_priv; - int rc; - - memset(buffer, 0, 16); - if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) { - tuner_warn("i2c i/o error: rc == %d (should be 16)\n", rc); - return -EREMOTEIO; - } - - return 0; -} - -static inline int tea5761_signal(struct dvb_frontend *fe, const char *buffer) -{ - struct tea5761_priv *priv = fe->tuner_priv; - - int signal = ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); - - tuner_dbg("Signal strength: %d\n", signal); - - return signal; -} - -static inline int tea5761_stereo(struct dvb_frontend *fe, const char *buffer) -{ - struct tea5761_priv *priv = fe->tuner_priv; - - int stereo = buffer[9] & TEA5761_TUNCHECK_STEREO; - - tuner_dbg("Radio ST GET = %02x\n", stereo); - - return (stereo ? V4L2_TUNER_SUB_STEREO : 0); -} - -static int tea5761_get_status(struct dvb_frontend *fe, u32 *status) -{ - unsigned char buffer[16]; - - *status = 0; - - if (0 == tea5761_read_status(fe, buffer)) { - if (tea5761_signal(fe, buffer)) - *status = TUNER_STATUS_LOCKED; - if (tea5761_stereo(fe, buffer)) - *status |= TUNER_STATUS_STEREO; - } - - return 0; -} - -static int tea5761_get_rf_strength(struct dvb_frontend *fe, u16 *strength) -{ - unsigned char buffer[16]; - - *strength = 0; - - if (0 == tea5761_read_status(fe, buffer)) - *strength = tea5761_signal(fe, buffer); - - return 0; -} - -int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) -{ - unsigned char buffer[16]; - int rc; - struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; - - if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) { - printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc); - return -EINVAL; - } - - if ((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061)) { - printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x." - " It is not a TEA5761\n", - buffer[13], buffer[14], buffer[15]); - return -EINVAL; - } - printk(KERN_WARNING "tea5761: TEA%02x%02x detected. " - "Manufacturer ID= 0x%02x\n", - buffer[14], buffer[15], buffer[13]); - - return 0; -} - -static int tea5761_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - - return 0; -} - -static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tea5761_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static struct dvb_tuner_ops tea5761_tuner_ops = { - .info = { - .name = "tea5761", // Philips TEA5761HN FM Radio - }, - .set_analog_params = set_radio_freq, - .sleep = set_radio_sleep, - .release = tea5761_release, - .get_frequency = tea5761_get_frequency, - .get_status = tea5761_get_status, - .get_rf_strength = tea5761_get_rf_strength, -}; - -struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr) -{ - struct tea5761_priv *priv = NULL; - - if (tea5761_autodetection(i2c_adap, i2c_addr) != 0) - return NULL; - - priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - fe->tuner_priv = priv; - - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; - priv->i2c_props.name = "tea5761"; - - memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - tuner_info("type set to %s\n", "Philips TEA5761HN FM Radio"); - - return fe; -} - - -EXPORT_SYMBOL_GPL(tea5761_attach); -EXPORT_SYMBOL_GPL(tea5761_autodetection); - -MODULE_DESCRIPTION("Philips TEA5761 FM tuner driver"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/tea5761.h b/drivers/media/common/tuners/tea5761.h deleted file mode 100644 index 2e2ff82c95a4..000000000000 --- a/drivers/media/common/tuners/tea5761.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - 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 __TEA5761_H__ -#define __TEA5761_H__ - -#include -#include "dvb_frontend.h" - -#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE)) -extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); - -extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr); -#else -static inline int tea5761_autodetection(struct i2c_adapter* i2c_adap, - u8 i2c_addr) -{ - printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", - __func__); - return -EINVAL; -} - -static inline struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* __TEA5761_H__ */ diff --git a/drivers/media/common/tuners/tea5767.c b/drivers/media/common/tuners/tea5767.c deleted file mode 100644 index 36e85d81acb2..000000000000 --- a/drivers/media/common/tuners/tea5767.c +++ /dev/null @@ -1,475 +0,0 @@ -/* - * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview - * I2C address is allways 0xC0. - * - * - * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License - * - * tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa - * from their contributions on DScaler. - */ - -#include -#include -#include -#include -#include "tuner-i2c.h" -#include "tea5767.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -/*****************************************************************************/ - -struct tea5767_priv { - struct tuner_i2c_props i2c_props; - u32 frequency; - struct tea5767_ctrl ctrl; -}; - -/*****************************************************************************/ - -/****************************** - * Write mode register values * - ******************************/ - -/* First register */ -#define TEA5767_MUTE 0x80 /* Mutes output */ -#define TEA5767_SEARCH 0x40 /* Activates station search */ -/* Bits 0-5 for divider MSB */ - -/* Second register */ -/* Bits 0-7 for divider LSB */ - -/* Third register */ - -/* Station search from botton to up */ -#define TEA5767_SEARCH_UP 0x80 - -/* Searches with ADC output = 10 */ -#define TEA5767_SRCH_HIGH_LVL 0x60 - -/* Searches with ADC output = 10 */ -#define TEA5767_SRCH_MID_LVL 0x40 - -/* Searches with ADC output = 5 */ -#define TEA5767_SRCH_LOW_LVL 0x20 - -/* if on, div=4*(Frf+Fif)/Fref otherwise, div=4*(Frf-Fif)/Freq) */ -#define TEA5767_HIGH_LO_INJECT 0x10 - -/* Disable stereo */ -#define TEA5767_MONO 0x08 - -/* Disable right channel and turns to mono */ -#define TEA5767_MUTE_RIGHT 0x04 - -/* Disable left channel and turns to mono */ -#define TEA5767_MUTE_LEFT 0x02 - -#define TEA5767_PORT1_HIGH 0x01 - -/* Fourth register */ -#define TEA5767_PORT2_HIGH 0x80 -/* Chips stops working. Only I2C bus remains on */ -#define TEA5767_STDBY 0x40 - -/* Japan freq (76-108 MHz. If disabled, 87.5-108 MHz */ -#define TEA5767_JAPAN_BAND 0x20 - -/* Unselected means 32.768 KHz freq as reference. Otherwise Xtal at 13 MHz */ -#define TEA5767_XTAL_32768 0x10 - -/* Cuts weak signals */ -#define TEA5767_SOFT_MUTE 0x08 - -/* Activates high cut control */ -#define TEA5767_HIGH_CUT_CTRL 0x04 - -/* Activates stereo noise control */ -#define TEA5767_ST_NOISE_CTL 0x02 - -/* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */ -#define TEA5767_SRCH_IND 0x01 - -/* Fifth register */ - -/* By activating, it will use Xtal at 13 MHz as reference for divider */ -#define TEA5767_PLLREF_ENABLE 0x80 - -/* By activating, deemphasis=50, or else, deemphasis of 50us */ -#define TEA5767_DEEMPH_75 0X40 - -/***************************** - * Read mode register values * - *****************************/ - -/* First register */ -#define TEA5767_READY_FLAG_MASK 0x80 -#define TEA5767_BAND_LIMIT_MASK 0X40 -/* Bits 0-5 for divider MSB after search or preset */ - -/* Second register */ -/* Bits 0-7 for divider LSB after search or preset */ - -/* Third register */ -#define TEA5767_STEREO_MASK 0x80 -#define TEA5767_IF_CNTR_MASK 0x7f - -/* Fourth register */ -#define TEA5767_ADC_LEVEL_MASK 0xf0 - -/* should be 0 */ -#define TEA5767_CHIP_ID_MASK 0x0f - -/* Fifth register */ -/* Reserved for future extensions */ -#define TEA5767_RESERVED_MASK 0xff - -/*****************************************************************************/ - -static void tea5767_status_dump(struct tea5767_priv *priv, - unsigned char *buffer) -{ - unsigned int div, frq; - - if (TEA5767_READY_FLAG_MASK & buffer[0]) - tuner_info("Ready Flag ON\n"); - else - tuner_info("Ready Flag OFF\n"); - - if (TEA5767_BAND_LIMIT_MASK & buffer[0]) - tuner_info("Tuner at band limit\n"); - else - tuner_info("Tuner not at band limit\n"); - - div = ((buffer[0] & 0x3f) << 8) | buffer[1]; - - switch (priv->ctrl.xtal_freq) { - case TEA5767_HIGH_LO_13MHz: - frq = (div * 50000 - 700000 - 225000) / 4; /* Freq in KHz */ - break; - case TEA5767_LOW_LO_13MHz: - frq = (div * 50000 + 700000 + 225000) / 4; /* Freq in KHz */ - break; - case TEA5767_LOW_LO_32768: - frq = (div * 32768 + 700000 + 225000) / 4; /* Freq in KHz */ - break; - case TEA5767_HIGH_LO_32768: - default: - frq = (div * 32768 - 700000 - 225000) / 4; /* Freq in KHz */ - break; - } - buffer[0] = (div >> 8) & 0x3f; - buffer[1] = div & 0xff; - - tuner_info("Frequency %d.%03d KHz (divider = 0x%04x)\n", - frq / 1000, frq % 1000, div); - - if (TEA5767_STEREO_MASK & buffer[2]) - tuner_info("Stereo\n"); - else - tuner_info("Mono\n"); - - tuner_info("IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK); - - tuner_info("ADC Level = %d\n", - (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4); - - tuner_info("Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK)); - - tuner_info("Reserved = 0x%02x\n", - (buffer[4] & TEA5767_RESERVED_MASK)); -} - -/* Freq should be specifyed at 62.5 Hz */ -static int set_radio_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tea5767_priv *priv = fe->tuner_priv; - unsigned int frq = params->frequency; - unsigned char buffer[5]; - unsigned div; - int rc; - - tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000); - - buffer[2] = 0; - - if (priv->ctrl.port1) - buffer[2] |= TEA5767_PORT1_HIGH; - - if (params->audmode == V4L2_TUNER_MODE_MONO) { - tuner_dbg("TEA5767 set to mono\n"); - buffer[2] |= TEA5767_MONO; - } else { - tuner_dbg("TEA5767 set to stereo\n"); - } - - - buffer[3] = 0; - - if (priv->ctrl.port2) - buffer[3] |= TEA5767_PORT2_HIGH; - - if (priv->ctrl.high_cut) - buffer[3] |= TEA5767_HIGH_CUT_CTRL; - - if (priv->ctrl.st_noise) - buffer[3] |= TEA5767_ST_NOISE_CTL; - - if (priv->ctrl.soft_mute) - buffer[3] |= TEA5767_SOFT_MUTE; - - if (priv->ctrl.japan_band) - buffer[3] |= TEA5767_JAPAN_BAND; - - buffer[4] = 0; - - if (priv->ctrl.deemph_75) - buffer[4] |= TEA5767_DEEMPH_75; - - if (priv->ctrl.pllref) - buffer[4] |= TEA5767_PLLREF_ENABLE; - - - /* Rounds freq to next decimal value - for 62.5 KHz step */ - /* frq = 20*(frq/16)+radio_frq[frq%16]; */ - - switch (priv->ctrl.xtal_freq) { - case TEA5767_HIGH_LO_13MHz: - tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n"); - buffer[2] |= TEA5767_HIGH_LO_INJECT; - div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000; - break; - case TEA5767_LOW_LO_13MHz: - tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n"); - - div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000; - break; - case TEA5767_LOW_LO_32768: - tuner_dbg("radio LOW LO inject xtal @ 32,768 MHz\n"); - buffer[3] |= TEA5767_XTAL_32768; - /* const 700=4000*175 Khz - to adjust freq to right value */ - div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15; - break; - case TEA5767_HIGH_LO_32768: - default: - tuner_dbg("radio HIGH LO inject xtal @ 32,768 MHz\n"); - - buffer[2] |= TEA5767_HIGH_LO_INJECT; - buffer[3] |= TEA5767_XTAL_32768; - div = ((frq * (4000 / 16) + 700000 + 225000) + 16384) >> 15; - break; - } - buffer[0] = (div >> 8) & 0x3f; - buffer[1] = div & 0xff; - - if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); - - if (debug) { - if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); - else - tea5767_status_dump(priv, buffer); - } - - priv->frequency = frq * 125 / 2; - - return 0; -} - -static int tea5767_read_status(struct dvb_frontend *fe, char *buffer) -{ - struct tea5767_priv *priv = fe->tuner_priv; - int rc; - - memset(buffer, 0, 5); - if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) { - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); - return -EREMOTEIO; - } - - return 0; -} - -static inline int tea5767_signal(struct dvb_frontend *fe, const char *buffer) -{ - struct tea5767_priv *priv = fe->tuner_priv; - - int signal = ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); - - tuner_dbg("Signal strength: %d\n", signal); - - return signal; -} - -static inline int tea5767_stereo(struct dvb_frontend *fe, const char *buffer) -{ - struct tea5767_priv *priv = fe->tuner_priv; - - int stereo = buffer[2] & TEA5767_STEREO_MASK; - - tuner_dbg("Radio ST GET = %02x\n", stereo); - - return (stereo ? V4L2_TUNER_SUB_STEREO : 0); -} - -static int tea5767_get_status(struct dvb_frontend *fe, u32 *status) -{ - unsigned char buffer[5]; - - *status = 0; - - if (0 == tea5767_read_status(fe, buffer)) { - if (tea5767_signal(fe, buffer)) - *status = TUNER_STATUS_LOCKED; - if (tea5767_stereo(fe, buffer)) - *status |= TUNER_STATUS_STEREO; - } - - return 0; -} - -static int tea5767_get_rf_strength(struct dvb_frontend *fe, u16 *strength) -{ - unsigned char buffer[5]; - - *strength = 0; - - if (0 == tea5767_read_status(fe, buffer)) - *strength = tea5767_signal(fe, buffer); - - return 0; -} - -static int tea5767_standby(struct dvb_frontend *fe) -{ - unsigned char buffer[5]; - struct tea5767_priv *priv = fe->tuner_priv; - unsigned div, rc; - - div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */ - buffer[0] = (div >> 8) & 0x3f; - buffer[1] = div & 0xff; - buffer[2] = TEA5767_PORT1_HIGH; - buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | - TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY; - buffer[4] = 0; - - if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); - - return 0; -} - -int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) -{ - struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; - unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - int rc; - - if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) { - printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc); - return -EINVAL; - } - - /* If all bytes are the same then it's a TV tuner and not a tea5767 */ - if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && - buffer[0] == buffer[3] && buffer[0] == buffer[4]) { - printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n"); - return -EINVAL; - } - - /* Status bytes: - * Byte 4: bit 3:1 : CI (Chip Identification) == 0 - * bit 0 : internally set to 0 - * Byte 5: bit 7:0 : == 0 - */ - if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) { - printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n"); - return -EINVAL; - } - - - return 0; -} - -static int tea5767_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - - return 0; -} - -static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tea5767_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - - return 0; -} - -static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg) -{ - struct tea5767_priv *priv = fe->tuner_priv; - - memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl)); - - return 0; -} - -static struct dvb_tuner_ops tea5767_tuner_ops = { - .info = { - .name = "tea5767", // Philips TEA5767HN FM Radio - }, - - .set_analog_params = set_radio_freq, - .set_config = tea5767_set_config, - .sleep = tea5767_standby, - .release = tea5767_release, - .get_frequency = tea5767_get_frequency, - .get_status = tea5767_get_status, - .get_rf_strength = tea5767_get_rf_strength, -}; - -struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr) -{ - struct tea5767_priv *priv = NULL; - - priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - fe->tuner_priv = priv; - - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; - priv->i2c_props.name = "tea5767"; - - priv->ctrl.xtal_freq = TEA5767_HIGH_LO_32768; - priv->ctrl.port1 = 1; - priv->ctrl.port2 = 1; - priv->ctrl.high_cut = 1; - priv->ctrl.st_noise = 1; - priv->ctrl.japan_band = 1; - - memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - tuner_info("type set to %s\n", "Philips TEA5767HN FM Radio"); - - return fe; -} - -EXPORT_SYMBOL_GPL(tea5767_attach); -EXPORT_SYMBOL_GPL(tea5767_autodetection); - -MODULE_DESCRIPTION("Philips TEA5767 FM tuner driver"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/tea5767.h b/drivers/media/common/tuners/tea5767.h deleted file mode 100644 index d30ab1b483de..000000000000 --- a/drivers/media/common/tuners/tea5767.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - 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 __TEA5767_H__ -#define __TEA5767_H__ - -#include -#include "dvb_frontend.h" - -enum tea5767_xtal { - TEA5767_LOW_LO_32768 = 0, - TEA5767_HIGH_LO_32768 = 1, - TEA5767_LOW_LO_13MHz = 2, - TEA5767_HIGH_LO_13MHz = 3, -}; - -struct tea5767_ctrl { - unsigned int port1:1; - unsigned int port2:1; - unsigned int high_cut:1; - unsigned int st_noise:1; - unsigned int soft_mute:1; - unsigned int japan_band:1; - unsigned int deemph_75:1; - unsigned int pllref:1; - enum tea5767_xtal xtal_freq; -}; - -#if defined(CONFIG_MEDIA_TUNER_TEA5767) || (defined(CONFIG_MEDIA_TUNER_TEA5767_MODULE) && defined(MODULE)) -extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); - -extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr); -#else -static inline int tea5767_autodetection(struct i2c_adapter* i2c_adap, - u8 i2c_addr) -{ - printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", - __func__); - return -EINVAL; -} - -static inline struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* __TEA5767_H__ */ diff --git a/drivers/media/common/tuners/tua9001.c b/drivers/media/common/tuners/tua9001.c deleted file mode 100644 index de2607084672..000000000000 --- a/drivers/media/common/tuners/tua9001.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Infineon TUA 9001 silicon tuner 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "tua9001.h" -#include "tua9001_priv.h" - -/* write register */ -static int tua9001_wr_reg(struct tua9001_priv *priv, u8 reg, u16 val) -{ - int ret; - u8 buf[3] = { reg, (val >> 8) & 0xff, (val >> 0) & 0xff }; - struct i2c_msg msg[1] = { - { - .addr = priv->cfg->i2c_addr, - .flags = 0, - .len = sizeof(buf), - .buf = buf, - } - }; - - ret = i2c_transfer(priv->i2c, msg, 1); - if (ret == 1) { - ret = 0; - } else { - printk(KERN_WARNING "%s: I2C wr failed=%d reg=%02x\n", - __func__, ret, reg); - ret = -EREMOTEIO; - } - - return ret; -} - -static int tua9001_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - - return 0; -} - -static int tua9001_init(struct dvb_frontend *fe) -{ - struct tua9001_priv *priv = fe->tuner_priv; - int ret = 0; - u8 i; - struct reg_val data[] = { - { 0x1e, 0x6512 }, - { 0x25, 0xb888 }, - { 0x39, 0x5460 }, - { 0x3b, 0x00c0 }, - { 0x3a, 0xf000 }, - { 0x08, 0x0000 }, - { 0x32, 0x0030 }, - { 0x41, 0x703a }, - { 0x40, 0x1c78 }, - { 0x2c, 0x1c00 }, - { 0x36, 0xc013 }, - { 0x37, 0x6f18 }, - { 0x27, 0x0008 }, - { 0x2a, 0x0001 }, - { 0x34, 0x0a40 }, - }; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */ - - for (i = 0; i < ARRAY_SIZE(data); i++) { - ret = tua9001_wr_reg(priv, data[i].reg, data[i].val); - if (ret) - break; - } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */ - - if (ret < 0) - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int tua9001_set_params(struct dvb_frontend *fe) -{ - struct tua9001_priv *priv = fe->tuner_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret, i; - u16 val; - u32 frequency; - struct reg_val data[2]; - - pr_debug("%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", - __func__, c->delivery_system, c->frequency, - c->bandwidth_hz); - - switch (c->delivery_system) { - case SYS_DVBT: - switch (c->bandwidth_hz) { - case 8000000: - val = 0x0000; - break; - case 7000000: - val = 0x1000; - break; - case 6000000: - val = 0x2000; - break; - case 5000000: - val = 0x3000; - break; - default: - ret = -EINVAL; - goto err; - } - break; - default: - ret = -EINVAL; - goto err; - } - - data[0].reg = 0x04; - data[0].val = val; - - frequency = (c->frequency - 150000000); - frequency /= 100; - frequency *= 48; - frequency /= 10000; - - data[1].reg = 0x1f; - data[1].val = frequency; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */ - - for (i = 0; i < ARRAY_SIZE(data); i++) { - ret = tua9001_wr_reg(priv, data[i].reg, data[i].val); - if (ret < 0) - break; - } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */ - -err: - if (ret < 0) - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - *frequency = 0; /* Zero-IF */ - - return 0; -} - -static const struct dvb_tuner_ops tua9001_tuner_ops = { - .info = { - .name = "Infineon TUA 9001", - - .frequency_min = 170000000, - .frequency_max = 862000000, - .frequency_step = 0, - }, - - .release = tua9001_release, - - .init = tua9001_init, - .set_params = tua9001_set_params, - - .get_if_frequency = tua9001_get_if_frequency, -}; - -struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tua9001_config *cfg) -{ - struct tua9001_priv *priv = NULL; - - priv = kzalloc(sizeof(struct tua9001_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->cfg = cfg; - priv->i2c = i2c; - - printk(KERN_INFO "Infineon TUA 9001 successfully attached."); - - memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = priv; - return fe; -} -EXPORT_SYMBOL(tua9001_attach); - -MODULE_DESCRIPTION("Infineon TUA 9001 silicon tuner driver"); -MODULE_AUTHOR("Antti Palosaari "); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/tua9001.h b/drivers/media/common/tuners/tua9001.h deleted file mode 100644 index 38d6ae76b1d6..000000000000 --- a/drivers/media/common/tuners/tua9001.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Infineon TUA 9001 silicon tuner 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef TUA9001_H -#define TUA9001_H - -#include "dvb_frontend.h" - -struct tua9001_config { - /* - * I2C address - */ - u8 i2c_addr; -}; - -#if defined(CONFIG_MEDIA_TUNER_TUA9001) || \ - (defined(CONFIG_MEDIA_TUNER_TUA9001_MODULE) && defined(MODULE)) -extern struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tua9001_config *cfg); -#else -static inline struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tua9001_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff --git a/drivers/media/common/tuners/tua9001_priv.h b/drivers/media/common/tuners/tua9001_priv.h deleted file mode 100644 index 73cc1ce0575c..000000000000 --- a/drivers/media/common/tuners/tua9001_priv.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Infineon TUA 9001 silicon tuner 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef TUA9001_PRIV_H -#define TUA9001_PRIV_H - -struct reg_val { - u8 reg; - u16 val; -}; - -struct tua9001_priv { - struct tua9001_config *cfg; - struct i2c_adapter *i2c; -}; - -#endif diff --git a/drivers/media/common/tuners/tuner-i2c.h b/drivers/media/common/tuners/tuner-i2c.h deleted file mode 100644 index 18f005634c67..000000000000 --- a/drivers/media/common/tuners/tuner-i2c.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - tuner-i2c.h - i2c interface for different tuners - - Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) - - 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 __TUNER_I2C_H__ -#define __TUNER_I2C_H__ - -#include -#include - -struct tuner_i2c_props { - u8 addr; - struct i2c_adapter *adap; - - /* used for tuner instance management */ - int count; - char *name; -}; - -static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len) -{ - struct i2c_msg msg = { .addr = props->addr, .flags = 0, - .buf = buf, .len = len }; - int ret = i2c_transfer(props->adap, &msg, 1); - - return (ret == 1) ? len : ret; -} - -static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, int len) -{ - struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD, - .buf = buf, .len = len }; - int ret = i2c_transfer(props->adap, &msg, 1); - - return (ret == 1) ? len : ret; -} - -static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props, - char *obuf, int olen, - char *ibuf, int ilen) -{ - struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0, - .buf = obuf, .len = olen }, - { .addr = props->addr, .flags = I2C_M_RD, - .buf = ibuf, .len = ilen } }; - int ret = i2c_transfer(props->adap, msg, 2); - - return (ret == 2) ? ilen : ret; -} - -/* Callers must declare as a global for the module: - * - * static LIST_HEAD(hybrid_tuner_instance_list); - * - * hybrid_tuner_instance_list should be the third argument - * passed into hybrid_tuner_request_state(). - * - * state structure must contain the following: - * - * struct list_head hybrid_tuner_instance_list; - * struct tuner_i2c_props i2c_props; - * - * hybrid_tuner_instance_list (both within state structure and globally) - * is only required if the driver is using hybrid_tuner_request_state - * and hybrid_tuner_release_state to manage state sharing between - * multiple instances of hybrid tuners. - */ - -#define tuner_printk(kernlvl, i2cprops, fmt, arg...) do { \ - printk(kernlvl "%s %d-%04x: " fmt, i2cprops.name, \ - i2cprops.adap ? \ - i2c_adapter_id(i2cprops.adap) : -1, \ - i2cprops.addr, ##arg); \ - } while (0) - -/* TO DO: convert all callers of these macros to pass in - * struct tuner_i2c_props, then remove the macro wrappers */ - -#define __tuner_warn(i2cprops, fmt, arg...) do { \ - tuner_printk(KERN_WARNING, i2cprops, fmt, ##arg); \ - } while (0) - -#define __tuner_info(i2cprops, fmt, arg...) do { \ - tuner_printk(KERN_INFO, i2cprops, fmt, ##arg); \ - } while (0) - -#define __tuner_err(i2cprops, fmt, arg...) do { \ - tuner_printk(KERN_ERR, i2cprops, fmt, ##arg); \ - } while (0) - -#define __tuner_dbg(i2cprops, fmt, arg...) do { \ - if ((debug)) \ - tuner_printk(KERN_DEBUG, i2cprops, fmt, ##arg); \ - } while (0) - -#define tuner_warn(fmt, arg...) __tuner_warn(priv->i2c_props, fmt, ##arg) -#define tuner_info(fmt, arg...) __tuner_info(priv->i2c_props, fmt, ##arg) -#define tuner_err(fmt, arg...) __tuner_err(priv->i2c_props, fmt, ##arg) -#define tuner_dbg(fmt, arg...) __tuner_dbg(priv->i2c_props, fmt, ##arg) - -/****************************************************************************/ - -/* The return value of hybrid_tuner_request_state indicates the number of - * instances using this tuner object. - * - * 0 - no instances, indicates an error - kzalloc must have failed - * - * 1 - one instance, indicates that the tuner object was created successfully - * - * 2 (or more) instances, indicates that an existing tuner object was found - */ - -#define hybrid_tuner_request_state(type, state, list, i2cadap, i2caddr, devname)\ -({ \ - int __ret = 0; \ - list_for_each_entry(state, &list, hybrid_tuner_instance_list) { \ - if (((i2cadap) && (state->i2c_props.adap)) && \ - ((i2c_adapter_id(state->i2c_props.adap) == \ - i2c_adapter_id(i2cadap)) && \ - (i2caddr == state->i2c_props.addr))) { \ - __tuner_info(state->i2c_props, \ - "attaching existing instance\n"); \ - state->i2c_props.count++; \ - __ret = state->i2c_props.count; \ - break; \ - } \ - } \ - if (0 == __ret) { \ - state = kzalloc(sizeof(type), GFP_KERNEL); \ - if (NULL == state) \ - goto __fail; \ - state->i2c_props.addr = i2caddr; \ - state->i2c_props.adap = i2cadap; \ - state->i2c_props.name = devname; \ - __tuner_info(state->i2c_props, \ - "creating new instance\n"); \ - list_add_tail(&state->hybrid_tuner_instance_list, &list);\ - state->i2c_props.count++; \ - __ret = state->i2c_props.count; \ - } \ -__fail: \ - __ret; \ -}) - -#define hybrid_tuner_release_state(state) \ -({ \ - int __ret; \ - state->i2c_props.count--; \ - __ret = state->i2c_props.count; \ - if (!state->i2c_props.count) { \ - __tuner_info(state->i2c_props, "destroying instance\n");\ - list_del(&state->hybrid_tuner_instance_list); \ - kfree(state); \ - } \ - __ret; \ -}) - -#define hybrid_tuner_report_instance_count(state) \ -({ \ - int __ret = 0; \ - if (state) \ - __ret = state->i2c_props.count; \ - __ret; \ -}) - -#endif /* __TUNER_I2C_H__ */ diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c deleted file mode 100644 index 39e7e583c8c0..000000000000 --- a/drivers/media/common/tuners/tuner-simple.c +++ /dev/null @@ -1,1155 +0,0 @@ -/* - * i2c tv tuner chip device driver - * controls all those simple 4-control-bytes style tuners. - * - * This "tuner-simple" module was split apart from the original "tuner" module. - */ -#include -#include -#include -#include -#include -#include -#include "tuner-i2c.h" -#include "tuner-simple.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -#define TUNER_SIMPLE_MAX 64 -static unsigned int simple_devcount; - -static int offset; -module_param(offset, int, 0664); -MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner"); - -static unsigned int atv_input[TUNER_SIMPLE_MAX] = \ - { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 }; -static unsigned int dtv_input[TUNER_SIMPLE_MAX] = \ - { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 }; -module_param_array(atv_input, int, NULL, 0644); -module_param_array(dtv_input, int, NULL, 0644); -MODULE_PARM_DESC(atv_input, "specify atv rf input, 0 for autoselect"); -MODULE_PARM_DESC(dtv_input, "specify dtv rf input, 0 for autoselect"); - -/* ---------------------------------------------------------------------- */ - -/* tv standard selection for Temic 4046 FM5 - this value takes the low bits of control byte 2 - from datasheet Rev.01, Feb.00 - standard BG I L L2 D - picture IF 38.9 38.9 38.9 33.95 38.9 - sound 1 33.4 32.9 32.4 40.45 32.4 - sound 2 33.16 - NICAM 33.05 32.348 33.05 33.05 - */ -#define TEMIC_SET_PAL_I 0x05 -#define TEMIC_SET_PAL_DK 0x09 -#define TEMIC_SET_PAL_L 0x0a /* SECAM ? */ -#define TEMIC_SET_PAL_L2 0x0b /* change IF ! */ -#define TEMIC_SET_PAL_BG 0x0c - -/* tv tuner system standard selection for Philips FQ1216ME - this value takes the low bits of control byte 2 - from datasheet "1999 Nov 16" (supersedes "1999 Mar 23") - standard BG DK I L L` - picture carrier 38.90 38.90 38.90 38.90 33.95 - colour 34.47 34.47 34.47 34.47 38.38 - sound 1 33.40 32.40 32.90 32.40 40.45 - sound 2 33.16 - - - - - NICAM 33.05 33.05 32.35 33.05 39.80 - */ -#define PHILIPS_SET_PAL_I 0x01 /* Bit 2 always zero !*/ -#define PHILIPS_SET_PAL_BGDK 0x09 -#define PHILIPS_SET_PAL_L2 0x0a -#define PHILIPS_SET_PAL_L 0x0b - -/* system switching for Philips FI1216MF MK2 - from datasheet "1996 Jul 09", - standard BG L L' - picture carrier 38.90 38.90 33.95 - colour 34.47 34.37 38.38 - sound 1 33.40 32.40 40.45 - sound 2 33.16 - - - NICAM 33.05 33.05 39.80 - */ -#define PHILIPS_MF_SET_STD_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */ -#define PHILIPS_MF_SET_STD_L 0x03 /* Used on Secam France */ -#define PHILIPS_MF_SET_STD_LC 0x02 /* Used on SECAM L' */ - -/* Control byte */ - -#define TUNER_RATIO_MASK 0x06 /* Bit cb1:cb2 */ -#define TUNER_RATIO_SELECT_50 0x00 -#define TUNER_RATIO_SELECT_32 0x02 -#define TUNER_RATIO_SELECT_166 0x04 -#define TUNER_RATIO_SELECT_62 0x06 - -#define TUNER_CHARGE_PUMP 0x40 /* Bit cb6 */ - -/* Status byte */ - -#define TUNER_POR 0x80 -#define TUNER_FL 0x40 -#define TUNER_MODE 0x38 -#define TUNER_AFC 0x07 -#define TUNER_SIGNAL 0x07 -#define TUNER_STEREO 0x10 - -#define TUNER_PLL_LOCKED 0x40 -#define TUNER_STEREO_MK3 0x04 - -static DEFINE_MUTEX(tuner_simple_list_mutex); -static LIST_HEAD(hybrid_tuner_instance_list); - -struct tuner_simple_priv { - unsigned int nr; - u16 last_div; - - struct tuner_i2c_props i2c_props; - struct list_head hybrid_tuner_instance_list; - - unsigned int type; - struct tunertype *tun; - - u32 frequency; - u32 bandwidth; -}; - -/* ---------------------------------------------------------------------- */ - -static int tuner_read_status(struct dvb_frontend *fe) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - unsigned char byte; - - if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1)) - return 0; - - return byte; -} - -static inline int tuner_signal(const int status) -{ - return (status & TUNER_SIGNAL) << 13; -} - -static inline int tuner_stereo(const int type, const int status) -{ - switch (type) { - case TUNER_PHILIPS_FM1216ME_MK3: - case TUNER_PHILIPS_FM1236_MK3: - case TUNER_PHILIPS_FM1256_IH3: - case TUNER_LG_NTSC_TAPE: - case TUNER_TCL_MF02GIP_5N: - return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3); - case TUNER_PHILIPS_FM1216MK5: - return status | TUNER_STEREO; - default: - return status & TUNER_STEREO; - } -} - -static inline int tuner_islocked(const int status) -{ - return (status & TUNER_FL); -} - -static inline int tuner_afcstatus(const int status) -{ - return (status & TUNER_AFC) - 2; -} - - -static int simple_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - int tuner_status; - - if (priv->i2c_props.adap == NULL) - return -EINVAL; - - tuner_status = tuner_read_status(fe); - - *status = 0; - - if (tuner_islocked(tuner_status)) - *status = TUNER_STATUS_LOCKED; - if (tuner_stereo(priv->type, tuner_status)) - *status |= TUNER_STATUS_STEREO; - - tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status)); - - return 0; -} - -static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - int signal; - - if (priv->i2c_props.adap == NULL) - return -EINVAL; - - signal = tuner_signal(tuner_read_status(fe)); - - *strength = signal; - - tuner_dbg("Signal strength: %d\n", signal); - - return 0; -} - -/* ---------------------------------------------------------------------- */ - -static inline char *tuner_param_name(enum param_type type) -{ - char *name; - - switch (type) { - case TUNER_PARAM_TYPE_RADIO: - name = "radio"; - break; - case TUNER_PARAM_TYPE_PAL: - name = "pal"; - break; - case TUNER_PARAM_TYPE_SECAM: - name = "secam"; - break; - case TUNER_PARAM_TYPE_NTSC: - name = "ntsc"; - break; - case TUNER_PARAM_TYPE_DIGITAL: - name = "digital"; - break; - default: - name = "unknown"; - break; - } - return name; -} - -static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe, - enum param_type desired_type) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - struct tunertype *tun = priv->tun; - int i; - - for (i = 0; i < tun->count; i++) - if (desired_type == tun->params[i].type) - break; - - /* use default tuner params if desired_type not available */ - if (i == tun->count) { - tuner_dbg("desired params (%s) undefined for tuner %d\n", - tuner_param_name(desired_type), priv->type); - i = 0; - } - - tuner_dbg("using tuner params #%d (%s)\n", i, - tuner_param_name(tun->params[i].type)); - - return &tun->params[i]; -} - -static int simple_config_lookup(struct dvb_frontend *fe, - struct tuner_params *t_params, - unsigned *frequency, u8 *config, u8 *cb) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - int i; - - for (i = 0; i < t_params->count; i++) { - if (*frequency > t_params->ranges[i].limit) - continue; - break; - } - if (i == t_params->count) { - tuner_dbg("frequency out of range (%d > %d)\n", - *frequency, t_params->ranges[i - 1].limit); - *frequency = t_params->ranges[--i].limit; - } - *config = t_params->ranges[i].config; - *cb = t_params->ranges[i].cb; - - tuner_dbg("freq = %d.%02d (%d), range = %d, " - "config = 0x%02x, cb = 0x%02x\n", - *frequency / 16, *frequency % 16 * 100 / 16, *frequency, - i, *config, *cb); - - return i; -} - -/* ---------------------------------------------------------------------- */ - -static void simple_set_rf_input(struct dvb_frontend *fe, - u8 *config, u8 *cb, unsigned int rf) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - - switch (priv->type) { - case TUNER_PHILIPS_TUV1236D: - switch (rf) { - case 1: - *cb |= 0x08; - break; - default: - *cb &= ~0x08; - break; - } - break; - case TUNER_PHILIPS_FCV1236D: - switch (rf) { - case 1: - *cb |= 0x01; - break; - default: - *cb &= ~0x01; - break; - } - break; - default: - break; - } -} - -static int simple_std_setup(struct dvb_frontend *fe, - struct analog_parameters *params, - u8 *config, u8 *cb) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - int rc; - - /* tv norm specific stuff for multi-norm tuners */ - switch (priv->type) { - case TUNER_PHILIPS_SECAM: /* FI1216MF */ - /* 0x01 -> ??? no change ??? */ - /* 0x02 -> PAL BDGHI / SECAM L */ - /* 0x04 -> ??? PAL others / SECAM others ??? */ - *cb &= ~0x03; - if (params->std & V4L2_STD_SECAM_L) - /* also valid for V4L2_STD_SECAM */ - *cb |= PHILIPS_MF_SET_STD_L; - else if (params->std & V4L2_STD_SECAM_LC) - *cb |= PHILIPS_MF_SET_STD_LC; - else /* V4L2_STD_B|V4L2_STD_GH */ - *cb |= PHILIPS_MF_SET_STD_BG; - break; - - case TUNER_TEMIC_4046FM5: - *cb &= ~0x0f; - - if (params->std & V4L2_STD_PAL_BG) { - *cb |= TEMIC_SET_PAL_BG; - - } else if (params->std & V4L2_STD_PAL_I) { - *cb |= TEMIC_SET_PAL_I; - - } else if (params->std & V4L2_STD_PAL_DK) { - *cb |= TEMIC_SET_PAL_DK; - - } else if (params->std & V4L2_STD_SECAM_L) { - *cb |= TEMIC_SET_PAL_L; - - } - break; - - case TUNER_PHILIPS_FQ1216ME: - *cb &= ~0x0f; - - if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { - *cb |= PHILIPS_SET_PAL_BGDK; - - } else if (params->std & V4L2_STD_PAL_I) { - *cb |= PHILIPS_SET_PAL_I; - - } else if (params->std & V4L2_STD_SECAM_L) { - *cb |= PHILIPS_SET_PAL_L; - - } - break; - - case TUNER_PHILIPS_FCV1236D: - /* 0x00 -> ATSC antenna input 1 */ - /* 0x01 -> ATSC antenna input 2 */ - /* 0x02 -> NTSC antenna input 1 */ - /* 0x03 -> NTSC antenna input 2 */ - *cb &= ~0x03; - if (!(params->std & V4L2_STD_ATSC)) - *cb |= 2; - break; - - case TUNER_MICROTUNE_4042FI5: - /* Set the charge pump for fast tuning */ - *config |= TUNER_CHARGE_PUMP; - break; - - case TUNER_PHILIPS_TUV1236D: - { - struct tuner_i2c_props i2c = priv->i2c_props; - /* 0x40 -> ATSC antenna input 1 */ - /* 0x48 -> ATSC antenna input 2 */ - /* 0x00 -> NTSC antenna input 1 */ - /* 0x08 -> NTSC antenna input 2 */ - u8 buffer[4] = { 0x14, 0x00, 0x17, 0x00}; - *cb &= ~0x40; - if (params->std & V4L2_STD_ATSC) { - *cb |= 0x40; - buffer[1] = 0x04; - } - /* set to the correct mode (analog or digital) */ - i2c.addr = 0x0a; - rc = tuner_i2c_xfer_send(&i2c, &buffer[0], 2); - if (2 != rc) - tuner_warn("i2c i/o error: rc == %d " - "(should be 2)\n", rc); - rc = tuner_i2c_xfer_send(&i2c, &buffer[2], 2); - if (2 != rc) - tuner_warn("i2c i/o error: rc == %d " - "(should be 2)\n", rc); - break; - } - } - if (atv_input[priv->nr]) - simple_set_rf_input(fe, config, cb, atv_input[priv->nr]); - - return 0; -} - -static int simple_set_aux_byte(struct dvb_frontend *fe, u8 config, u8 aux) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - int rc; - u8 buffer[2]; - - buffer[0] = (config & ~0x38) | 0x18; - buffer[1] = aux; - - tuner_dbg("setting aux byte: 0x%02x 0x%02x\n", buffer[0], buffer[1]); - - rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2); - if (2 != rc) - tuner_warn("i2c i/o error: rc == %d (should be 2)\n", rc); - - return rc == 2 ? 0 : rc; -} - -static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer, - u16 div, u8 config, u8 cb) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - int rc; - - switch (priv->type) { - case TUNER_LG_TDVS_H06XF: - simple_set_aux_byte(fe, config, 0x20); - break; - case TUNER_PHILIPS_FQ1216LME_MK3: - simple_set_aux_byte(fe, config, 0x60); /* External AGC */ - break; - case TUNER_MICROTUNE_4042FI5: - { - /* FIXME - this may also work for other tuners */ - unsigned long timeout = jiffies + msecs_to_jiffies(1); - u8 status_byte = 0; - - /* Wait until the PLL locks */ - for (;;) { - if (time_after(jiffies, timeout)) - return 0; - rc = tuner_i2c_xfer_recv(&priv->i2c_props, - &status_byte, 1); - if (1 != rc) { - tuner_warn("i2c i/o read error: rc == %d " - "(should be 1)\n", rc); - break; - } - if (status_byte & TUNER_PLL_LOCKED) - break; - udelay(10); - } - - /* Set the charge pump for optimized phase noise figure */ - config &= ~TUNER_CHARGE_PUMP; - buffer[0] = (div>>8) & 0x7f; - buffer[1] = div & 0xff; - buffer[2] = config; - buffer[3] = cb; - tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", - buffer[0], buffer[1], buffer[2], buffer[3]); - - rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); - if (4 != rc) - tuner_warn("i2c i/o error: rc == %d " - "(should be 4)\n", rc); - break; - } - } - - return 0; -} - -static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - - switch (priv->type) { - case TUNER_TENA_9533_DI: - case TUNER_YMEC_TVF_5533MF: - tuner_dbg("This tuner doesn't have FM. " - "Most cards have a TEA5767 for FM\n"); - return 0; - case TUNER_PHILIPS_FM1216ME_MK3: - case TUNER_PHILIPS_FM1236_MK3: - case TUNER_PHILIPS_FMD1216ME_MK3: - case TUNER_PHILIPS_FMD1216MEX_MK3: - case TUNER_LG_NTSC_TAPE: - case TUNER_PHILIPS_FM1256_IH3: - case TUNER_TCL_MF02GIP_5N: - buffer[3] = 0x19; - break; - case TUNER_PHILIPS_FM1216MK5: - buffer[2] = 0x88; - buffer[3] = 0x09; - break; - case TUNER_TNF_5335MF: - buffer[3] = 0x11; - break; - case TUNER_LG_PAL_FM: - buffer[3] = 0xa5; - break; - case TUNER_THOMSON_DTT761X: - buffer[3] = 0x39; - break; - case TUNER_PHILIPS_FQ1216LME_MK3: - case TUNER_PHILIPS_FQ1236_MK5: - tuner_err("This tuner doesn't have FM\n"); - /* Set the low band for sanity, since it covers 88-108 MHz */ - buffer[3] = 0x01; - break; - case TUNER_MICROTUNE_4049FM5: - default: - buffer[3] = 0xa4; - break; - } - - return 0; -} - -/* ---------------------------------------------------------------------- */ - -static int simple_set_tv_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - u8 config, cb; - u16 div; - u8 buffer[4]; - int rc, IFPCoff, i; - enum param_type desired_type; - struct tuner_params *t_params; - - /* IFPCoff = Video Intermediate Frequency - Vif: - 940 =16*58.75 NTSC/J (Japan) - 732 =16*45.75 M/N STD - 704 =16*44 ATSC (at DVB code) - 632 =16*39.50 I U.K. - 622.4=16*38.90 B/G D/K I, L STD - 592 =16*37.00 D China - 590 =16.36.875 B Australia - 543.2=16*33.95 L' STD - 171.2=16*10.70 FM Radio (at set_radio_freq) - */ - - if (params->std == V4L2_STD_NTSC_M_JP) { - IFPCoff = 940; - desired_type = TUNER_PARAM_TYPE_NTSC; - } else if ((params->std & V4L2_STD_MN) && - !(params->std & ~V4L2_STD_MN)) { - IFPCoff = 732; - desired_type = TUNER_PARAM_TYPE_NTSC; - } else if (params->std == V4L2_STD_SECAM_LC) { - IFPCoff = 543; - desired_type = TUNER_PARAM_TYPE_SECAM; - } else { - IFPCoff = 623; - desired_type = TUNER_PARAM_TYPE_PAL; - } - - t_params = simple_tuner_params(fe, desired_type); - - i = simple_config_lookup(fe, t_params, ¶ms->frequency, - &config, &cb); - - div = params->frequency + IFPCoff + offset; - - tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, " - "Offset=%d.%02d MHz, div=%0d\n", - params->frequency / 16, params->frequency % 16 * 100 / 16, - IFPCoff / 16, IFPCoff % 16 * 100 / 16, - offset / 16, offset % 16 * 100 / 16, div); - - /* tv norm specific stuff for multi-norm tuners */ - simple_std_setup(fe, params, &config, &cb); - - if (t_params->cb_first_if_lower_freq && div < priv->last_div) { - buffer[0] = config; - buffer[1] = cb; - buffer[2] = (div>>8) & 0x7f; - buffer[3] = div & 0xff; - } else { - buffer[0] = (div>>8) & 0x7f; - buffer[1] = div & 0xff; - buffer[2] = config; - buffer[3] = cb; - } - priv->last_div = div; - if (t_params->has_tda9887) { - struct v4l2_priv_tun_config tda9887_cfg; - int tda_config = 0; - int is_secam_l = (params->std & (V4L2_STD_SECAM_L | - V4L2_STD_SECAM_LC)) && - !(params->std & ~(V4L2_STD_SECAM_L | - V4L2_STD_SECAM_LC)); - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &tda_config; - - if (params->std == V4L2_STD_SECAM_LC) { - if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc) - tda_config |= TDA9887_PORT1_ACTIVE; - if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc) - tda_config |= TDA9887_PORT2_ACTIVE; - } else { - if (t_params->port1_active) - tda_config |= TDA9887_PORT1_ACTIVE; - if (t_params->port2_active) - tda_config |= TDA9887_PORT2_ACTIVE; - } - if (t_params->intercarrier_mode) - tda_config |= TDA9887_INTERCARRIER; - if (is_secam_l) { - if (i == 0 && t_params->default_top_secam_low) - tda_config |= TDA9887_TOP(t_params->default_top_secam_low); - else if (i == 1 && t_params->default_top_secam_mid) - tda_config |= TDA9887_TOP(t_params->default_top_secam_mid); - else if (t_params->default_top_secam_high) - tda_config |= TDA9887_TOP(t_params->default_top_secam_high); - } else { - if (i == 0 && t_params->default_top_low) - tda_config |= TDA9887_TOP(t_params->default_top_low); - else if (i == 1 && t_params->default_top_mid) - tda_config |= TDA9887_TOP(t_params->default_top_mid); - else if (t_params->default_top_high) - tda_config |= TDA9887_TOP(t_params->default_top_high); - } - if (t_params->default_pll_gating_18) - tda_config |= TDA9887_GATING_18; - i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, - &tda9887_cfg); - } - tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", - buffer[0], buffer[1], buffer[2], buffer[3]); - - rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); - if (4 != rc) - tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); - - simple_post_tune(fe, &buffer[0], div, config, cb); - - return 0; -} - -static int simple_set_radio_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tunertype *tun; - struct tuner_simple_priv *priv = fe->tuner_priv; - u8 buffer[4]; - u16 div; - int rc, j; - struct tuner_params *t_params; - unsigned int freq = params->frequency; - - tun = priv->tun; - - for (j = tun->count-1; j > 0; j--) - if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO) - break; - /* default t_params (j=0) will be used if desired type wasn't found */ - t_params = &tun->params[j]; - - /* Select Radio 1st IF used */ - switch (t_params->radio_if) { - case 0: /* 10.7 MHz */ - freq += (unsigned int)(10.7*16000); - break; - case 1: /* 33.3 MHz */ - freq += (unsigned int)(33.3*16000); - break; - case 2: /* 41.3 MHz */ - freq += (unsigned int)(41.3*16000); - break; - default: - tuner_warn("Unsupported radio_if value %d\n", - t_params->radio_if); - return 0; - } - - buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) | - TUNER_RATIO_SELECT_50; /* 50 kHz step */ - - /* Bandswitch byte */ - simple_radio_bandswitch(fe, &buffer[0]); - - /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps - freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) = - freq * (1/800) */ - div = (freq + 400) / 800; - - if (t_params->cb_first_if_lower_freq && div < priv->last_div) { - buffer[0] = buffer[2]; - buffer[1] = buffer[3]; - buffer[2] = (div>>8) & 0x7f; - buffer[3] = div & 0xff; - } else { - buffer[0] = (div>>8) & 0x7f; - buffer[1] = div & 0xff; - } - - tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n", - buffer[0], buffer[1], buffer[2], buffer[3]); - priv->last_div = div; - - if (t_params->has_tda9887) { - int config = 0; - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &config; - - if (t_params->port1_active && - !t_params->port1_fm_high_sensitivity) - config |= TDA9887_PORT1_ACTIVE; - if (t_params->port2_active && - !t_params->port2_fm_high_sensitivity) - config |= TDA9887_PORT2_ACTIVE; - if (t_params->intercarrier_mode) - config |= TDA9887_INTERCARRIER; -/* if (t_params->port1_set_for_fm_mono) - config &= ~TDA9887_PORT1_ACTIVE;*/ - if (t_params->fm_gain_normal) - config |= TDA9887_GAIN_NORMAL; - if (t_params->radio_if == 2) - config |= TDA9887_RIF_41_3; - i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, - &tda9887_cfg); - } - rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); - if (4 != rc) - tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); - - /* Write AUX byte */ - switch (priv->type) { - case TUNER_PHILIPS_FM1216ME_MK3: - buffer[2] = 0x98; - buffer[3] = 0x20; /* set TOP AGC */ - rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); - if (4 != rc) - tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); - break; - } - - return 0; -} - -static int simple_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - int ret = -EINVAL; - - if (priv->i2c_props.adap == NULL) - return -EINVAL; - - switch (params->mode) { - case V4L2_TUNER_RADIO: - ret = simple_set_radio_freq(fe, params); - priv->frequency = params->frequency * 125 / 2; - break; - case V4L2_TUNER_ANALOG_TV: - case V4L2_TUNER_DIGITAL_TV: - ret = simple_set_tv_freq(fe, params); - priv->frequency = params->frequency * 62500; - break; - } - priv->bandwidth = 0; - - return ret; -} - -static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf, - const u32 delsys, - const u32 frequency, - const u32 bandwidth) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - - switch (priv->type) { - case TUNER_PHILIPS_FMD1216ME_MK3: - case TUNER_PHILIPS_FMD1216MEX_MK3: - if (bandwidth == 8000000 && - frequency >= 158870000) - buf[3] |= 0x08; - break; - case TUNER_PHILIPS_TD1316: - /* determine band */ - buf[3] |= (frequency < 161000000) ? 1 : - (frequency < 444000000) ? 2 : 4; - - /* setup PLL filter */ - if (bandwidth == 8000000) - buf[3] |= 1 << 3; - break; - case TUNER_PHILIPS_TUV1236D: - case TUNER_PHILIPS_FCV1236D: - { - unsigned int new_rf; - - if (dtv_input[priv->nr]) - new_rf = dtv_input[priv->nr]; - else - switch (delsys) { - case SYS_DVBC_ANNEX_B: - new_rf = 1; - break; - case SYS_ATSC: - default: - new_rf = 0; - break; - } - simple_set_rf_input(fe, &buf[2], &buf[3], new_rf); - break; - } - default: - break; - } -} - -static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, - const u32 delsys, - const u32 freq, - const u32 bw) -{ - /* This function returns the tuned frequency on success, 0 on error */ - struct tuner_simple_priv *priv = fe->tuner_priv; - struct tunertype *tun = priv->tun; - static struct tuner_params *t_params; - u8 config, cb; - u32 div; - int ret; - u32 frequency = freq / 62500; - - if (!tun->stepsize) { - /* tuner-core was loaded before the digital tuner was - * configured and somehow picked the wrong tuner type */ - tuner_err("attempt to treat tuner %d (%s) as digital tuner " - "without stepsize defined.\n", - priv->type, priv->tun->name); - return 0; /* failure */ - } - - t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL); - ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb); - if (ret < 0) - return 0; /* failure */ - - div = ((frequency + t_params->iffreq) * 62500 + offset + - tun->stepsize/2) / tun->stepsize; - - buf[0] = div >> 8; - buf[1] = div & 0xff; - buf[2] = config; - buf[3] = cb; - - simple_set_dvb(fe, buf, delsys, freq, bw); - - tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", - tun->name, div, buf[0], buf[1], buf[2], buf[3]); - - /* calculate the frequency we set it to */ - return (div * tun->stepsize) - t_params->iffreq; -} - -static int simple_dvb_calc_regs(struct dvb_frontend *fe, - u8 *buf, int buf_len) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u32 delsys = c->delivery_system; - u32 bw = c->bandwidth_hz; - struct tuner_simple_priv *priv = fe->tuner_priv; - u32 frequency; - - if (buf_len < 5) - return -EINVAL; - - frequency = simple_dvb_configure(fe, buf+1, delsys, c->frequency, bw); - if (frequency == 0) - return -EINVAL; - - buf[0] = priv->i2c_props.addr; - - priv->frequency = frequency; - priv->bandwidth = c->bandwidth_hz; - - return 5; -} - -static int simple_dvb_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u32 delsys = c->delivery_system; - u32 bw = c->bandwidth_hz; - u32 freq = c->frequency; - struct tuner_simple_priv *priv = fe->tuner_priv; - u32 frequency; - u32 prev_freq, prev_bw; - int ret; - u8 buf[5]; - - if (priv->i2c_props.adap == NULL) - return -EINVAL; - - prev_freq = priv->frequency; - prev_bw = priv->bandwidth; - - frequency = simple_dvb_configure(fe, buf+1, delsys, freq, bw); - if (frequency == 0) - return -EINVAL; - - buf[0] = priv->i2c_props.addr; - - priv->frequency = frequency; - priv->bandwidth = bw; - - /* put analog demod in standby when tuning digital */ - if (fe->ops.analog_ops.standby) - fe->ops.analog_ops.standby(fe); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - /* buf[0] contains the i2c address, but * - * we already have it in i2c_props.addr */ - ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4); - if (ret != 4) - goto fail; - - return 0; -fail: - /* calc_regs sets frequency and bandwidth. if we failed, unset them */ - priv->frequency = prev_freq; - priv->bandwidth = prev_bw; - - return ret; -} - -static int simple_init(struct dvb_frontend *fe) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - - if (priv->i2c_props.adap == NULL) - return -EINVAL; - - if (priv->tun->initdata) { - int ret; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - ret = tuner_i2c_xfer_send(&priv->i2c_props, - priv->tun->initdata + 1, - priv->tun->initdata[0]); - if (ret != priv->tun->initdata[0]) - return ret; - } - - return 0; -} - -static int simple_sleep(struct dvb_frontend *fe) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - - if (priv->i2c_props.adap == NULL) - return -EINVAL; - - if (priv->tun->sleepdata) { - int ret; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - ret = tuner_i2c_xfer_send(&priv->i2c_props, - priv->tun->sleepdata + 1, - priv->tun->sleepdata[0]); - if (ret != priv->tun->sleepdata[0]) - return ret; - } - - return 0; -} - -static int simple_release(struct dvb_frontend *fe) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - - mutex_lock(&tuner_simple_list_mutex); - - if (priv) - hybrid_tuner_release_state(priv); - - mutex_unlock(&tuner_simple_list_mutex); - - fe->tuner_priv = NULL; - - return 0; -} - -static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; - return 0; -} - -static struct dvb_tuner_ops simple_tuner_ops = { - .init = simple_init, - .sleep = simple_sleep, - .set_analog_params = simple_set_params, - .set_params = simple_dvb_set_params, - .calc_regs = simple_dvb_calc_regs, - .release = simple_release, - .get_frequency = simple_get_frequency, - .get_bandwidth = simple_get_bandwidth, - .get_status = simple_get_status, - .get_rf_strength = simple_get_rf_strength, -}; - -struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr, - unsigned int type) -{ - struct tuner_simple_priv *priv = NULL; - int instance; - - if (type >= tuner_count) { - printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n", - __func__, type, tuner_count-1); - return NULL; - } - - /* If i2c_adap is set, check that the tuner is at the correct address. - * Otherwise, if i2c_adap is NULL, the tuner will be programmed directly - * by the digital demod via calc_regs. - */ - if (i2c_adap != NULL) { - u8 b[1]; - struct i2c_msg msg = { - .addr = i2c_addr, .flags = I2C_M_RD, - .buf = b, .len = 1, - }; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (1 != i2c_transfer(i2c_adap, &msg, 1)) - printk(KERN_WARNING "tuner-simple %d-%04x: " - "unable to probe %s, proceeding anyway.", - i2c_adapter_id(i2c_adap), i2c_addr, - tuners[type].name); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - mutex_lock(&tuner_simple_list_mutex); - - instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv, - hybrid_tuner_instance_list, - i2c_adap, i2c_addr, - "tuner-simple"); - switch (instance) { - case 0: - mutex_unlock(&tuner_simple_list_mutex); - return NULL; - case 1: - fe->tuner_priv = priv; - - priv->type = type; - priv->tun = &tuners[type]; - priv->nr = simple_devcount++; - break; - default: - fe->tuner_priv = priv; - break; - } - - mutex_unlock(&tuner_simple_list_mutex); - - memcpy(&fe->ops.tuner_ops, &simple_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - if (type != priv->type) - tuner_warn("couldn't set type to %d. Using %d (%s) instead\n", - type, priv->type, priv->tun->name); - else - tuner_info("type set to %d (%s)\n", - priv->type, priv->tun->name); - - if ((debug) || ((atv_input[priv->nr] > 0) || - (dtv_input[priv->nr] > 0))) { - if (0 == atv_input[priv->nr]) - tuner_info("tuner %d atv rf input will be " - "autoselected\n", priv->nr); - else - tuner_info("tuner %d atv rf input will be " - "set to input %d (insmod option)\n", - priv->nr, atv_input[priv->nr]); - if (0 == dtv_input[priv->nr]) - tuner_info("tuner %d dtv rf input will be " - "autoselected\n", priv->nr); - else - tuner_info("tuner %d dtv rf input will be " - "set to input %d (insmod option)\n", - priv->nr, dtv_input[priv->nr]); - } - - strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name, - sizeof(fe->ops.tuner_ops.info.name)); - - return fe; -} -EXPORT_SYMBOL_GPL(simple_tuner_attach); - -MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver"); -MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); -MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/common/tuners/tuner-simple.h b/drivers/media/common/tuners/tuner-simple.h deleted file mode 100644 index 381fa5d35a9b..000000000000 --- a/drivers/media/common/tuners/tuner-simple.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - 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 __TUNER_SIMPLE_H__ -#define __TUNER_SIMPLE_H__ - -#include -#include "dvb_frontend.h" - -#if defined(CONFIG_MEDIA_TUNER_SIMPLE) || (defined(CONFIG_MEDIA_TUNER_SIMPLE_MODULE) && defined(MODULE)) -extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr, - unsigned int type); -#else -static inline struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr, - unsigned int type) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* __TUNER_SIMPLE_H__ */ diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c deleted file mode 100644 index 2da4440c16ee..000000000000 --- a/drivers/media/common/tuners/tuner-types.c +++ /dev/null @@ -1,1883 +0,0 @@ -/* - * - * i2c tv tuner chip device type database. - * - */ - -#include -#include -#include -#include - -/* ---------------------------------------------------------------------- */ - -/* - * The floats in the tuner struct are computed at compile time - * by gcc and cast back to integers. Thus we don't violate the - * "no float in kernel" rule. - * - * A tuner_range may be referenced by multiple tuner_params structs. - * There are many duplicates in here. Reusing tuner_range structs, - * rather than defining new ones for each tuner, will cut down on - * memory usage, and is preferred when possible. - * - * Each tuner_params array may contain one or more elements, one - * for each video standard. - * - * FIXME: tuner_params struct contains an element, tda988x. We must - * set this for all tuners that contain a tda988x chip, and then we - * can remove this setting from the various card structs. - * - * FIXME: Right now, all tuners are using the first tuner_params[] - * array element for analog mode. In the future, we will be merging - * similar tuner definitions together, such that each tuner definition - * will have a tuner_params struct for each available video standard. - * At that point, the tuner_params[] array element will be chosen - * based on the video standard in use. - */ - -/* The following was taken from dvb-pll.c: */ - -/* Set AGC TOP value to 103 dBuV: - * 0x80 = Control Byte - * 0x40 = 250 uA charge pump (irrelevant) - * 0x18 = Aux Byte to follow - * 0x06 = 64.5 kHz divider (irrelevant) - * 0x01 = Disable Vt (aka sleep) - * - * 0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA) - * 0x50 = AGC Take over point = 103 dBuV - */ -static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 }; - -/* 0x04 = 166.67 kHz divider - * - * 0x80 = AGC Time constant 50ms Iagc = 9 uA - * 0x20 = AGC Take over point = 112 dBuV - */ -static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 }; - -/* 0-9 */ -/* ------------ TUNER_TEMIC_PAL - TEMIC PAL ------------ */ - -static struct tuner_range tuner_temic_pal_ranges[] = { - { 16 * 140.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 463.25 /*MHz*/, 0x8e, 0x04, }, - { 16 * 999.99 , 0x8e, 0x01, }, -}; - -static struct tuner_params tuner_temic_pal_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_pal_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_PAL_I - Philips PAL_I ------------ */ - -static struct tuner_range tuner_philips_pal_i_ranges[] = { - { 16 * 140.25 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_philips_pal_i_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_philips_pal_i_ranges, - .count = ARRAY_SIZE(tuner_philips_pal_i_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_NTSC - Philips NTSC ------------ */ - -static struct tuner_range tuner_philips_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 451.25 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_philips_ntsc_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_philips_ntsc_ranges, - .count = ARRAY_SIZE(tuner_philips_ntsc_ranges), - .cb_first_if_lower_freq = 1, - }, -}; - -/* ------------ TUNER_PHILIPS_SECAM - Philips SECAM ------------ */ - -static struct tuner_range tuner_philips_secam_ranges[] = { - { 16 * 168.25 /*MHz*/, 0x8e, 0xa7, }, - { 16 * 447.25 /*MHz*/, 0x8e, 0x97, }, - { 16 * 999.99 , 0x8e, 0x37, }, -}; - -static struct tuner_params tuner_philips_secam_params[] = { - { - .type = TUNER_PARAM_TYPE_SECAM, - .ranges = tuner_philips_secam_ranges, - .count = ARRAY_SIZE(tuner_philips_secam_ranges), - .cb_first_if_lower_freq = 1, - }, -}; - -/* ------------ TUNER_PHILIPS_PAL - Philips PAL ------------ */ - -static struct tuner_range tuner_philips_pal_ranges[] = { - { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 447.25 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_philips_pal_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_philips_pal_ranges, - .count = ARRAY_SIZE(tuner_philips_pal_ranges), - .cb_first_if_lower_freq = 1, - }, -}; - -/* ------------ TUNER_TEMIC_NTSC - TEMIC NTSC ------------ */ - -static struct tuner_range tuner_temic_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 463.25 /*MHz*/, 0x8e, 0x04, }, - { 16 * 999.99 , 0x8e, 0x01, }, -}; - -static struct tuner_params tuner_temic_ntsc_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_temic_ntsc_ranges, - .count = ARRAY_SIZE(tuner_temic_ntsc_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_PAL_I - TEMIC PAL_I ------------ */ - -static struct tuner_range tuner_temic_pal_i_ranges[] = { - { 16 * 170.00 /*MHz*/, 0x8e, 0x02, }, - { 16 * 450.00 /*MHz*/, 0x8e, 0x04, }, - { 16 * 999.99 , 0x8e, 0x01, }, -}; - -static struct tuner_params tuner_temic_pal_i_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_pal_i_ranges, - .count = ARRAY_SIZE(tuner_temic_pal_i_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4036FY5_NTSC - TEMIC NTSC ------------ */ - -static struct tuner_range tuner_temic_4036fy5_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_temic_4036fy5_ntsc_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_temic_4036fy5_ntsc_ranges, - .count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_ranges), - }, -}; - -/* ------------ TUNER_ALPS_TSBH1_NTSC - TEMIC NTSC ------------ */ - -static struct tuner_range tuner_alps_tsb_1_ranges[] = { - { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 385.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_params tuner_alps_tsbh1_ntsc_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_alps_tsb_1_ranges, - .count = ARRAY_SIZE(tuner_alps_tsb_1_ranges), - }, -}; - -/* 10-19 */ -/* ------------ TUNER_ALPS_TSBE1_PAL - TEMIC PAL ------------ */ - -static struct tuner_params tuner_alps_tsb_1_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_alps_tsb_1_ranges, - .count = ARRAY_SIZE(tuner_alps_tsb_1_ranges), - }, -}; - -/* ------------ TUNER_ALPS_TSBB5_PAL_I - Alps PAL_I ------------ */ - -static struct tuner_range tuner_alps_tsb_5_pal_ranges[] = { - { 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 351.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_params tuner_alps_tsbb5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_alps_tsb_5_pal_ranges, - .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), - }, -}; - -/* ------------ TUNER_ALPS_TSBE5_PAL - Alps PAL ------------ */ - -static struct tuner_params tuner_alps_tsbe5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_alps_tsb_5_pal_ranges, - .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), - }, -}; - -/* ------------ TUNER_ALPS_TSBC5_PAL - Alps PAL ------------ */ - -static struct tuner_params tuner_alps_tsbc5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_alps_tsb_5_pal_ranges, - .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4006FH5_PAL - TEMIC PAL ------------ */ - -static struct tuner_range tuner_lg_pal_ranges[] = { - { 16 * 170.00 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 450.00 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_temic_4006fh5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_pal_ranges, - .count = ARRAY_SIZE(tuner_lg_pal_ranges), - }, -}; - -/* ------------ TUNER_ALPS_TSHC6_NTSC - Alps NTSC ------------ */ - -static struct tuner_range tuner_alps_tshc6_ntsc_ranges[] = { - { 16 * 137.25 /*MHz*/, 0x8e, 0x14, }, - { 16 * 385.25 /*MHz*/, 0x8e, 0x12, }, - { 16 * 999.99 , 0x8e, 0x11, }, -}; - -static struct tuner_params tuner_alps_tshc6_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_alps_tshc6_ntsc_ranges, - .count = ARRAY_SIZE(tuner_alps_tshc6_ntsc_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_PAL_DK - TEMIC PAL ------------ */ - -static struct tuner_range tuner_temic_pal_dk_ranges[] = { - { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 456.25 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_temic_pal_dk_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_pal_dk_ranges, - .count = ARRAY_SIZE(tuner_temic_pal_dk_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_NTSC_M - Philips NTSC ------------ */ - -static struct tuner_range tuner_philips_ntsc_m_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 454.00 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_philips_ntsc_m_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_philips_ntsc_m_ranges, - .count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4066FY5_PAL_I - TEMIC PAL_I ------------ */ - -static struct tuner_range tuner_temic_40x6f_5_pal_ranges[] = { - { 16 * 169.00 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 454.00 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_temic_4066fy5_pal_i_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_40x6f_5_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4006FN5_MULTI_PAL - TEMIC PAL ------------ */ - -static struct tuner_params tuner_temic_4006fn5_multi_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_40x6f_5_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), - }, -}; - -/* 20-29 */ -/* ------------ TUNER_TEMIC_4009FR5_PAL - TEMIC PAL ------------ */ - -static struct tuner_range tuner_temic_4009f_5_pal_ranges[] = { - { 16 * 141.00 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 464.00 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_temic_4009f_5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_4009f_5_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4039FR5_NTSC - TEMIC NTSC ------------ */ - -static struct tuner_range tuner_temic_4x3x_f_5_ntsc_ranges[] = { - { 16 * 158.00 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 453.00 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_temic_4039fr5_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_temic_4x3x_f_5_ntsc_ranges, - .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4046FM5 - TEMIC PAL ------------ */ - -static struct tuner_params tuner_temic_4046fm5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_40x6f_5_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_PAL_DK - Philips PAL ------------ */ - -static struct tuner_params tuner_philips_pal_dk_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_pal_ranges, - .count = ARRAY_SIZE(tuner_lg_pal_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_FQ1216ME - Philips PAL ------------ */ - -static struct tuner_params tuner_philips_fq1216me_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_pal_ranges, - .count = ARRAY_SIZE(tuner_lg_pal_ranges), - .has_tda9887 = 1, - .port1_active = 1, - .port2_active = 1, - .port2_invert_for_secam_lc = 1, - }, -}; - -/* ------------ TUNER_LG_PAL_I_FM - LGINNOTEK PAL_I ------------ */ - -static struct tuner_params tuner_lg_pal_i_fm_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_pal_ranges, - .count = ARRAY_SIZE(tuner_lg_pal_ranges), - }, -}; - -/* ------------ TUNER_LG_PAL_I - LGINNOTEK PAL_I ------------ */ - -static struct tuner_params tuner_lg_pal_i_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_pal_ranges, - .count = ARRAY_SIZE(tuner_lg_pal_ranges), - }, -}; - -/* ------------ TUNER_LG_NTSC_FM - LGINNOTEK NTSC ------------ */ - -static struct tuner_range tuner_lg_ntsc_fm_ranges[] = { - { 16 * 210.00 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 497.00 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_lg_ntsc_fm_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_lg_ntsc_fm_ranges, - .count = ARRAY_SIZE(tuner_lg_ntsc_fm_ranges), - }, -}; - -/* ------------ TUNER_LG_PAL_FM - LGINNOTEK PAL ------------ */ - -static struct tuner_params tuner_lg_pal_fm_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_pal_ranges, - .count = ARRAY_SIZE(tuner_lg_pal_ranges), - }, -}; - -/* ------------ TUNER_LG_PAL - LGINNOTEK PAL ------------ */ - -static struct tuner_params tuner_lg_pal_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_pal_ranges, - .count = ARRAY_SIZE(tuner_lg_pal_ranges), - }, -}; - -/* 30-39 */ -/* ------------ TUNER_TEMIC_4009FN5_MULTI_PAL_FM - TEMIC PAL ------------ */ - -static struct tuner_params tuner_temic_4009_fn5_multi_pal_fm_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_4009f_5_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), - }, -}; - -/* ------------ TUNER_SHARP_2U5JF5540_NTSC - SHARP NTSC ------------ */ - -static struct tuner_range tuner_sharp_2u5jf5540_ntsc_ranges[] = { - { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 317.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_params tuner_sharp_2u5jf5540_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_sharp_2u5jf5540_ntsc_ranges, - .count = ARRAY_SIZE(tuner_sharp_2u5jf5540_ntsc_ranges), - }, -}; - -/* ------------ TUNER_Samsung_PAL_TCPM9091PD27 - Samsung PAL ------------ */ - -static struct tuner_range tuner_samsung_pal_tcpm9091pd27_ranges[] = { - { 16 * 169 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 464 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_samsung_pal_tcpm9091pd27_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_samsung_pal_tcpm9091pd27_ranges, - .count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4106FH5 - TEMIC PAL ------------ */ - -static struct tuner_params tuner_temic_4106fh5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_4009f_5_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4012FY5 - TEMIC PAL ------------ */ - -static struct tuner_params tuner_temic_4012fy5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_pal_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4136FY5 - TEMIC NTSC ------------ */ - -static struct tuner_params tuner_temic_4136_fy5_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_temic_4x3x_f_5_ntsc_ranges, - .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges), - }, -}; - -/* ------------ TUNER_LG_PAL_NEW_TAPC - LGINNOTEK PAL ------------ */ - -static struct tuner_range tuner_lg_new_tapc_ranges[] = { - { 16 * 170.00 /*MHz*/, 0x8e, 0x01, }, - { 16 * 450.00 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_params tuner_lg_pal_new_tapc_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_new_tapc_ranges, - .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_FM1216ME_MK3 - Philips PAL ------------ */ - -static struct tuner_range tuner_fm1216me_mk3_pal_ranges[] = { - { 16 * 158.00 /*MHz*/, 0x8e, 0x01, }, - { 16 * 442.00 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x04, }, -}; - -static struct tuner_params tuner_fm1216me_mk3_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_fm1216me_mk3_pal_ranges, - .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges), - .cb_first_if_lower_freq = 1, - .has_tda9887 = 1, - .port1_active = 1, - .port2_active = 1, - .port2_invert_for_secam_lc = 1, - .port1_fm_high_sensitivity = 1, - .default_top_mid = -2, - .default_top_secam_mid = -2, - .default_top_secam_high = -2, - }, -}; - -/* ------------ TUNER_PHILIPS_FM1216MK5 - Philips PAL ------------ */ - -static struct tuner_range tuner_fm1216mk5_pal_ranges[] = { - { 16 * 158.00 /*MHz*/, 0xce, 0x01, }, - { 16 * 441.00 /*MHz*/, 0xce, 0x02, }, - { 16 * 864.00 , 0xce, 0x04, }, -}; - -static struct tuner_params tuner_fm1216mk5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_fm1216mk5_pal_ranges, - .count = ARRAY_SIZE(tuner_fm1216mk5_pal_ranges), - .cb_first_if_lower_freq = 1, - .has_tda9887 = 1, - .port1_active = 1, - .port2_active = 1, - .port2_invert_for_secam_lc = 1, - .port1_fm_high_sensitivity = 1, - .default_top_mid = -2, - .default_top_secam_mid = -2, - .default_top_secam_high = -2, - }, -}; - -/* ------------ TUNER_LG_NTSC_NEW_TAPC - LGINNOTEK NTSC ------------ */ - -static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_lg_new_tapc_ranges, - .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), - }, -}; - -/* 40-49 */ -/* ------------ TUNER_HITACHI_NTSC - HITACHI NTSC ------------ */ - -static struct tuner_params tuner_hitachi_ntsc_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_lg_new_tapc_ranges, - .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_PAL_MK - Philips PAL ------------ */ - -static struct tuner_range tuner_philips_pal_mk_pal_ranges[] = { - { 16 * 140.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 463.25 /*MHz*/, 0x8e, 0xc2, }, - { 16 * 999.99 , 0x8e, 0xcf, }, -}; - -static struct tuner_params tuner_philips_pal_mk_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_philips_pal_mk_pal_ranges, - .count = ARRAY_SIZE(tuner_philips_pal_mk_pal_ranges), - }, -}; - -/* ---- TUNER_PHILIPS_FCV1236D - Philips FCV1236D (ATSC/NTSC) ---- */ - -static struct tuner_range tuner_philips_fcv1236d_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0x8e, 0xa2, }, - { 16 * 451.25 /*MHz*/, 0x8e, 0x92, }, - { 16 * 999.99 , 0x8e, 0x32, }, -}; - -static struct tuner_range tuner_philips_fcv1236d_atsc_ranges[] = { - { 16 * 159.00 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 453.00 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_philips_fcv1236d_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_philips_fcv1236d_ntsc_ranges, - .count = ARRAY_SIZE(tuner_philips_fcv1236d_ntsc_ranges), - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_philips_fcv1236d_atsc_ranges, - .count = ARRAY_SIZE(tuner_philips_fcv1236d_atsc_ranges), - .iffreq = 16 * 44.00, - }, -}; - -/* ------------ TUNER_PHILIPS_FM1236_MK3 - Philips NTSC ------------ */ - -static struct tuner_range tuner_fm1236_mk3_ntsc_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x8e, 0x01, }, - { 16 * 442.00 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x04, }, -}; - -static struct tuner_params tuner_fm1236_mk3_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_fm1236_mk3_ntsc_ranges, - .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), - .cb_first_if_lower_freq = 1, - .has_tda9887 = 1, - .port1_active = 1, - .port2_active = 1, - .port1_fm_high_sensitivity = 1, - }, -}; - -/* ------------ TUNER_PHILIPS_4IN1 - Philips NTSC ------------ */ - -static struct tuner_params tuner_philips_4in1_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_fm1236_mk3_ntsc_ranges, - .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), - }, -}; - -/* ------------ TUNER_MICROTUNE_4049FM5 - Microtune PAL ------------ */ - -static struct tuner_params tuner_microtune_4049_fm5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_4009f_5_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), - .has_tda9887 = 1, - .port1_invert_for_secam_lc = 1, - .default_pll_gating_18 = 1, - .fm_gain_normal=1, - .radio_if = 1, /* 33.3 MHz */ - }, -}; - -/* ------------ TUNER_PANASONIC_VP27 - Panasonic NTSC ------------ */ - -static struct tuner_range tuner_panasonic_vp27_ntsc_ranges[] = { - { 16 * 160.00 /*MHz*/, 0xce, 0x01, }, - { 16 * 454.00 /*MHz*/, 0xce, 0x02, }, - { 16 * 999.99 , 0xce, 0x08, }, -}; - -static struct tuner_params tuner_panasonic_vp27_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_panasonic_vp27_ntsc_ranges, - .count = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges), - .has_tda9887 = 1, - .intercarrier_mode = 1, - .default_top_low = -3, - .default_top_mid = -3, - .default_top_high = -3, - }, -}; - -/* ------------ TUNER_TNF_8831BGFF - Philips PAL ------------ */ - -static struct tuner_range tuner_tnf_8831bgff_pal_ranges[] = { - { 16 * 161.25 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_tnf_8831bgff_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_tnf_8831bgff_pal_ranges, - .count = ARRAY_SIZE(tuner_tnf_8831bgff_pal_ranges), - }, -}; - -/* ------------ TUNER_MICROTUNE_4042FI5 - Microtune NTSC ------------ */ - -static struct tuner_range tuner_microtune_4042fi5_ntsc_ranges[] = { - { 16 * 162.00 /*MHz*/, 0x8e, 0xa2, }, - { 16 * 457.00 /*MHz*/, 0x8e, 0x94, }, - { 16 * 999.99 , 0x8e, 0x31, }, -}; - -static struct tuner_range tuner_microtune_4042fi5_atsc_ranges[] = { - { 16 * 162.00 /*MHz*/, 0x8e, 0xa1, }, - { 16 * 457.00 /*MHz*/, 0x8e, 0x91, }, - { 16 * 999.99 , 0x8e, 0x31, }, -}; - -static struct tuner_params tuner_microtune_4042fi5_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_microtune_4042fi5_ntsc_ranges, - .count = ARRAY_SIZE(tuner_microtune_4042fi5_ntsc_ranges), - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_microtune_4042fi5_atsc_ranges, - .count = ARRAY_SIZE(tuner_microtune_4042fi5_atsc_ranges), - .iffreq = 16 * 44.00 /*MHz*/, - }, -}; - -/* 50-59 */ -/* ------------ TUNER_TCL_2002N - TCL NTSC ------------ */ - -static struct tuner_range tuner_tcl_2002n_ntsc_ranges[] = { - { 16 * 172.00 /*MHz*/, 0x8e, 0x01, }, - { 16 * 448.00 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_params tuner_tcl_2002n_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_tcl_2002n_ntsc_ranges, - .count = ARRAY_SIZE(tuner_tcl_2002n_ntsc_ranges), - .cb_first_if_lower_freq = 1, - }, -}; - -/* ------------ TUNER_PHILIPS_FM1256_IH3 - Philips PAL ------------ */ - -static struct tuner_params tuner_philips_fm1256_ih3_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_fm1236_mk3_ntsc_ranges, - .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), - .radio_if = 1, /* 33.3 MHz */ - }, -}; - -/* ------------ TUNER_THOMSON_DTT7610 - THOMSON ATSC ------------ */ - -/* single range used for both ntsc and atsc */ -static struct tuner_range tuner_thomson_dtt7610_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0x8e, 0x39, }, - { 16 * 454.00 /*MHz*/, 0x8e, 0x3a, }, - { 16 * 999.99 , 0x8e, 0x3c, }, -}; - -static struct tuner_params tuner_thomson_dtt7610_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_thomson_dtt7610_ntsc_ranges, - .count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges), - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_thomson_dtt7610_ntsc_ranges, - .count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges), - .iffreq = 16 * 44.00 /*MHz*/, - }, -}; - -/* ------------ TUNER_PHILIPS_FQ1286 - Philips NTSC ------------ */ - -static struct tuner_range tuner_philips_fq1286_ntsc_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x8e, 0x41, }, - { 16 * 454.00 /*MHz*/, 0x8e, 0x42, }, - { 16 * 999.99 , 0x8e, 0x04, }, -}; - -static struct tuner_params tuner_philips_fq1286_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_philips_fq1286_ntsc_ranges, - .count = ARRAY_SIZE(tuner_philips_fq1286_ntsc_ranges), - }, -}; - -/* ------------ TUNER_TCL_2002MB - TCL PAL ------------ */ - -static struct tuner_range tuner_tcl_2002mb_pal_ranges[] = { - { 16 * 170.00 /*MHz*/, 0xce, 0x01, }, - { 16 * 450.00 /*MHz*/, 0xce, 0x02, }, - { 16 * 999.99 , 0xce, 0x08, }, -}; - -static struct tuner_params tuner_tcl_2002mb_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_tcl_2002mb_pal_ranges, - .count = ARRAY_SIZE(tuner_tcl_2002mb_pal_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_FQ1216AME_MK4 - Philips PAL ------------ */ - -static struct tuner_range tuner_philips_fq12_6a___mk4_pal_ranges[] = { - { 16 * 160.00 /*MHz*/, 0xce, 0x01, }, - { 16 * 442.00 /*MHz*/, 0xce, 0x02, }, - { 16 * 999.99 , 0xce, 0x04, }, -}; - -static struct tuner_params tuner_philips_fq1216ame_mk4_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_philips_fq12_6a___mk4_pal_ranges, - .count = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_pal_ranges), - .has_tda9887 = 1, - .port1_active = 1, - .port2_invert_for_secam_lc = 1, - .default_top_mid = -2, - .default_top_secam_low = -2, - .default_top_secam_mid = -2, - .default_top_secam_high = -2, - }, -}; - -/* ------------ TUNER_PHILIPS_FQ1236A_MK4 - Philips NTSC ------------ */ - -static struct tuner_params tuner_philips_fq1236a_mk4_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_fm1236_mk3_ntsc_ranges, - .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), - }, -}; - -/* ------------ TUNER_YMEC_TVF_8531MF - Philips NTSC ------------ */ - -static struct tuner_params tuner_ymec_tvf_8531mf_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_philips_ntsc_m_ranges, - .count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges), - }, -}; - -/* ------------ TUNER_YMEC_TVF_5533MF - Philips NTSC ------------ */ - -static struct tuner_range tuner_ymec_tvf_5533mf_ntsc_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x8e, 0x01, }, - { 16 * 454.00 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x04, }, -}; - -static struct tuner_params tuner_ymec_tvf_5533mf_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_ymec_tvf_5533mf_ntsc_ranges, - .count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_ntsc_ranges), - }, -}; - -/* 60-69 */ -/* ------------ TUNER_THOMSON_DTT761X - THOMSON ATSC ------------ */ -/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ - -static struct tuner_range tuner_thomson_dtt761x_ntsc_ranges[] = { - { 16 * 145.25 /*MHz*/, 0x8e, 0x39, }, - { 16 * 415.25 /*MHz*/, 0x8e, 0x3a, }, - { 16 * 999.99 , 0x8e, 0x3c, }, -}; - -static struct tuner_range tuner_thomson_dtt761x_atsc_ranges[] = { - { 16 * 147.00 /*MHz*/, 0x8e, 0x39, }, - { 16 * 417.00 /*MHz*/, 0x8e, 0x3a, }, - { 16 * 999.99 , 0x8e, 0x3c, }, -}; - -static struct tuner_params tuner_thomson_dtt761x_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_thomson_dtt761x_ntsc_ranges, - .count = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges), - .has_tda9887 = 1, - .fm_gain_normal = 1, - .radio_if = 2, /* 41.3 MHz */ - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_thomson_dtt761x_atsc_ranges, - .count = ARRAY_SIZE(tuner_thomson_dtt761x_atsc_ranges), - .iffreq = 16 * 44.00, /*MHz*/ - }, -}; - -/* ------------ TUNER_TENA_9533_DI - Philips PAL ------------ */ - -static struct tuner_range tuner_tena_9533_di_pal_ranges[] = { - { 16 * 160.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 464.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x04, }, -}; - -static struct tuner_params tuner_tena_9533_di_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_tena_9533_di_pal_ranges, - .count = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges), - }, -}; - -/* ------------ TUNER_TENA_TNF_5337 - Tena tnf5337MFD STD M/N ------------ */ - -static struct tuner_range tuner_tena_tnf_5337_ntsc_ranges[] = { - { 16 * 166.25 /*MHz*/, 0x86, 0x01, }, - { 16 * 466.25 /*MHz*/, 0x86, 0x02, }, - { 16 * 999.99 , 0x86, 0x08, }, -}; - -static struct tuner_params tuner_tena_tnf_5337_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_tena_tnf_5337_ntsc_ranges, - .count = ARRAY_SIZE(tuner_tena_tnf_5337_ntsc_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_FMD1216ME(X)_MK3 - Philips PAL ------------ */ - -static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x86, 0x51, }, - { 16 * 442.00 /*MHz*/, 0x86, 0x52, }, - { 16 * 999.99 , 0x86, 0x54, }, -}; - -static struct tuner_range tuner_philips_fmd1216me_mk3_dvb_ranges[] = { - { 16 * 143.87 /*MHz*/, 0xbc, 0x41 }, - { 16 * 158.87 /*MHz*/, 0xf4, 0x41 }, - { 16 * 329.87 /*MHz*/, 0xbc, 0x42 }, - { 16 * 441.87 /*MHz*/, 0xf4, 0x42 }, - { 16 * 625.87 /*MHz*/, 0xbc, 0x44 }, - { 16 * 803.87 /*MHz*/, 0xf4, 0x44 }, - { 16 * 999.99 , 0xfc, 0x44 }, -}; - -static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_philips_fmd1216me_mk3_pal_ranges, - .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges), - .has_tda9887 = 1, - .port1_active = 1, - .port2_active = 1, - .port2_fm_high_sensitivity = 1, - .port2_invert_for_secam_lc = 1, - .port1_set_for_fm_mono = 1, - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges, - .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges), - .iffreq = 16 * 36.125, /*MHz*/ - }, -}; - -static struct tuner_params tuner_philips_fmd1216mex_mk3_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_philips_fmd1216me_mk3_pal_ranges, - .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges), - .has_tda9887 = 1, - .port1_active = 1, - .port2_active = 1, - .port2_fm_high_sensitivity = 1, - .port2_invert_for_secam_lc = 1, - .port1_set_for_fm_mono = 1, - .radio_if = 1, - .fm_gain_normal = 1, - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges, - .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges), - .iffreq = 16 * 36.125, /*MHz*/ - }, -}; - -/* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */ - -static struct tuner_range tuner_tua6034_ntsc_ranges[] = { - { 16 * 165.00 /*MHz*/, 0x8e, 0x01 }, - { 16 * 450.00 /*MHz*/, 0x8e, 0x02 }, - { 16 * 999.99 , 0x8e, 0x04 }, -}; - -static struct tuner_range tuner_tua6034_atsc_ranges[] = { - { 16 * 165.00 /*MHz*/, 0xce, 0x01 }, - { 16 * 450.00 /*MHz*/, 0xce, 0x02 }, - { 16 * 999.99 , 0xce, 0x04 }, -}; - -static struct tuner_params tuner_lg_tdvs_h06xf_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_tua6034_ntsc_ranges, - .count = ARRAY_SIZE(tuner_tua6034_ntsc_ranges), - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_tua6034_atsc_ranges, - .count = ARRAY_SIZE(tuner_tua6034_atsc_ranges), - .iffreq = 16 * 44.00, - }, -}; - -/* ------------ TUNER_YMEC_TVF66T5_B_DFF - Philips PAL ------------ */ - -static struct tuner_range tuner_ymec_tvf66t5_b_dff_pal_ranges[] = { - { 16 * 160.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 464.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_params tuner_ymec_tvf66t5_b_dff_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_ymec_tvf66t5_b_dff_pal_ranges, - .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_pal_ranges), - }, -}; - -/* ------------ TUNER_LG_NTSC_TALN_MINI - LGINNOTEK NTSC ------------ */ - -static struct tuner_range tuner_lg_taln_ntsc_ranges[] = { - { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 373.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_range tuner_lg_taln_pal_secam_ranges[] = { - { 16 * 150.00 /*MHz*/, 0x8e, 0x01, }, - { 16 * 425.00 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_params tuner_lg_taln_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_lg_taln_ntsc_ranges, - .count = ARRAY_SIZE(tuner_lg_taln_ntsc_ranges), - },{ - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_taln_pal_secam_ranges, - .count = ARRAY_SIZE(tuner_lg_taln_pal_secam_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_TD1316 - Philips PAL ------------ */ - -static struct tuner_range tuner_philips_td1316_pal_ranges[] = { - { 16 * 160.00 /*MHz*/, 0xc8, 0xa1, }, - { 16 * 442.00 /*MHz*/, 0xc8, 0xa2, }, - { 16 * 999.99 , 0xc8, 0xa4, }, -}; - -static struct tuner_range tuner_philips_td1316_dvb_ranges[] = { - { 16 * 93.834 /*MHz*/, 0xca, 0x60, }, - { 16 * 123.834 /*MHz*/, 0xca, 0xa0, }, - { 16 * 163.834 /*MHz*/, 0xca, 0xc0, }, - { 16 * 253.834 /*MHz*/, 0xca, 0x60, }, - { 16 * 383.834 /*MHz*/, 0xca, 0xa0, }, - { 16 * 443.834 /*MHz*/, 0xca, 0xc0, }, - { 16 * 583.834 /*MHz*/, 0xca, 0x60, }, - { 16 * 793.834 /*MHz*/, 0xca, 0xa0, }, - { 16 * 999.999 , 0xca, 0xe0, }, -}; - -static struct tuner_params tuner_philips_td1316_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_philips_td1316_pal_ranges, - .count = ARRAY_SIZE(tuner_philips_td1316_pal_ranges), - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_philips_td1316_dvb_ranges, - .count = ARRAY_SIZE(tuner_philips_td1316_dvb_ranges), - .iffreq = 16 * 36.166667 /*MHz*/, - }, -}; - -/* ------------ TUNER_PHILIPS_TUV1236D - Philips ATSC ------------ */ - -static struct tuner_range tuner_tuv1236d_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0xce, 0x01, }, - { 16 * 454.00 /*MHz*/, 0xce, 0x02, }, - { 16 * 999.99 , 0xce, 0x04, }, -}; - -static struct tuner_range tuner_tuv1236d_atsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0xc6, 0x41, }, - { 16 * 454.00 /*MHz*/, 0xc6, 0x42, }, - { 16 * 999.99 , 0xc6, 0x44, }, -}; - -static struct tuner_params tuner_tuv1236d_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_tuv1236d_ntsc_ranges, - .count = ARRAY_SIZE(tuner_tuv1236d_ntsc_ranges), - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_tuv1236d_atsc_ranges, - .count = ARRAY_SIZE(tuner_tuv1236d_atsc_ranges), - .iffreq = 16 * 44.00, - }, -}; - -/* ------------ TUNER_TNF_xxx5 - Texas Instruments--------- */ -/* This is known to work with Tenna TVF58t5-MFF and TVF5835 MFF - * but it is expected to work also with other Tenna/Ymec - * models based on TI SN 761677 chip on both PAL and NTSC - */ - -static struct tuner_range tuner_tnf_5335_d_if_pal_ranges[] = { - { 16 * 168.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 471.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_range tuner_tnf_5335mf_ntsc_ranges[] = { - { 16 * 169.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 469.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_params tuner_tnf_5335mf_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_tnf_5335mf_ntsc_ranges, - .count = ARRAY_SIZE(tuner_tnf_5335mf_ntsc_ranges), - }, - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_tnf_5335_d_if_pal_ranges, - .count = ARRAY_SIZE(tuner_tnf_5335_d_if_pal_ranges), - }, -}; - -/* 70-79 */ -/* ------------ TUNER_SAMSUNG_TCPN_2121P30A - Samsung NTSC ------------ */ - -/* '+ 4' turns on the Low Noise Amplifier */ -static struct tuner_range tuner_samsung_tcpn_2121p30a_ntsc_ranges[] = { - { 16 * 130.00 /*MHz*/, 0xce, 0x01 + 4, }, - { 16 * 364.50 /*MHz*/, 0xce, 0x02 + 4, }, - { 16 * 999.99 , 0xce, 0x08 + 4, }, -}; - -static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges, - .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges), - }, -}; - -/* ------------ TUNER_THOMSON_FE6600 - DViCO Hybrid PAL ------------ */ - -static struct tuner_range tuner_thomson_fe6600_pal_ranges[] = { - { 16 * 160.00 /*MHz*/, 0xfe, 0x11, }, - { 16 * 442.00 /*MHz*/, 0xf6, 0x12, }, - { 16 * 999.99 , 0xf6, 0x18, }, -}; - -static struct tuner_range tuner_thomson_fe6600_dvb_ranges[] = { - { 16 * 250.00 /*MHz*/, 0xb4, 0x12, }, - { 16 * 455.00 /*MHz*/, 0xfe, 0x11, }, - { 16 * 775.50 /*MHz*/, 0xbc, 0x18, }, - { 16 * 999.99 , 0xf4, 0x18, }, -}; - -static struct tuner_params tuner_thomson_fe6600_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_thomson_fe6600_pal_ranges, - .count = ARRAY_SIZE(tuner_thomson_fe6600_pal_ranges), - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_thomson_fe6600_dvb_ranges, - .count = ARRAY_SIZE(tuner_thomson_fe6600_dvb_ranges), - .iffreq = 16 * 36.125 /*MHz*/, - }, -}; - -/* ------------ TUNER_SAMSUNG_TCPG_6121P30A - Samsung PAL ------------ */ - -/* '+ 4' turns on the Low Noise Amplifier */ -static struct tuner_range tuner_samsung_tcpg_6121p30a_pal_ranges[] = { - { 16 * 146.25 /*MHz*/, 0xce, 0x01 + 4, }, - { 16 * 428.50 /*MHz*/, 0xce, 0x02 + 4, }, - { 16 * 999.99 , 0xce, 0x08 + 4, }, -}; - -static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_samsung_tcpg_6121p30a_pal_ranges, - .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_pal_ranges), - .has_tda9887 = 1, - .port1_active = 1, - .port2_active = 1, - .port2_invert_for_secam_lc = 1, - }, -}; - -/* ------------ TUNER_TCL_MF02GIP-5N-E - TCL MF02GIP-5N ------------ */ - -static struct tuner_range tuner_tcl_mf02gip_5n_ntsc_ranges[] = { - { 16 * 172.00 /*MHz*/, 0x8e, 0x01, }, - { 16 * 448.00 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x04, }, -}; - -static struct tuner_params tuner_tcl_mf02gip_5n_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_tcl_mf02gip_5n_ntsc_ranges, - .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_ntsc_ranges), - .cb_first_if_lower_freq = 1, - }, -}; - -/* 80-89 */ -/* --------- TUNER_PHILIPS_FQ1216LME_MK3 -- active loopthrough, no FM ------- */ - -static struct tuner_params tuner_fq1216lme_mk3_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_fm1216me_mk3_pal_ranges, - .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges), - .cb_first_if_lower_freq = 1, /* not specified, but safe to do */ - .has_tda9887 = 1, /* TDA9886 */ - .port1_active = 1, - .port2_active = 1, - .port2_invert_for_secam_lc = 1, - .default_top_low = 4, - .default_top_mid = 4, - .default_top_high = 4, - .default_top_secam_low = 4, - .default_top_secam_mid = 4, - .default_top_secam_high = 4, - }, -}; - -/* ----- TUNER_PARTSNIC_PTI_5NF05 - Partsnic (Daewoo) PTI-5NF05 NTSC ----- */ - -static struct tuner_range tuner_partsnic_pti_5nf05_ranges[] = { - /* The datasheet specified channel ranges and the bandswitch byte */ - /* The control byte value of 0x8e is just a guess */ - { 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, /* Channels 2 - B */ - { 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, /* Channels C - W+11 */ - { 16 * 999.99 , 0x8e, 0x08, }, /* Channels W+12 - 69 */ -}; - -static struct tuner_params tuner_partsnic_pti_5nf05_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_partsnic_pti_5nf05_ranges, - .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_ranges), - .cb_first_if_lower_freq = 1, /* not specified but safe to do */ - }, -}; - -/* --------- TUNER_PHILIPS_CU1216L - DVB-C NIM ------------------------- */ - -static struct tuner_range tuner_cu1216l_ranges[] = { - { 16 * 160.25 /*MHz*/, 0xce, 0x01 }, - { 16 * 444.25 /*MHz*/, 0xce, 0x02 }, - { 16 * 999.99 , 0xce, 0x04 }, -}; - -static struct tuner_params tuner_philips_cu1216l_params[] = { - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_cu1216l_ranges, - .count = ARRAY_SIZE(tuner_cu1216l_ranges), - .iffreq = 16 * 36.125, /*MHz*/ - }, -}; - -/* ---------------------- TUNER_SONY_BTF_PXN01Z ------------------------ */ - -static struct tuner_range tuner_sony_btf_pxn01z_ranges[] = { - { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x04, }, -}; - -static struct tuner_params tuner_sony_btf_pxn01z_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_sony_btf_pxn01z_ranges, - .count = ARRAY_SIZE(tuner_sony_btf_pxn01z_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_FQ1236_MK5 - Philips NTSC ------------ */ - -static struct tuner_params tuner_philips_fq1236_mk5_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_fm1236_mk3_ntsc_ranges, - .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), - .has_tda9887 = 1, /* TDA9885, no FM radio */ - }, -}; - -/* --------------------------------------------------------------------- */ - -struct tunertype tuners[] = { - /* 0-9 */ - [TUNER_TEMIC_PAL] = { /* TEMIC PAL */ - .name = "Temic PAL (4002 FH5)", - .params = tuner_temic_pal_params, - .count = ARRAY_SIZE(tuner_temic_pal_params), - }, - [TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */ - .name = "Philips PAL_I (FI1246 and compatibles)", - .params = tuner_philips_pal_i_params, - .count = ARRAY_SIZE(tuner_philips_pal_i_params), - }, - [TUNER_PHILIPS_NTSC] = { /* Philips NTSC */ - .name = "Philips NTSC (FI1236,FM1236 and compatibles)", - .params = tuner_philips_ntsc_params, - .count = ARRAY_SIZE(tuner_philips_ntsc_params), - }, - [TUNER_PHILIPS_SECAM] = { /* Philips SECAM */ - .name = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", - .params = tuner_philips_secam_params, - .count = ARRAY_SIZE(tuner_philips_secam_params), - }, - [TUNER_ABSENT] = { /* Tuner Absent */ - .name = "NoTuner", - }, - [TUNER_PHILIPS_PAL] = { /* Philips PAL */ - .name = "Philips PAL_BG (FI1216 and compatibles)", - .params = tuner_philips_pal_params, - .count = ARRAY_SIZE(tuner_philips_pal_params), - }, - [TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */ - .name = "Temic NTSC (4032 FY5)", - .params = tuner_temic_ntsc_params, - .count = ARRAY_SIZE(tuner_temic_ntsc_params), - }, - [TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */ - .name = "Temic PAL_I (4062 FY5)", - .params = tuner_temic_pal_i_params, - .count = ARRAY_SIZE(tuner_temic_pal_i_params), - }, - [TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */ - .name = "Temic NTSC (4036 FY5)", - .params = tuner_temic_4036fy5_ntsc_params, - .count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_params), - }, - [TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */ - .name = "Alps HSBH1", - .params = tuner_alps_tsbh1_ntsc_params, - .count = ARRAY_SIZE(tuner_alps_tsbh1_ntsc_params), - }, - - /* 10-19 */ - [TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */ - .name = "Alps TSBE1", - .params = tuner_alps_tsb_1_params, - .count = ARRAY_SIZE(tuner_alps_tsb_1_params), - }, - [TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */ - .name = "Alps TSBB5", - .params = tuner_alps_tsbb5_params, - .count = ARRAY_SIZE(tuner_alps_tsbb5_params), - }, - [TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */ - .name = "Alps TSBE5", - .params = tuner_alps_tsbe5_params, - .count = ARRAY_SIZE(tuner_alps_tsbe5_params), - }, - [TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */ - .name = "Alps TSBC5", - .params = tuner_alps_tsbc5_params, - .count = ARRAY_SIZE(tuner_alps_tsbc5_params), - }, - [TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */ - .name = "Temic PAL_BG (4006FH5)", - .params = tuner_temic_4006fh5_params, - .count = ARRAY_SIZE(tuner_temic_4006fh5_params), - }, - [TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */ - .name = "Alps TSCH6", - .params = tuner_alps_tshc6_params, - .count = ARRAY_SIZE(tuner_alps_tshc6_params), - }, - [TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */ - .name = "Temic PAL_DK (4016 FY5)", - .params = tuner_temic_pal_dk_params, - .count = ARRAY_SIZE(tuner_temic_pal_dk_params), - }, - [TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */ - .name = "Philips NTSC_M (MK2)", - .params = tuner_philips_ntsc_m_params, - .count = ARRAY_SIZE(tuner_philips_ntsc_m_params), - }, - [TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */ - .name = "Temic PAL_I (4066 FY5)", - .params = tuner_temic_4066fy5_pal_i_params, - .count = ARRAY_SIZE(tuner_temic_4066fy5_pal_i_params), - }, - [TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */ - .name = "Temic PAL* auto (4006 FN5)", - .params = tuner_temic_4006fn5_multi_params, - .count = ARRAY_SIZE(tuner_temic_4006fn5_multi_params), - }, - - /* 20-29 */ - [TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */ - .name = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", - .params = tuner_temic_4009f_5_params, - .count = ARRAY_SIZE(tuner_temic_4009f_5_params), - }, - [TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */ - .name = "Temic NTSC (4039 FR5)", - .params = tuner_temic_4039fr5_params, - .count = ARRAY_SIZE(tuner_temic_4039fr5_params), - }, - [TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */ - .name = "Temic PAL/SECAM multi (4046 FM5)", - .params = tuner_temic_4046fm5_params, - .count = ARRAY_SIZE(tuner_temic_4046fm5_params), - }, - [TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */ - .name = "Philips PAL_DK (FI1256 and compatibles)", - .params = tuner_philips_pal_dk_params, - .count = ARRAY_SIZE(tuner_philips_pal_dk_params), - }, - [TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */ - .name = "Philips PAL/SECAM multi (FQ1216ME)", - .params = tuner_philips_fq1216me_params, - .count = ARRAY_SIZE(tuner_philips_fq1216me_params), - }, - [TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */ - .name = "LG PAL_I+FM (TAPC-I001D)", - .params = tuner_lg_pal_i_fm_params, - .count = ARRAY_SIZE(tuner_lg_pal_i_fm_params), - }, - [TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */ - .name = "LG PAL_I (TAPC-I701D)", - .params = tuner_lg_pal_i_params, - .count = ARRAY_SIZE(tuner_lg_pal_i_params), - }, - [TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */ - .name = "LG NTSC+FM (TPI8NSR01F)", - .params = tuner_lg_ntsc_fm_params, - .count = ARRAY_SIZE(tuner_lg_ntsc_fm_params), - }, - [TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */ - .name = "LG PAL_BG+FM (TPI8PSB01D)", - .params = tuner_lg_pal_fm_params, - .count = ARRAY_SIZE(tuner_lg_pal_fm_params), - }, - [TUNER_LG_PAL] = { /* LGINNOTEK PAL */ - .name = "LG PAL_BG (TPI8PSB11D)", - .params = tuner_lg_pal_params, - .count = ARRAY_SIZE(tuner_lg_pal_params), - }, - - /* 30-39 */ - [TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */ - .name = "Temic PAL* auto + FM (4009 FN5)", - .params = tuner_temic_4009_fn5_multi_pal_fm_params, - .count = ARRAY_SIZE(tuner_temic_4009_fn5_multi_pal_fm_params), - }, - [TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */ - .name = "SHARP NTSC_JP (2U5JF5540)", - .params = tuner_sharp_2u5jf5540_params, - .count = ARRAY_SIZE(tuner_sharp_2u5jf5540_params), - }, - [TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */ - .name = "Samsung PAL TCPM9091PD27", - .params = tuner_samsung_pal_tcpm9091pd27_params, - .count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_params), - }, - [TUNER_MT2032] = { /* Microtune PAL|NTSC */ - .name = "MT20xx universal", - /* see mt20xx.c for details */ }, - [TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */ - .name = "Temic PAL_BG (4106 FH5)", - .params = tuner_temic_4106fh5_params, - .count = ARRAY_SIZE(tuner_temic_4106fh5_params), - }, - [TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */ - .name = "Temic PAL_DK/SECAM_L (4012 FY5)", - .params = tuner_temic_4012fy5_params, - .count = ARRAY_SIZE(tuner_temic_4012fy5_params), - }, - [TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */ - .name = "Temic NTSC (4136 FY5)", - .params = tuner_temic_4136_fy5_params, - .count = ARRAY_SIZE(tuner_temic_4136_fy5_params), - }, - [TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */ - .name = "LG PAL (newer TAPC series)", - .params = tuner_lg_pal_new_tapc_params, - .count = ARRAY_SIZE(tuner_lg_pal_new_tapc_params), - }, - [TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */ - .name = "Philips PAL/SECAM multi (FM1216ME MK3)", - .params = tuner_fm1216me_mk3_params, - .count = ARRAY_SIZE(tuner_fm1216me_mk3_params), - }, - [TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */ - .name = "LG NTSC (newer TAPC series)", - .params = tuner_lg_ntsc_new_tapc_params, - .count = ARRAY_SIZE(tuner_lg_ntsc_new_tapc_params), - }, - - /* 40-49 */ - [TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */ - .name = "HITACHI V7-J180AT", - .params = tuner_hitachi_ntsc_params, - .count = ARRAY_SIZE(tuner_hitachi_ntsc_params), - }, - [TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */ - .name = "Philips PAL_MK (FI1216 MK)", - .params = tuner_philips_pal_mk_params, - .count = ARRAY_SIZE(tuner_philips_pal_mk_params), - }, - [TUNER_PHILIPS_FCV1236D] = { /* Philips ATSC */ - .name = "Philips FCV1236D ATSC/NTSC dual in", - .params = tuner_philips_fcv1236d_params, - .count = ARRAY_SIZE(tuner_philips_fcv1236d_params), - .min = 16 * 53.00, - .max = 16 * 803.00, - .stepsize = 62500, - }, - [TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */ - .name = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", - .params = tuner_fm1236_mk3_params, - .count = ARRAY_SIZE(tuner_fm1236_mk3_params), - }, - [TUNER_PHILIPS_4IN1] = { /* Philips NTSC */ - .name = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", - .params = tuner_philips_4in1_params, - .count = ARRAY_SIZE(tuner_philips_4in1_params), - }, - [TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */ - .name = "Microtune 4049 FM5", - .params = tuner_microtune_4049_fm5_params, - .count = ARRAY_SIZE(tuner_microtune_4049_fm5_params), - }, - [TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */ - .name = "Panasonic VP27s/ENGE4324D", - .params = tuner_panasonic_vp27_params, - .count = ARRAY_SIZE(tuner_panasonic_vp27_params), - }, - [TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */ - .name = "LG NTSC (TAPE series)", - .params = tuner_fm1236_mk3_params, - .count = ARRAY_SIZE(tuner_fm1236_mk3_params), - }, - [TUNER_TNF_8831BGFF] = { /* Philips PAL */ - .name = "Tenna TNF 8831 BGFF)", - .params = tuner_tnf_8831bgff_params, - .count = ARRAY_SIZE(tuner_tnf_8831bgff_params), - }, - [TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */ - .name = "Microtune 4042 FI5 ATSC/NTSC dual in", - .params = tuner_microtune_4042fi5_params, - .count = ARRAY_SIZE(tuner_microtune_4042fi5_params), - .min = 16 * 57.00, - .max = 16 * 858.00, - .stepsize = 62500, - }, - - /* 50-59 */ - [TUNER_TCL_2002N] = { /* TCL NTSC */ - .name = "TCL 2002N", - .params = tuner_tcl_2002n_params, - .count = ARRAY_SIZE(tuner_tcl_2002n_params), - }, - [TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */ - .name = "Philips PAL/SECAM_D (FM 1256 I-H3)", - .params = tuner_philips_fm1256_ih3_params, - .count = ARRAY_SIZE(tuner_philips_fm1256_ih3_params), - }, - [TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */ - .name = "Thomson DTT 7610 (ATSC/NTSC)", - .params = tuner_thomson_dtt7610_params, - .count = ARRAY_SIZE(tuner_thomson_dtt7610_params), - .min = 16 * 44.00, - .max = 16 * 958.00, - .stepsize = 62500, - }, - [TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */ - .name = "Philips FQ1286", - .params = tuner_philips_fq1286_params, - .count = ARRAY_SIZE(tuner_philips_fq1286_params), - }, - [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */ - .name = "Philips/NXP TDA 8290/8295 + 8275/8275A/18271", - /* see tda8290.c for details */ }, - [TUNER_TCL_2002MB] = { /* TCL PAL */ - .name = "TCL 2002MB", - .params = tuner_tcl_2002mb_params, - .count = ARRAY_SIZE(tuner_tcl_2002mb_params), - }, - [TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */ - .name = "Philips PAL/SECAM multi (FQ1216AME MK4)", - .params = tuner_philips_fq1216ame_mk4_params, - .count = ARRAY_SIZE(tuner_philips_fq1216ame_mk4_params), - }, - [TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */ - .name = "Philips FQ1236A MK4", - .params = tuner_philips_fq1236a_mk4_params, - .count = ARRAY_SIZE(tuner_philips_fq1236a_mk4_params), - }, - [TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */ - .name = "Ymec TVision TVF-8531MF/8831MF/8731MF", - .params = tuner_ymec_tvf_8531mf_params, - .count = ARRAY_SIZE(tuner_ymec_tvf_8531mf_params), - }, - [TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */ - .name = "Ymec TVision TVF-5533MF", - .params = tuner_ymec_tvf_5533mf_params, - .count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_params), - }, - - /* 60-69 */ - [TUNER_THOMSON_DTT761X] = { /* THOMSON ATSC */ - /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ - .name = "Thomson DTT 761X (ATSC/NTSC)", - .params = tuner_thomson_dtt761x_params, - .count = ARRAY_SIZE(tuner_thomson_dtt761x_params), - .min = 16 * 57.00, - .max = 16 * 863.00, - .stepsize = 62500, - .initdata = tua603x_agc103, - }, - [TUNER_TENA_9533_DI] = { /* Philips PAL */ - .name = "Tena TNF9533-D/IF/TNF9533-B/DF", - .params = tuner_tena_9533_di_params, - .count = ARRAY_SIZE(tuner_tena_9533_di_params), - }, - [TUNER_TEA5767] = { /* Philips RADIO */ - .name = "Philips TEA5767HN FM Radio", - /* see tea5767.c for details */ - }, - [TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */ - .name = "Philips FMD1216ME MK3 Hybrid Tuner", - .params = tuner_philips_fmd1216me_mk3_params, - .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params), - .min = 16 * 50.87, - .max = 16 * 858.00, - .stepsize = 166667, - .initdata = tua603x_agc112, - .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 }, - }, - [TUNER_LG_TDVS_H06XF] = { /* LGINNOTEK ATSC */ - .name = "LG TDVS-H06xF", /* H061F, H062F & H064F */ - .params = tuner_lg_tdvs_h06xf_params, - .count = ARRAY_SIZE(tuner_lg_tdvs_h06xf_params), - .min = 16 * 54.00, - .max = 16 * 863.00, - .stepsize = 62500, - .initdata = tua603x_agc103, - }, - [TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */ - .name = "Ymec TVF66T5-B/DFF", - .params = tuner_ymec_tvf66t5_b_dff_params, - .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_params), - }, - [TUNER_LG_TALN] = { /* LGINNOTEK NTSC / PAL / SECAM */ - .name = "LG TALN series", - .params = tuner_lg_taln_params, - .count = ARRAY_SIZE(tuner_lg_taln_params), - }, - [TUNER_PHILIPS_TD1316] = { /* Philips PAL */ - .name = "Philips TD1316 Hybrid Tuner", - .params = tuner_philips_td1316_params, - .count = ARRAY_SIZE(tuner_philips_td1316_params), - .min = 16 * 87.00, - .max = 16 * 895.00, - .stepsize = 166667, - }, - [TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */ - .name = "Philips TUV1236D ATSC/NTSC dual in", - .params = tuner_tuv1236d_params, - .count = ARRAY_SIZE(tuner_tuv1236d_params), - .min = 16 * 54.00, - .max = 16 * 864.00, - .stepsize = 62500, - }, - [TUNER_TNF_5335MF] = { /* Tenna PAL/NTSC */ - .name = "Tena TNF 5335 and similar models", - .params = tuner_tnf_5335mf_params, - .count = ARRAY_SIZE(tuner_tnf_5335mf_params), - }, - - /* 70-79 */ - [TUNER_SAMSUNG_TCPN_2121P30A] = { /* Samsung NTSC */ - .name = "Samsung TCPN 2121P30A", - .params = tuner_samsung_tcpn_2121p30a_params, - .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params), - }, - [TUNER_XC2028] = { /* Xceive 2028 */ - .name = "Xceive xc2028/xc3028 tuner", - /* see tuner-xc2028.c for details */ - }, - [TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */ - .name = "Thomson FE6600", - .params = tuner_thomson_fe6600_params, - .count = ARRAY_SIZE(tuner_thomson_fe6600_params), - .min = 16 * 44.25, - .max = 16 * 858.00, - .stepsize = 166667, - }, - [TUNER_SAMSUNG_TCPG_6121P30A] = { /* Samsung PAL */ - .name = "Samsung TCPG 6121P30A", - .params = tuner_samsung_tcpg_6121p30a_params, - .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_params), - }, - [TUNER_TDA9887] = { /* Philips TDA 9887 IF PLL Demodulator. - This chip is part of some modern tuners */ - .name = "Philips TDA988[5,6,7] IF PLL Demodulator", - /* see tda9887.c for details */ - }, - [TUNER_TEA5761] = { /* Philips RADIO */ - .name = "Philips TEA5761 FM Radio", - /* see tea5767.c for details */ - }, - [TUNER_XC5000] = { /* Xceive 5000 */ - .name = "Xceive 5000 tuner", - /* see xc5000.c for details */ - }, - [TUNER_XC4000] = { /* Xceive 4000 */ - .name = "Xceive 4000 tuner", - /* see xc4000.c for details */ - }, - [TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */ - .name = "TCL tuner MF02GIP-5N-E", - .params = tuner_tcl_mf02gip_5n_params, - .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params), - }, - [TUNER_PHILIPS_FMD1216MEX_MK3] = { /* Philips PAL */ - .name = "Philips FMD1216MEX MK3 Hybrid Tuner", - .params = tuner_philips_fmd1216mex_mk3_params, - .count = ARRAY_SIZE(tuner_philips_fmd1216mex_mk3_params), - .min = 16 * 50.87, - .max = 16 * 858.00, - .stepsize = 166667, - .initdata = tua603x_agc112, - .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 }, - }, - [TUNER_PHILIPS_FM1216MK5] = { /* Philips PAL */ - .name = "Philips PAL/SECAM multi (FM1216 MK5)", - .params = tuner_fm1216mk5_params, - .count = ARRAY_SIZE(tuner_fm1216mk5_params), - }, - - /* 80-89 */ - [TUNER_PHILIPS_FQ1216LME_MK3] = { /* PAL/SECAM, Loop-thru, no FM */ - .name = "Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough", - .params = tuner_fq1216lme_mk3_params, - .count = ARRAY_SIZE(tuner_fq1216lme_mk3_params), - }, - - [TUNER_PARTSNIC_PTI_5NF05] = { - .name = "Partsnic (Daewoo) PTI-5NF05", - .params = tuner_partsnic_pti_5nf05_params, - .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_params), - }, - [TUNER_PHILIPS_CU1216L] = { - .name = "Philips CU1216L", - .params = tuner_philips_cu1216l_params, - .count = ARRAY_SIZE(tuner_philips_cu1216l_params), - .stepsize = 62500, - }, - [TUNER_NXP_TDA18271] = { - .name = "NXP TDA18271", - /* see tda18271-fe.c for details */ - }, - [TUNER_SONY_BTF_PXN01Z] = { - .name = "Sony BTF-Pxn01Z", - .params = tuner_sony_btf_pxn01z_params, - .count = ARRAY_SIZE(tuner_sony_btf_pxn01z_params), - }, - [TUNER_PHILIPS_FQ1236_MK5] = { /* NTSC, TDA9885, no FM radio */ - .name = "Philips FQ1236 MK5", - .params = tuner_philips_fq1236_mk5_params, - .count = ARRAY_SIZE(tuner_philips_fq1236_mk5_params), - }, - [TUNER_TENA_TNF_5337] = { /* Tena 5337 MFD */ - .name = "Tena TNF5337 MFD", - .params = tuner_tena_tnf_5337_params, - .count = ARRAY_SIZE(tuner_tena_tnf_5337_params), - }, - [TUNER_XC5000C] = { /* Xceive 5000C */ - .name = "Xceive 5000C tuner", - /* see xc5000.c for details */ - }, -}; -EXPORT_SYMBOL(tuners); - -unsigned const int tuner_count = ARRAY_SIZE(tuners); -EXPORT_SYMBOL(tuner_count); - -MODULE_DESCRIPTION("Simple tuner device type database"); -MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/tuner-xc2028-types.h b/drivers/media/common/tuners/tuner-xc2028-types.h deleted file mode 100644 index 74dc46a71f64..000000000000 --- a/drivers/media/common/tuners/tuner-xc2028-types.h +++ /dev/null @@ -1,141 +0,0 @@ -/* tuner-xc2028_types - * - * This file includes internal tipes to be used inside tuner-xc2028. - * Shouldn't be included outside tuner-xc2028 - * - * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License v2 - */ - -/* xc3028 firmware types */ - -/* BASE firmware should be loaded before any other firmware */ -#define BASE (1<<0) -#define BASE_TYPES (BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1) - -/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */ -#define F8MHZ (1<<1) - -/* Multichannel Television Sound (MTS) - Those firmwares are capable of using xc2038 DSP to decode audio and - produce a baseband audio output on some pins of the chip. - There are MTS firmwares for the most used video standards. It should be - required to use MTS firmwares, depending on the way audio is routed into - the bridge chip - */ -#define MTS (1<<2) - -/* FIXME: I have no idea what's the difference between - D2620 and D2633 firmwares - */ -#define D2620 (1<<3) -#define D2633 (1<<4) - -/* DTV firmwares for 6, 7 and 8 MHz - DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS - DTV8 - 8MHz - DVB-C/DVB-T - */ -#define DTV6 (1 << 5) -#define QAM (1 << 6) -#define DTV7 (1<<7) -#define DTV78 (1<<8) -#define DTV8 (1<<9) - -#define DTV_TYPES (D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC) - -/* There's a FM | BASE firmware + FM specific firmware (std=0) */ -#define FM (1<<10) - -#define STD_SPECIFIC_TYPES (MTS|FM|LCD|NOGD) - -/* Applies only for FM firmware - Makes it use RF input 1 (pin #2) instead of input 2 (pin #4) - */ -#define INPUT1 (1<<11) - - -/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M) - and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) - There are variants both with and without NOGD - Those firmwares produce better result with LCD displays - */ -#define LCD (1<<12) - -/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M) - and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) - The NOGD firmwares don't have group delay compensation filter - */ -#define NOGD (1<<13) - -/* Old firmwares were broken into init0 and init1 */ -#define INIT1 (1<<14) - -/* SCODE firmware selects particular behaviours */ -#define MONO (1 << 15) -#define ATSC (1 << 16) -#define IF (1 << 17) -#define LG60 (1 << 18) -#define ATI638 (1 << 19) -#define OREN538 (1 << 20) -#define OREN36 (1 << 21) -#define TOYOTA388 (1 << 22) -#define TOYOTA794 (1 << 23) -#define DIBCOM52 (1 << 24) -#define ZARLINK456 (1 << 25) -#define CHINA (1 << 26) -#define F6MHZ (1 << 27) -#define INPUT2 (1 << 28) -#define SCODE (1 << 29) - -/* This flag identifies that the scode table has a new format */ -#define HAS_IF (1 << 30) - -/* There are different scode tables for MTS and non-MTS. - The MTS firmwares support mono only - */ -#define SCODE_TYPES (SCODE | MTS) - - -/* Newer types not defined on videodev2.h. - The original idea were to move all those types to videodev2.h, but - it seemed overkill, since, with the exception of SECAM/K3, the other - types seem to be autodetected. - It is not clear where secam/k3 is used, nor we have a feedback of this - working or being autodetected by the standard secam firmware. - */ - -#define V4L2_STD_SECAM_K3 (0x04000000) - -/* Audio types */ - -#define V4L2_STD_A2_A (1LL<<32) -#define V4L2_STD_A2_B (1LL<<33) -#define V4L2_STD_NICAM_A (1LL<<34) -#define V4L2_STD_NICAM_B (1LL<<35) -#define V4L2_STD_AM (1LL<<36) -#define V4L2_STD_BTSC (1LL<<37) -#define V4L2_STD_EIAJ (1LL<<38) - -#define V4L2_STD_A2 (V4L2_STD_A2_A | V4L2_STD_A2_B) -#define V4L2_STD_NICAM (V4L2_STD_NICAM_A | V4L2_STD_NICAM_B) - -/* To preserve backward compatibilty, - (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported - */ - -#define V4L2_STD_AUDIO (V4L2_STD_A2 | \ - V4L2_STD_NICAM | \ - V4L2_STD_AM | \ - V4L2_STD_BTSC | \ - V4L2_STD_EIAJ) - -/* Used standards with audio restrictions */ - -#define V4L2_STD_PAL_BG_A2_A (V4L2_STD_PAL_BG | V4L2_STD_A2_A) -#define V4L2_STD_PAL_BG_A2_B (V4L2_STD_PAL_BG | V4L2_STD_A2_B) -#define V4L2_STD_PAL_BG_NICAM_A (V4L2_STD_PAL_BG | V4L2_STD_NICAM_A) -#define V4L2_STD_PAL_BG_NICAM_B (V4L2_STD_PAL_BG | V4L2_STD_NICAM_B) -#define V4L2_STD_PAL_DK_A2 (V4L2_STD_PAL_DK | V4L2_STD_A2) -#define V4L2_STD_PAL_DK_NICAM (V4L2_STD_PAL_DK | V4L2_STD_NICAM) -#define V4L2_STD_SECAM_L_NICAM (V4L2_STD_SECAM_L | V4L2_STD_NICAM) -#define V4L2_STD_SECAM_L_AM (V4L2_STD_SECAM_L | V4L2_STD_AM) diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c deleted file mode 100644 index 7bcb6b0ff1df..000000000000 --- a/drivers/media/common/tuners/tuner-xc2028.c +++ /dev/null @@ -1,1509 +0,0 @@ -/* tuner-xc2028 - * - * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) - * - * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com) - * - frontend interface - * - * This code is placed under the terms of the GNU General Public License v2 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "tuner-i2c.h" -#include "tuner-xc2028.h" -#include "tuner-xc2028-types.h" - -#include -#include "dvb_frontend.h" - -/* Registers (Write-only) */ -#define XREG_INIT 0x00 -#define XREG_RF_FREQ 0x02 -#define XREG_POWER_DOWN 0x08 - -/* Registers (Read-only) */ -#define XREG_FREQ_ERROR 0x01 -#define XREG_LOCK 0x02 -#define XREG_VERSION 0x04 -#define XREG_PRODUCT_ID 0x08 -#define XREG_HSYNC_FREQ 0x10 -#define XREG_FRAME_LINES 0x20 -#define XREG_SNR 0x40 - -#define XREG_ADC_ENV 0x0100 - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -static int no_poweroff; -module_param(no_poweroff, int, 0644); -MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" - "1 keep device energized and with tuner ready all the times.\n" - " Faster, but consumes more power and keeps the device hotter\n"); - -static char audio_std[8]; -module_param_string(audio_std, audio_std, sizeof(audio_std), 0); -MODULE_PARM_DESC(audio_std, - "Audio standard. XC3028 audio decoder explicitly " - "needs to know what audio\n" - "standard is needed for some video standards with audio A2 or NICAM.\n" - "The valid values are:\n" - "A2\n" - "A2/A\n" - "A2/B\n" - "NICAM\n" - "NICAM/A\n" - "NICAM/B\n"); - -static char firmware_name[30]; -module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); -MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the " - "default firmware name\n"); - -static LIST_HEAD(hybrid_tuner_instance_list); -static DEFINE_MUTEX(xc2028_list_mutex); - -/* struct for storing firmware table */ -struct firmware_description { - unsigned int type; - v4l2_std_id id; - __u16 int_freq; - unsigned char *ptr; - unsigned int size; -}; - -struct firmware_properties { - unsigned int type; - v4l2_std_id id; - v4l2_std_id std_req; - __u16 int_freq; - unsigned int scode_table; - int scode_nr; -}; - -enum xc2028_state { - XC2028_NO_FIRMWARE = 0, - XC2028_WAITING_FIRMWARE, - XC2028_ACTIVE, - XC2028_SLEEP, - XC2028_NODEV, -}; - -struct xc2028_data { - struct list_head hybrid_tuner_instance_list; - struct tuner_i2c_props i2c_props; - __u32 frequency; - - enum xc2028_state state; - const char *fname; - - struct firmware_description *firm; - int firm_size; - __u16 firm_version; - - __u16 hwmodel; - __u16 hwvers; - - struct xc2028_ctrl ctrl; - - struct firmware_properties cur_fw; - - struct mutex lock; -}; - -#define i2c_send(priv, buf, size) ({ \ - int _rc; \ - _rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \ - if (size != _rc) \ - tuner_info("i2c output error: rc = %d (should be %d)\n",\ - _rc, (int)size); \ - if (priv->ctrl.msleep) \ - msleep(priv->ctrl.msleep); \ - _rc; \ -}) - -#define i2c_rcv(priv, buf, size) ({ \ - int _rc; \ - _rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \ - if (size != _rc) \ - tuner_err("i2c input error: rc = %d (should be %d)\n", \ - _rc, (int)size); \ - _rc; \ -}) - -#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \ - int _rc; \ - _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \ - ibuf, isize); \ - if (isize != _rc) \ - tuner_err("i2c input error: rc = %d (should be %d)\n", \ - _rc, (int)isize); \ - if (priv->ctrl.msleep) \ - msleep(priv->ctrl.msleep); \ - _rc; \ -}) - -#define send_seq(priv, data...) ({ \ - static u8 _val[] = data; \ - int _rc; \ - if (sizeof(_val) != \ - (_rc = tuner_i2c_xfer_send(&priv->i2c_props, \ - _val, sizeof(_val)))) { \ - tuner_err("Error on line %d: %d\n", __LINE__, _rc); \ - } else if (priv->ctrl.msleep) \ - msleep(priv->ctrl.msleep); \ - _rc; \ -}) - -static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) -{ - unsigned char buf[2]; - unsigned char ibuf[2]; - - tuner_dbg("%s %04x called\n", __func__, reg); - - buf[0] = reg >> 8; - buf[1] = (unsigned char) reg; - - if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2) - return -EIO; - - *val = (ibuf[1]) | (ibuf[0] << 8); - return 0; -} - -#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) -static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) -{ - if (type & BASE) - printk("BASE "); - if (type & INIT1) - printk("INIT1 "); - if (type & F8MHZ) - printk("F8MHZ "); - if (type & MTS) - printk("MTS "); - if (type & D2620) - printk("D2620 "); - if (type & D2633) - printk("D2633 "); - if (type & DTV6) - printk("DTV6 "); - if (type & QAM) - printk("QAM "); - if (type & DTV7) - printk("DTV7 "); - if (type & DTV78) - printk("DTV78 "); - if (type & DTV8) - printk("DTV8 "); - if (type & FM) - printk("FM "); - if (type & INPUT1) - printk("INPUT1 "); - if (type & LCD) - printk("LCD "); - if (type & NOGD) - printk("NOGD "); - if (type & MONO) - printk("MONO "); - if (type & ATSC) - printk("ATSC "); - if (type & IF) - printk("IF "); - if (type & LG60) - printk("LG60 "); - if (type & ATI638) - printk("ATI638 "); - if (type & OREN538) - printk("OREN538 "); - if (type & OREN36) - printk("OREN36 "); - if (type & TOYOTA388) - printk("TOYOTA388 "); - if (type & TOYOTA794) - printk("TOYOTA794 "); - if (type & DIBCOM52) - printk("DIBCOM52 "); - if (type & ZARLINK456) - printk("ZARLINK456 "); - if (type & CHINA) - printk("CHINA "); - if (type & F6MHZ) - printk("F6MHZ "); - if (type & INPUT2) - printk("INPUT2 "); - if (type & SCODE) - printk("SCODE "); - if (type & HAS_IF) - printk("HAS_IF_%d ", int_freq); -} - -static v4l2_std_id parse_audio_std_option(void) -{ - if (strcasecmp(audio_std, "A2") == 0) - return V4L2_STD_A2; - if (strcasecmp(audio_std, "A2/A") == 0) - return V4L2_STD_A2_A; - if (strcasecmp(audio_std, "A2/B") == 0) - return V4L2_STD_A2_B; - if (strcasecmp(audio_std, "NICAM") == 0) - return V4L2_STD_NICAM; - if (strcasecmp(audio_std, "NICAM/A") == 0) - return V4L2_STD_NICAM_A; - if (strcasecmp(audio_std, "NICAM/B") == 0) - return V4L2_STD_NICAM_B; - - return 0; -} - -static int check_device_status(struct xc2028_data *priv) -{ - switch (priv->state) { - case XC2028_NO_FIRMWARE: - case XC2028_WAITING_FIRMWARE: - return -EAGAIN; - case XC2028_ACTIVE: - case XC2028_SLEEP: - return 0; - case XC2028_NODEV: - return -ENODEV; - } - return 0; -} - -static void free_firmware(struct xc2028_data *priv) -{ - int i; - tuner_dbg("%s called\n", __func__); - - if (!priv->firm) - return; - - for (i = 0; i < priv->firm_size; i++) - kfree(priv->firm[i].ptr); - - kfree(priv->firm); - - priv->firm = NULL; - priv->firm_size = 0; - priv->state = XC2028_NO_FIRMWARE; - - memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); -} - -static int load_all_firmwares(struct dvb_frontend *fe, - const struct firmware *fw) -{ - struct xc2028_data *priv = fe->tuner_priv; - const unsigned char *p, *endp; - int rc = 0; - int n, n_array; - char name[33]; - - tuner_dbg("%s called\n", __func__); - - p = fw->data; - endp = p + fw->size; - - if (fw->size < sizeof(name) - 1 + 2 + 2) { - tuner_err("Error: firmware file %s has invalid size!\n", - priv->fname); - goto corrupt; - } - - memcpy(name, p, sizeof(name) - 1); - name[sizeof(name) - 1] = 0; - p += sizeof(name) - 1; - - priv->firm_version = get_unaligned_le16(p); - p += 2; - - n_array = get_unaligned_le16(p); - p += 2; - - tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n", - n_array, priv->fname, name, - priv->firm_version >> 8, priv->firm_version & 0xff); - - priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL); - if (priv->firm == NULL) { - tuner_err("Not enough memory to load firmware file.\n"); - rc = -ENOMEM; - goto err; - } - priv->firm_size = n_array; - - n = -1; - while (p < endp) { - __u32 type, size; - v4l2_std_id id; - __u16 int_freq = 0; - - n++; - if (n >= n_array) { - tuner_err("More firmware images in file than " - "were expected!\n"); - goto corrupt; - } - - /* Checks if there's enough bytes to read */ - if (endp - p < sizeof(type) + sizeof(id) + sizeof(size)) - goto header; - - type = get_unaligned_le32(p); - p += sizeof(type); - - id = get_unaligned_le64(p); - p += sizeof(id); - - if (type & HAS_IF) { - int_freq = get_unaligned_le16(p); - p += sizeof(int_freq); - if (endp - p < sizeof(size)) - goto header; - } - - size = get_unaligned_le32(p); - p += sizeof(size); - - if (!size || size > endp - p) { - tuner_err("Firmware type "); - dump_firm_type(type); - printk("(%x), id %llx is corrupted " - "(size=%d, expected %d)\n", - type, (unsigned long long)id, - (unsigned)(endp - p), size); - goto corrupt; - } - - priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); - if (priv->firm[n].ptr == NULL) { - tuner_err("Not enough memory to load firmware file.\n"); - rc = -ENOMEM; - goto err; - } - tuner_dbg("Reading firmware type "); - if (debug) { - dump_firm_type_and_int_freq(type, int_freq); - printk("(%x), id %llx, size=%d.\n", - type, (unsigned long long)id, size); - } - - memcpy(priv->firm[n].ptr, p, size); - priv->firm[n].type = type; - priv->firm[n].id = id; - priv->firm[n].size = size; - priv->firm[n].int_freq = int_freq; - - p += size; - } - - if (n + 1 != priv->firm_size) { - tuner_err("Firmware file is incomplete!\n"); - goto corrupt; - } - - goto done; - -header: - tuner_err("Firmware header is incomplete!\n"); -corrupt: - rc = -EINVAL; - tuner_err("Error: firmware file is corrupted!\n"); - -err: - tuner_info("Releasing partially loaded firmware file.\n"); - free_firmware(priv); - -done: - if (rc == 0) - tuner_dbg("Firmware files loaded.\n"); - else - priv->state = XC2028_NODEV; - - return rc; -} - -static int seek_firmware(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id *id) -{ - struct xc2028_data *priv = fe->tuner_priv; - int i, best_i = -1, best_nr_matches = 0; - unsigned int type_mask = 0; - - tuner_dbg("%s called, want type=", __func__); - if (debug) { - dump_firm_type(type); - printk("(%x), id %016llx.\n", type, (unsigned long long)*id); - } - - if (!priv->firm) { - tuner_err("Error! firmware not loaded\n"); - return -EINVAL; - } - - if (((type & ~SCODE) == 0) && (*id == 0)) - *id = V4L2_STD_PAL; - - if (type & BASE) - type_mask = BASE_TYPES; - else if (type & SCODE) { - type &= SCODE_TYPES; - type_mask = SCODE_TYPES & ~HAS_IF; - } else if (type & DTV_TYPES) - type_mask = DTV_TYPES; - else if (type & STD_SPECIFIC_TYPES) - type_mask = STD_SPECIFIC_TYPES; - - type &= type_mask; - - if (!(type & SCODE)) - type_mask = ~0; - - /* Seek for exact match */ - for (i = 0; i < priv->firm_size; i++) { - if ((type == (priv->firm[i].type & type_mask)) && - (*id == priv->firm[i].id)) - goto found; - } - - /* Seek for generic video standard match */ - for (i = 0; i < priv->firm_size; i++) { - v4l2_std_id match_mask; - int nr_matches; - - if (type != (priv->firm[i].type & type_mask)) - continue; - - match_mask = *id & priv->firm[i].id; - if (!match_mask) - continue; - - if ((*id & match_mask) == *id) - goto found; /* Supports all the requested standards */ - - nr_matches = hweight64(match_mask); - if (nr_matches > best_nr_matches) { - best_nr_matches = nr_matches; - best_i = i; - } - } - - if (best_nr_matches > 0) { - tuner_dbg("Selecting best matching firmware (%d bits) for " - "type=", best_nr_matches); - dump_firm_type(type); - printk("(%x), id %016llx:\n", type, (unsigned long long)*id); - i = best_i; - goto found; - } - - /*FIXME: Would make sense to seek for type "hint" match ? */ - - i = -ENOENT; - goto ret; - -found: - *id = priv->firm[i].id; - -ret: - tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found"); - if (debug) { - dump_firm_type(type); - printk("(%x), id %016llx.\n", type, (unsigned long long)*id); - } - return i; -} - -static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg) -{ - struct xc2028_data *priv = fe->tuner_priv; - - /* analog side (tuner-core) uses i2c_adap->algo_data. - * digital side is not guaranteed to have algo_data defined. - * - * digital side will always have fe->dvb defined. - * analog side (tuner-core) doesn't (yet) define fe->dvb. - */ - - return (!fe->callback) ? -EINVAL : - fe->callback(((fe->dvb) && (fe->dvb->priv)) ? - fe->dvb->priv : priv->i2c_props.adap->algo_data, - DVB_FRONTEND_COMPONENT_TUNER, cmd, arg); -} - -static int load_firmware(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id *id) -{ - struct xc2028_data *priv = fe->tuner_priv; - int pos, rc; - unsigned char *p, *endp, buf[priv->ctrl.max_len]; - - tuner_dbg("%s called\n", __func__); - - pos = seek_firmware(fe, type, id); - if (pos < 0) - return pos; - - tuner_info("Loading firmware for type="); - dump_firm_type(priv->firm[pos].type); - printk("(%x), id %016llx.\n", priv->firm[pos].type, - (unsigned long long)*id); - - p = priv->firm[pos].ptr; - endp = p + priv->firm[pos].size; - - while (p < endp) { - __u16 size; - - /* Checks if there's enough bytes to read */ - if (p + sizeof(size) > endp) { - tuner_err("Firmware chunk size is wrong\n"); - return -EINVAL; - } - - size = le16_to_cpu(*(__u16 *) p); - p += sizeof(size); - - if (size == 0xffff) - return 0; - - if (!size) { - /* Special callback command received */ - rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0); - if (rc < 0) { - tuner_err("Error at RESET code %d\n", - (*p) & 0x7f); - return -EINVAL; - } - continue; - } - if (size >= 0xff00) { - switch (size) { - case 0xff00: - rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0); - if (rc < 0) { - tuner_err("Error at RESET code %d\n", - (*p) & 0x7f); - return -EINVAL; - } - break; - default: - tuner_info("Invalid RESET code %d\n", - size & 0x7f); - return -EINVAL; - - } - continue; - } - - /* Checks for a sleep command */ - if (size & 0x8000) { - msleep(size & 0x7fff); - continue; - } - - if ((size + p > endp)) { - tuner_err("missing bytes: need %d, have %d\n", - size, (int)(endp - p)); - return -EINVAL; - } - - buf[0] = *p; - p++; - size--; - - /* Sends message chunks */ - while (size > 0) { - int len = (size < priv->ctrl.max_len - 1) ? - size : priv->ctrl.max_len - 1; - - memcpy(buf + 1, p, len); - - rc = i2c_send(priv, buf, len + 1); - if (rc < 0) { - tuner_err("%d returned from send\n", rc); - return -EINVAL; - } - - p += len; - size -= len; - } - - /* silently fail if the frontend doesn't support I2C flush */ - rc = do_tuner_callback(fe, XC2028_I2C_FLUSH, 0); - if ((rc < 0) && (rc != -EINVAL)) { - tuner_err("error executing flush: %d\n", rc); - return rc; - } - } - return 0; -} - -static int load_scode(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id *id, __u16 int_freq, int scode) -{ - struct xc2028_data *priv = fe->tuner_priv; - int pos, rc; - unsigned char *p; - - tuner_dbg("%s called\n", __func__); - - if (!int_freq) { - pos = seek_firmware(fe, type, id); - if (pos < 0) - return pos; - } else { - for (pos = 0; pos < priv->firm_size; pos++) { - if ((priv->firm[pos].int_freq == int_freq) && - (priv->firm[pos].type & HAS_IF)) - break; - } - if (pos == priv->firm_size) - return -ENOENT; - } - - p = priv->firm[pos].ptr; - - if (priv->firm[pos].type & HAS_IF) { - if (priv->firm[pos].size != 12 * 16 || scode >= 16) - return -EINVAL; - p += 12 * scode; - } else { - /* 16 SCODE entries per file; each SCODE entry is 12 bytes and - * has a 2-byte size header in the firmware format. */ - if (priv->firm[pos].size != 14 * 16 || scode >= 16 || - le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12) - return -EINVAL; - p += 14 * scode + 2; - } - - tuner_info("Loading SCODE for type="); - dump_firm_type_and_int_freq(priv->firm[pos].type, - priv->firm[pos].int_freq); - printk("(%x), id %016llx.\n", priv->firm[pos].type, - (unsigned long long)*id); - - if (priv->firm_version < 0x0202) - rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00}); - else - rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00}); - if (rc < 0) - return -EIO; - - rc = i2c_send(priv, p, 12); - if (rc < 0) - return -EIO; - - rc = send_seq(priv, {0x00, 0x8c}); - if (rc < 0) - return -EIO; - - return 0; -} - -static int check_firmware(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id std, __u16 int_freq) -{ - struct xc2028_data *priv = fe->tuner_priv; - struct firmware_properties new_fw; - int rc, retry_count = 0; - u16 version, hwmodel; - v4l2_std_id std0; - - tuner_dbg("%s called\n", __func__); - - rc = check_device_status(priv); - if (rc < 0) - return rc; - - if (priv->ctrl.mts && !(type & FM)) - type |= MTS; - -retry: - new_fw.type = type; - new_fw.id = std; - new_fw.std_req = std; - new_fw.scode_table = SCODE | priv->ctrl.scode_table; - new_fw.scode_nr = 0; - new_fw.int_freq = int_freq; - - tuner_dbg("checking firmware, user requested type="); - if (debug) { - dump_firm_type(new_fw.type); - printk("(%x), id %016llx, ", new_fw.type, - (unsigned long long)new_fw.std_req); - if (!int_freq) { - printk("scode_tbl "); - dump_firm_type(priv->ctrl.scode_table); - printk("(%x), ", priv->ctrl.scode_table); - } else - printk("int_freq %d, ", new_fw.int_freq); - printk("scode_nr %d\n", new_fw.scode_nr); - } - - /* - * No need to reload base firmware if it matches and if the tuner - * is not at sleep mode - */ - if ((priv->state == XC2028_ACTIVE) && - (((BASE | new_fw.type) & BASE_TYPES) == - (priv->cur_fw.type & BASE_TYPES))) { - tuner_dbg("BASE firmware not changed.\n"); - goto skip_base; - } - - /* Updating BASE - forget about all currently loaded firmware */ - memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); - - /* Reset is needed before loading firmware */ - rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0); - if (rc < 0) - goto fail; - - /* BASE firmwares are all std0 */ - std0 = 0; - rc = load_firmware(fe, BASE | new_fw.type, &std0); - if (rc < 0) { - tuner_err("Error %d while loading base firmware\n", - rc); - goto fail; - } - - /* Load INIT1, if needed */ - tuner_dbg("Load init1 firmware, if exists\n"); - - rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0); - if (rc == -ENOENT) - rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ, - &std0); - if (rc < 0 && rc != -ENOENT) { - tuner_err("Error %d while loading init1 firmware\n", - rc); - goto fail; - } - -skip_base: - /* - * No need to reload standard specific firmware if base firmware - * was not reloaded and requested video standards have not changed. - */ - if (priv->cur_fw.type == (BASE | new_fw.type) && - priv->cur_fw.std_req == std) { - tuner_dbg("Std-specific firmware already loaded.\n"); - goto skip_std_specific; - } - - /* Reloading std-specific firmware forces a SCODE update */ - priv->cur_fw.scode_table = 0; - - rc = load_firmware(fe, new_fw.type, &new_fw.id); - if (rc == -ENOENT) - rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id); - - if (rc < 0) - goto fail; - -skip_std_specific: - if (priv->cur_fw.scode_table == new_fw.scode_table && - priv->cur_fw.scode_nr == new_fw.scode_nr) { - tuner_dbg("SCODE firmware already loaded.\n"); - goto check_device; - } - - if (new_fw.type & FM) - goto check_device; - - /* Load SCODE firmware, if exists */ - tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr); - - rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, - new_fw.int_freq, new_fw.scode_nr); - -check_device: - if (xc2028_get_reg(priv, 0x0004, &version) < 0 || - xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) { - tuner_err("Unable to read tuner registers.\n"); - goto fail; - } - - tuner_dbg("Device is Xceive %d version %d.%d, " - "firmware version %d.%d\n", - hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, - (version & 0xf0) >> 4, version & 0xf); - - - if (priv->ctrl.read_not_reliable) - goto read_not_reliable; - - /* Check firmware version against what we downloaded. */ - if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) { - if (!priv->ctrl.read_not_reliable) { - tuner_err("Incorrect readback of firmware version.\n"); - goto fail; - } else { - tuner_err("Returned an incorrect version. However, " - "read is not reliable enough. Ignoring it.\n"); - hwmodel = 3028; - } - } - - /* Check that the tuner hardware model remains consistent over time. */ - if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) { - priv->hwmodel = hwmodel; - priv->hwvers = version & 0xff00; - } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || - priv->hwvers != (version & 0xff00)) { - tuner_err("Read invalid device hardware information - tuner " - "hung?\n"); - goto fail; - } - -read_not_reliable: - memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); - - /* - * By setting BASE in cur_fw.type only after successfully loading all - * firmwares, we can: - * 1. Identify that BASE firmware with type=0 has been loaded; - * 2. Tell whether BASE firmware was just changed the next time through. - */ - priv->cur_fw.type |= BASE; - priv->state = XC2028_ACTIVE; - - return 0; - -fail: - priv->state = XC2028_SLEEP; - - memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); - if (retry_count < 8) { - msleep(50); - retry_count++; - tuner_dbg("Retrying firmware load\n"); - goto retry; - } - - if (rc == -ENOENT) - rc = -EINVAL; - return rc; -} - -static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) -{ - struct xc2028_data *priv = fe->tuner_priv; - u16 frq_lock, signal = 0; - int rc, i; - - tuner_dbg("%s called\n", __func__); - - rc = check_device_status(priv); - if (rc < 0) - return rc; - - mutex_lock(&priv->lock); - - /* Sync Lock Indicator */ - for (i = 0; i < 3; i++) { - rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock); - if (rc < 0) - goto ret; - - if (frq_lock) - break; - msleep(6); - } - - /* Frequency didn't lock */ - if (frq_lock == 2) - goto ret; - - /* Get SNR of the video signal */ - rc = xc2028_get_reg(priv, XREG_SNR, &signal); - if (rc < 0) - goto ret; - - /* Signal level is 3 bits only */ - - signal = ((1 << 12) - 1) | ((signal & 0x07) << 12); - -ret: - mutex_unlock(&priv->lock); - - *strength = signal; - - tuner_dbg("signal strength is %d\n", signal); - - return rc; -} - -static int xc2028_get_afc(struct dvb_frontend *fe, s32 *afc) -{ - struct xc2028_data *priv = fe->tuner_priv; - int i, rc; - u16 frq_lock = 0; - s16 afc_reg = 0; - - rc = check_device_status(priv); - if (rc < 0) - return rc; - - mutex_lock(&priv->lock); - - /* Sync Lock Indicator */ - for (i = 0; i < 3; i++) { - rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock); - if (rc < 0) - goto ret; - - if (frq_lock) - break; - msleep(6); - } - - /* Frequency didn't lock */ - if (frq_lock == 2) - goto ret; - - /* Get AFC */ - rc = xc2028_get_reg(priv, XREG_FREQ_ERROR, &afc_reg); - if (rc < 0) - goto ret; - - *afc = afc_reg * 15625; /* Hz */ - - tuner_dbg("AFC is %d Hz\n", *afc); - -ret: - mutex_unlock(&priv->lock); - - return rc; -} - -#define DIV 15625 - -static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, - enum v4l2_tuner_type new_type, - unsigned int type, - v4l2_std_id std, - u16 int_freq) -{ - struct xc2028_data *priv = fe->tuner_priv; - int rc = -EINVAL; - unsigned char buf[4]; - u32 div, offset = 0; - - tuner_dbg("%s called\n", __func__); - - mutex_lock(&priv->lock); - - tuner_dbg("should set frequency %d kHz\n", freq / 1000); - - if (check_firmware(fe, type, std, int_freq) < 0) - goto ret; - - /* On some cases xc2028 can disable video output, if - * very weak signals are received. By sending a soft - * reset, this is re-enabled. So, it is better to always - * send a soft reset before changing channels, to be sure - * that xc2028 will be in a safe state. - * Maybe this might also be needed for DTV. - */ - switch (new_type) { - case V4L2_TUNER_ANALOG_TV: - rc = send_seq(priv, {0x00, 0x00}); - - /* Analog mode requires offset = 0 */ - break; - case V4L2_TUNER_RADIO: - /* Radio mode requires offset = 0 */ - break; - case V4L2_TUNER_DIGITAL_TV: - /* - * Digital modes require an offset to adjust to the - * proper frequency. The offset depends on what - * firmware version is used. - */ - - /* - * Adjust to the center frequency. This is calculated by the - * formula: offset = 1.25MHz - BW/2 - * For DTV 7/8, the firmware uses BW = 8000, so it needs a - * further adjustment to get the frequency center on VHF - */ - - /* - * The firmware DTV78 used to work fine in UHF band (8 MHz - * bandwidth) but not at all in VHF band (7 MHz bandwidth). - * The real problem was connected to the formula used to - * calculate the center frequency offset in VHF band. - * In fact, removing the 500KHz adjustment fixed the problem. - * This is coherent to what was implemented for the DTV7 - * firmware. - * In the end, now the center frequency is the same for all 3 - * firmwares (DTV7, DTV8, DTV78) and doesn't depend on channel - * bandwidth. - */ - - if (priv->cur_fw.type & DTV6) - offset = 1750000; - else /* DTV7 or DTV8 or DTV78 */ - offset = 2750000; - - /* - * xc3028 additional "magic" - * Depending on the firmware version, it needs some adjustments - * to properly centralize the frequency. This seems to be - * needed to compensate the SCODE table adjustments made by - * newer firmwares - */ - - /* - * The proper adjustment would be to do it at s-code table. - * However, this didn't work, as reported by - * Robert Lowery - */ - -#if 0 - /* - * Still need tests for XC3028L (firmware 3.2 or upper) - * So, for now, let's just comment the per-firmware - * version of this change. Reports with xc3028l working - * with and without the lines bellow are welcome - */ - - if (priv->firm_version < 0x0302) { - if (priv->cur_fw.type & DTV7) - offset += 500000; - } else { - if (priv->cur_fw.type & DTV7) - offset -= 300000; - else if (type != ATSC) /* DVB @6MHz, DTV 8 and DTV 7/8 */ - offset += 200000; - } -#endif - } - - div = (freq - offset + DIV / 2) / DIV; - - /* CMD= Set frequency */ - if (priv->firm_version < 0x0202) - rc = send_seq(priv, {0x00, XREG_RF_FREQ, 0x00, 0x00}); - else - rc = send_seq(priv, {0x80, XREG_RF_FREQ, 0x00, 0x00}); - if (rc < 0) - goto ret; - - /* Return code shouldn't be checked. - The reset CLK is needed only with tm6000. - Driver should work fine even if this fails. - */ - if (priv->ctrl.msleep) - msleep(priv->ctrl.msleep); - do_tuner_callback(fe, XC2028_RESET_CLK, 1); - - msleep(10); - - buf[0] = 0xff & (div >> 24); - buf[1] = 0xff & (div >> 16); - buf[2] = 0xff & (div >> 8); - buf[3] = 0xff & (div); - - rc = i2c_send(priv, buf, sizeof(buf)); - if (rc < 0) - goto ret; - msleep(100); - - priv->frequency = freq; - - tuner_dbg("divisor= %*ph (freq=%d.%03d)\n", 4, buf, - freq / 1000000, (freq % 1000000) / 1000); - - rc = 0; - -ret: - mutex_unlock(&priv->lock); - - return rc; -} - -static int xc2028_set_analog_freq(struct dvb_frontend *fe, - struct analog_parameters *p) -{ - struct xc2028_data *priv = fe->tuner_priv; - unsigned int type=0; - - tuner_dbg("%s called\n", __func__); - - if (p->mode == V4L2_TUNER_RADIO) { - type |= FM; - if (priv->ctrl.input1) - type |= INPUT1; - return generic_set_freq(fe, (625l * p->frequency) / 10, - V4L2_TUNER_RADIO, type, 0, 0); - } - - /* if std is not defined, choose one */ - if (!p->std) - p->std = V4L2_STD_MN; - - /* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */ - if (!(p->std & V4L2_STD_MN)) - type |= F8MHZ; - - /* Add audio hack to std mask */ - p->std |= parse_audio_std_option(); - - return generic_set_freq(fe, 62500l * p->frequency, - V4L2_TUNER_ANALOG_TV, type, p->std, 0); -} - -static int xc2028_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u32 delsys = c->delivery_system; - u32 bw = c->bandwidth_hz; - struct xc2028_data *priv = fe->tuner_priv; - int rc; - unsigned int type = 0; - u16 demod = 0; - - tuner_dbg("%s called\n", __func__); - - rc = check_device_status(priv); - if (rc < 0) - return rc; - - switch (delsys) { - case SYS_DVBT: - case SYS_DVBT2: - /* - * The only countries with 6MHz seem to be Taiwan/Uruguay. - * Both seem to require QAM firmware for OFDM decoding - * Tested in Taiwan by Terry Wu - */ - if (bw <= 6000000) - type |= QAM; - - switch (priv->ctrl.type) { - case XC2028_D2633: - type |= D2633; - break; - case XC2028_D2620: - type |= D2620; - break; - case XC2028_AUTO: - default: - /* Zarlink seems to need D2633 */ - if (priv->ctrl.demod == XC3028_FE_ZARLINK456) - type |= D2633; - else - type |= D2620; - } - break; - case SYS_ATSC: - /* The only ATSC firmware (at least on v2.7) is D2633 */ - type |= ATSC | D2633; - break; - /* DVB-S and pure QAM (FE_QAM) are not supported */ - default: - return -EINVAL; - } - - if (bw <= 6000000) { - type |= DTV6; - priv->ctrl.vhfbw7 = 0; - priv->ctrl.uhfbw8 = 0; - } else if (bw <= 7000000) { - if (c->frequency < 470000000) - priv->ctrl.vhfbw7 = 1; - else - priv->ctrl.uhfbw8 = 0; - type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7; - type |= F8MHZ; - } else { - if (c->frequency < 470000000) - priv->ctrl.vhfbw7 = 0; - else - priv->ctrl.uhfbw8 = 1; - type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8; - type |= F8MHZ; - } - - /* All S-code tables need a 200kHz shift */ - if (priv->ctrl.demod) { - demod = priv->ctrl.demod; - - /* - * Newer firmwares require a 200 kHz offset only for ATSC - */ - if (type == ATSC || priv->firm_version < 0x0302) - demod += 200; - /* - * The DTV7 S-code table needs a 700 kHz shift. - * - * DTV7 is only used in Australia. Germany or Italy may also - * use this firmware after initialization, but a tune to a UHF - * channel should then cause DTV78 to be used. - * - * Unfortunately, on real-field tests, the s-code offset - * didn't work as expected, as reported by - * Robert Lowery - */ - } - - return generic_set_freq(fe, c->frequency, - V4L2_TUNER_DIGITAL_TV, type, 0, demod); -} - -static int xc2028_sleep(struct dvb_frontend *fe) -{ - struct xc2028_data *priv = fe->tuner_priv; - int rc; - - rc = check_device_status(priv); - if (rc < 0) - return rc; - - /* Avoid firmware reload on slow devices or if PM disabled */ - if (no_poweroff || priv->ctrl.disable_power_mgmt) - return 0; - - tuner_dbg("Putting xc2028/3028 into poweroff mode.\n"); - if (debug > 1) { - tuner_dbg("Printing sleep stack trace:\n"); - dump_stack(); - } - - mutex_lock(&priv->lock); - - if (priv->firm_version < 0x0202) - rc = send_seq(priv, {0x00, XREG_POWER_DOWN, 0x00, 0x00}); - else - rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00}); - - priv->state = XC2028_SLEEP; - - mutex_unlock(&priv->lock); - - return rc; -} - -static int xc2028_dvb_release(struct dvb_frontend *fe) -{ - struct xc2028_data *priv = fe->tuner_priv; - - tuner_dbg("%s called\n", __func__); - - mutex_lock(&xc2028_list_mutex); - - /* only perform final cleanup if this is the last instance */ - if (hybrid_tuner_report_instance_count(priv) == 1) { - free_firmware(priv); - kfree(priv->ctrl.fname); - priv->ctrl.fname = NULL; - } - - if (priv) - hybrid_tuner_release_state(priv); - - mutex_unlock(&xc2028_list_mutex); - - fe->tuner_priv = NULL; - - return 0; -} - -static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct xc2028_data *priv = fe->tuner_priv; - int rc; - - tuner_dbg("%s called\n", __func__); - - rc = check_device_status(priv); - if (rc < 0) - return rc; - - *frequency = priv->frequency; - - return 0; -} - -static void load_firmware_cb(const struct firmware *fw, - void *context) -{ - struct dvb_frontend *fe = context; - struct xc2028_data *priv = fe->tuner_priv; - int rc; - - tuner_dbg("request_firmware_nowait(): %s\n", fw ? "OK" : "error"); - if (!fw) { - tuner_err("Could not load firmware %s.\n", priv->fname); - priv->state = XC2028_NODEV; - return; - } - - rc = load_all_firmwares(fe, fw); - - release_firmware(fw); - - if (rc < 0) - return; - priv->state = XC2028_SLEEP; -} - -static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) -{ - struct xc2028_data *priv = fe->tuner_priv; - struct xc2028_ctrl *p = priv_cfg; - int rc = 0; - - tuner_dbg("%s called\n", __func__); - - mutex_lock(&priv->lock); - - /* - * Copy the config data. - * For the firmware name, keep a local copy of the string, - * in order to avoid troubles during device release. - */ - if (priv->ctrl.fname) - kfree(priv->ctrl.fname); - memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); - if (p->fname) { - priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); - if (priv->ctrl.fname == NULL) - rc = -ENOMEM; - } - - /* - * If firmware name changed, frees firmware. As free_firmware will - * reset the status to NO_FIRMWARE, this forces a new request_firmware - */ - if (!firmware_name[0] && p->fname && - priv->fname && strcmp(p->fname, priv->fname)) - free_firmware(priv); - - if (priv->ctrl.max_len < 9) - priv->ctrl.max_len = 13; - - if (priv->state == XC2028_NO_FIRMWARE) { - if (!firmware_name[0]) - priv->fname = priv->ctrl.fname; - else - priv->fname = firmware_name; - - rc = request_firmware_nowait(THIS_MODULE, 1, - priv->fname, - priv->i2c_props.adap->dev.parent, - GFP_KERNEL, - fe, load_firmware_cb); - if (rc < 0) { - tuner_err("Failed to request firmware %s\n", - priv->fname); - priv->state = XC2028_NODEV; - } else - priv->state = XC2028_WAITING_FIRMWARE; - } - mutex_unlock(&priv->lock); - - return rc; -} - -static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { - .info = { - .name = "Xceive XC3028", - .frequency_min = 42000000, - .frequency_max = 864000000, - .frequency_step = 50000, - }, - - .set_config = xc2028_set_config, - .set_analog_params = xc2028_set_analog_freq, - .release = xc2028_dvb_release, - .get_frequency = xc2028_get_frequency, - .get_rf_strength = xc2028_signal, - .get_afc = xc2028_get_afc, - .set_params = xc2028_set_params, - .sleep = xc2028_sleep, -}; - -struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, - struct xc2028_config *cfg) -{ - struct xc2028_data *priv; - int instance; - - if (debug) - printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n"); - - if (NULL == cfg) - return NULL; - - if (!fe) { - printk(KERN_ERR "xc2028: No frontend!\n"); - return NULL; - } - - mutex_lock(&xc2028_list_mutex); - - instance = hybrid_tuner_request_state(struct xc2028_data, priv, - hybrid_tuner_instance_list, - cfg->i2c_adap, cfg->i2c_addr, - "xc2028"); - switch (instance) { - case 0: - /* memory allocation failure */ - goto fail; - break; - case 1: - /* new tuner instance */ - priv->ctrl.max_len = 13; - - mutex_init(&priv->lock); - - fe->tuner_priv = priv; - break; - case 2: - /* existing tuner instance */ - fe->tuner_priv = priv; - break; - } - - memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops, - sizeof(xc2028_dvb_tuner_ops)); - - tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner"); - - if (cfg->ctrl) - xc2028_set_config(fe, cfg->ctrl); - - mutex_unlock(&xc2028_list_mutex); - - return fe; -fail: - mutex_unlock(&xc2028_list_mutex); - - xc2028_dvb_release(fe); - return NULL; -} - -EXPORT_SYMBOL(xc2028_attach); - -MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver"); -MODULE_AUTHOR("Michel Ludwig "); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE); -MODULE_FIRMWARE(XC3028L_DEFAULT_FIRMWARE); diff --git a/drivers/media/common/tuners/tuner-xc2028.h b/drivers/media/common/tuners/tuner-xc2028.h deleted file mode 100644 index 9ebfb2d0ff14..000000000000 --- a/drivers/media/common/tuners/tuner-xc2028.h +++ /dev/null @@ -1,72 +0,0 @@ -/* tuner-xc2028 - * - * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License v2 - */ - -#ifndef __TUNER_XC2028_H__ -#define __TUNER_XC2028_H__ - -#include "dvb_frontend.h" - -#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw" -#define XC3028L_DEFAULT_FIRMWARE "xc3028L-v36.fw" - -/* Dmoduler IF (kHz) */ -#define XC3028_FE_DEFAULT 0 /* Don't load SCODE */ -#define XC3028_FE_LG60 6000 -#define XC3028_FE_ATI638 6380 -#define XC3028_FE_OREN538 5380 -#define XC3028_FE_OREN36 3600 -#define XC3028_FE_TOYOTA388 3880 -#define XC3028_FE_TOYOTA794 7940 -#define XC3028_FE_DIBCOM52 5200 -#define XC3028_FE_ZARLINK456 4560 -#define XC3028_FE_CHINA 5200 - -enum firmware_type { - XC2028_AUTO = 0, /* By default, auto-detects */ - XC2028_D2633, - XC2028_D2620, -}; - -struct xc2028_ctrl { - char *fname; - int max_len; - int msleep; - unsigned int scode_table; - unsigned int mts :1; - unsigned int input1:1; - unsigned int vhfbw7:1; - unsigned int uhfbw8:1; - unsigned int disable_power_mgmt:1; - unsigned int read_not_reliable:1; - unsigned int demod; - enum firmware_type type:2; -}; - -struct xc2028_config { - struct i2c_adapter *i2c_adap; - u8 i2c_addr; - struct xc2028_ctrl *ctrl; -}; - -/* xc2028 commands for callback */ -#define XC2028_TUNER_RESET 0 -#define XC2028_RESET_CLK 1 -#define XC2028_I2C_FLUSH 2 - -#if defined(CONFIG_MEDIA_TUNER_XC2028) || (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE)) -extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, - struct xc2028_config *cfg); -#else -static inline struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, - struct xc2028_config *cfg) -{ - printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", - __func__); - return NULL; -} -#endif - -#endif /* __TUNER_XC2028_H__ */ diff --git a/drivers/media/common/tuners/xc4000.c b/drivers/media/common/tuners/xc4000.c deleted file mode 100644 index 4937712278f6..000000000000 --- a/drivers/media/common/tuners/xc4000.c +++ /dev/null @@ -1,1757 +0,0 @@ -/* - * Driver for Xceive XC4000 "QAM/8VSB single chip tuner" - * - * Copyright (c) 2007 Xceive Corporation - * Copyright (c) 2007 Steven Toth - * Copyright (c) 2009 Devin Heitmueller - * Copyright (c) 2009 Davide Ferri - * Copyright (c) 2010 Istvan Varga - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" - -#include "xc4000.h" -#include "tuner-i2c.h" -#include "tuner-xc2028-types.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debugging level (0 to 2, default: 0 (off))."); - -static int no_poweroff; -module_param(no_poweroff, int, 0644); -MODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, " - "0 (default): use device-specific default mode)."); - -static int audio_std; -module_param(audio_std, int, 0644); -MODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly " - "needs to know what audio standard is needed for some video standards " - "with audio A2 or NICAM. The valid settings are a sum of:\n" - " 1: use NICAM/B or A2/B instead of NICAM/A or A2/A\n" - " 2: use A2 instead of NICAM or BTSC\n" - " 4: use SECAM/K3 instead of K1\n" - " 8: use PAL-D/K audio for SECAM-D/K\n" - "16: use FM radio input 1 instead of input 2\n" - "32: use mono audio (the lower three bits are ignored)"); - -static char firmware_name[30]; -module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); -MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the " - "default firmware name."); - -static DEFINE_MUTEX(xc4000_list_mutex); -static LIST_HEAD(hybrid_tuner_instance_list); - -#define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_INFO "%s: " fmt, "xc4000", ## arg) - -/* struct for storing firmware table */ -struct firmware_description { - unsigned int type; - v4l2_std_id id; - __u16 int_freq; - unsigned char *ptr; - unsigned int size; -}; - -struct firmware_properties { - unsigned int type; - v4l2_std_id id; - v4l2_std_id std_req; - __u16 int_freq; - unsigned int scode_table; - int scode_nr; -}; - -struct xc4000_priv { - struct tuner_i2c_props i2c_props; - struct list_head hybrid_tuner_instance_list; - struct firmware_description *firm; - int firm_size; - u32 if_khz; - u32 freq_hz; - u32 bandwidth; - u8 video_standard; - u8 rf_mode; - u8 default_pm; - u8 dvb_amplitude; - u8 set_smoothedcvbs; - u8 ignore_i2c_write_errors; - __u16 firm_version; - struct firmware_properties cur_fw; - __u16 hwmodel; - __u16 hwvers; - struct mutex lock; -}; - -#define XC4000_AUDIO_STD_B 1 -#define XC4000_AUDIO_STD_A2 2 -#define XC4000_AUDIO_STD_K3 4 -#define XC4000_AUDIO_STD_L 8 -#define XC4000_AUDIO_STD_INPUT1 16 -#define XC4000_AUDIO_STD_MONO 32 - -#define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.fw" - -/* Misc Defines */ -#define MAX_TV_STANDARD 24 -#define XC_MAX_I2C_WRITE_LENGTH 64 -#define XC_POWERED_DOWN 0x80000000U - -/* Signal Types */ -#define XC_RF_MODE_AIR 0 -#define XC_RF_MODE_CABLE 1 - -/* Product id */ -#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 -#define XC_PRODUCT_ID_XC4000 0x0FA0 -#define XC_PRODUCT_ID_XC4100 0x1004 - -/* Registers (Write-only) */ -#define XREG_INIT 0x00 -#define XREG_VIDEO_MODE 0x01 -#define XREG_AUDIO_MODE 0x02 -#define XREG_RF_FREQ 0x03 -#define XREG_D_CODE 0x04 -#define XREG_DIRECTSITTING_MODE 0x05 -#define XREG_SEEK_MODE 0x06 -#define XREG_POWER_DOWN 0x08 -#define XREG_SIGNALSOURCE 0x0A -#define XREG_SMOOTHEDCVBS 0x0E -#define XREG_AMPLITUDE 0x10 - -/* Registers (Read-only) */ -#define XREG_ADC_ENV 0x00 -#define XREG_QUALITY 0x01 -#define XREG_FRAME_LINES 0x02 -#define XREG_HSYNC_FREQ 0x03 -#define XREG_LOCK 0x04 -#define XREG_FREQ_ERROR 0x05 -#define XREG_SNR 0x06 -#define XREG_VERSION 0x07 -#define XREG_PRODUCT_ID 0x08 -#define XREG_SIGNAL_LEVEL 0x0A -#define XREG_NOISE_LEVEL 0x0B - -/* - Basic firmware description. This will remain with - the driver for documentation purposes. - - This represents an I2C firmware file encoded as a - string of unsigned char. Format is as follows: - - char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB - char[1 ]=len0_LSB -> length of first write transaction - char[2 ]=data0 -> first byte to be sent - char[3 ]=data1 - char[4 ]=data2 - char[ ]=... - char[M ]=dataN -> last byte to be sent - char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB - char[M+2]=len1_LSB -> length of second write transaction - char[M+3]=data0 - char[M+4]=data1 - ... - etc. - - The [len] value should be interpreted as follows: - - len= len_MSB _ len_LSB - len=1111_1111_1111_1111 : End of I2C_SEQUENCE - len=0000_0000_0000_0000 : Reset command: Do hardware reset - len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) - len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms - - For the RESET and WAIT commands, the two following bytes will contain - immediately the length of the following transaction. -*/ - -struct XC_TV_STANDARD { - const char *Name; - u16 audio_mode; - u16 video_mode; - u16 int_freq; -}; - -/* Tuner standards */ -#define XC4000_MN_NTSC_PAL_BTSC 0 -#define XC4000_MN_NTSC_PAL_A2 1 -#define XC4000_MN_NTSC_PAL_EIAJ 2 -#define XC4000_MN_NTSC_PAL_Mono 3 -#define XC4000_BG_PAL_A2 4 -#define XC4000_BG_PAL_NICAM 5 -#define XC4000_BG_PAL_MONO 6 -#define XC4000_I_PAL_NICAM 7 -#define XC4000_I_PAL_NICAM_MONO 8 -#define XC4000_DK_PAL_A2 9 -#define XC4000_DK_PAL_NICAM 10 -#define XC4000_DK_PAL_MONO 11 -#define XC4000_DK_SECAM_A2DK1 12 -#define XC4000_DK_SECAM_A2LDK3 13 -#define XC4000_DK_SECAM_A2MONO 14 -#define XC4000_DK_SECAM_NICAM 15 -#define XC4000_L_SECAM_NICAM 16 -#define XC4000_LC_SECAM_NICAM 17 -#define XC4000_DTV6 18 -#define XC4000_DTV8 19 -#define XC4000_DTV7_8 20 -#define XC4000_DTV7 21 -#define XC4000_FM_Radio_INPUT2 22 -#define XC4000_FM_Radio_INPUT1 23 - -static struct XC_TV_STANDARD xc4000_standard[MAX_TV_STANDARD] = { - {"M/N-NTSC/PAL-BTSC", 0x0000, 0x80A0, 4500}, - {"M/N-NTSC/PAL-A2", 0x0000, 0x80A0, 4600}, - {"M/N-NTSC/PAL-EIAJ", 0x0040, 0x80A0, 4500}, - {"M/N-NTSC/PAL-Mono", 0x0078, 0x80A0, 4500}, - {"B/G-PAL-A2", 0x0000, 0x8159, 5640}, - {"B/G-PAL-NICAM", 0x0004, 0x8159, 5740}, - {"B/G-PAL-MONO", 0x0078, 0x8159, 5500}, - {"I-PAL-NICAM", 0x0080, 0x8049, 6240}, - {"I-PAL-NICAM-MONO", 0x0078, 0x8049, 6000}, - {"D/K-PAL-A2", 0x0000, 0x8049, 6380}, - {"D/K-PAL-NICAM", 0x0080, 0x8049, 6200}, - {"D/K-PAL-MONO", 0x0078, 0x8049, 6500}, - {"D/K-SECAM-A2 DK1", 0x0000, 0x8049, 6340}, - {"D/K-SECAM-A2 L/DK3", 0x0000, 0x8049, 6000}, - {"D/K-SECAM-A2 MONO", 0x0078, 0x8049, 6500}, - {"D/K-SECAM-NICAM", 0x0080, 0x8049, 6200}, - {"L-SECAM-NICAM", 0x8080, 0x0009, 6200}, - {"L'-SECAM-NICAM", 0x8080, 0x4009, 6200}, - {"DTV6", 0x00C0, 0x8002, 0}, - {"DTV8", 0x00C0, 0x800B, 0}, - {"DTV7/8", 0x00C0, 0x801B, 0}, - {"DTV7", 0x00C0, 0x8007, 0}, - {"FM Radio-INPUT2", 0x0008, 0x9800, 10700}, - {"FM Radio-INPUT1", 0x0008, 0x9000, 10700} -}; - -static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val); -static int xc4000_tuner_reset(struct dvb_frontend *fe); -static void xc_debug_dump(struct xc4000_priv *priv); - -static int xc_send_i2c_data(struct xc4000_priv *priv, u8 *buf, int len) -{ - struct i2c_msg msg = { .addr = priv->i2c_props.addr, - .flags = 0, .buf = buf, .len = len }; - if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { - if (priv->ignore_i2c_write_errors == 0) { - printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n", - len); - if (len == 4) { - printk(KERN_ERR "bytes %*ph\n", 4, buf); - } - return -EREMOTEIO; - } - } - return 0; -} - -static int xc4000_tuner_reset(struct dvb_frontend *fe) -{ - struct xc4000_priv *priv = fe->tuner_priv; - int ret; - - dprintk(1, "%s()\n", __func__); - - if (fe->callback) { - ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ? - fe->dvb->priv : - priv->i2c_props.adap->algo_data, - DVB_FRONTEND_COMPONENT_TUNER, - XC4000_TUNER_RESET, 0); - if (ret) { - printk(KERN_ERR "xc4000: reset failed\n"); - return -EREMOTEIO; - } - } else { - printk(KERN_ERR "xc4000: no tuner reset callback function, " - "fatal\n"); - return -EINVAL; - } - return 0; -} - -static int xc_write_reg(struct xc4000_priv *priv, u16 regAddr, u16 i2cData) -{ - u8 buf[4]; - int result; - - buf[0] = (regAddr >> 8) & 0xFF; - buf[1] = regAddr & 0xFF; - buf[2] = (i2cData >> 8) & 0xFF; - buf[3] = i2cData & 0xFF; - result = xc_send_i2c_data(priv, buf, 4); - - return result; -} - -static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) -{ - struct xc4000_priv *priv = fe->tuner_priv; - - int i, nbytes_to_send, result; - unsigned int len, pos, index; - u8 buf[XC_MAX_I2C_WRITE_LENGTH]; - - index = 0; - while ((i2c_sequence[index] != 0xFF) || - (i2c_sequence[index + 1] != 0xFF)) { - len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; - if (len == 0x0000) { - /* RESET command */ - /* NOTE: this is ignored, as the reset callback was */ - /* already called by check_firmware() */ - index += 2; - } else if (len & 0x8000) { - /* WAIT command */ - msleep(len & 0x7FFF); - index += 2; - } else { - /* Send i2c data whilst ensuring individual transactions - * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. - */ - index += 2; - buf[0] = i2c_sequence[index]; - buf[1] = i2c_sequence[index + 1]; - pos = 2; - while (pos < len) { - if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) - nbytes_to_send = - XC_MAX_I2C_WRITE_LENGTH; - else - nbytes_to_send = (len - pos + 2); - for (i = 2; i < nbytes_to_send; i++) { - buf[i] = i2c_sequence[index + pos + - i - 2]; - } - result = xc_send_i2c_data(priv, buf, - nbytes_to_send); - - if (result != 0) - return result; - - pos += nbytes_to_send - 2; - } - index += len; - } - } - return 0; -} - -static int xc_set_tv_standard(struct xc4000_priv *priv, - u16 video_mode, u16 audio_mode) -{ - int ret; - dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode); - dprintk(1, "%s() Standard = %s\n", - __func__, - xc4000_standard[priv->video_standard].Name); - - /* Don't complain when the request fails because of i2c stretching */ - priv->ignore_i2c_write_errors = 1; - - ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode); - if (ret == 0) - ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode); - - priv->ignore_i2c_write_errors = 0; - - return ret; -} - -static int xc_set_signal_source(struct xc4000_priv *priv, u16 rf_mode) -{ - dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, - rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); - - if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) { - rf_mode = XC_RF_MODE_CABLE; - printk(KERN_ERR - "%s(), Invalid mode, defaulting to CABLE", - __func__); - } - return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); -} - -static const struct dvb_tuner_ops xc4000_tuner_ops; - -static int xc_set_rf_frequency(struct xc4000_priv *priv, u32 freq_hz) -{ - u16 freq_code; - - dprintk(1, "%s(%u)\n", __func__, freq_hz); - - if ((freq_hz > xc4000_tuner_ops.info.frequency_max) || - (freq_hz < xc4000_tuner_ops.info.frequency_min)) - return -EINVAL; - - freq_code = (u16)(freq_hz / 15625); - - /* WAS: Starting in firmware version 1.1.44, Xceive recommends using the - FINERFREQ for all normal tuning (the doc indicates reg 0x03 should - only be used for fast scanning for channel lock) */ - /* WAS: XREG_FINERFREQ */ - return xc_write_reg(priv, XREG_RF_FREQ, freq_code); -} - -static int xc_get_adc_envelope(struct xc4000_priv *priv, u16 *adc_envelope) -{ - return xc4000_readreg(priv, XREG_ADC_ENV, adc_envelope); -} - -static int xc_get_frequency_error(struct xc4000_priv *priv, u32 *freq_error_hz) -{ - int result; - u16 regData; - u32 tmp; - - result = xc4000_readreg(priv, XREG_FREQ_ERROR, ®Data); - if (result != 0) - return result; - - tmp = (u32)regData & 0xFFFFU; - tmp = (tmp < 0x8000U ? tmp : 0x10000U - tmp); - (*freq_error_hz) = tmp * 15625; - return result; -} - -static int xc_get_lock_status(struct xc4000_priv *priv, u16 *lock_status) -{ - return xc4000_readreg(priv, XREG_LOCK, lock_status); -} - -static int xc_get_version(struct xc4000_priv *priv, - u8 *hw_majorversion, u8 *hw_minorversion, - u8 *fw_majorversion, u8 *fw_minorversion) -{ - u16 data; - int result; - - result = xc4000_readreg(priv, XREG_VERSION, &data); - if (result != 0) - return result; - - (*hw_majorversion) = (data >> 12) & 0x0F; - (*hw_minorversion) = (data >> 8) & 0x0F; - (*fw_majorversion) = (data >> 4) & 0x0F; - (*fw_minorversion) = data & 0x0F; - - return 0; -} - -static int xc_get_hsync_freq(struct xc4000_priv *priv, u32 *hsync_freq_hz) -{ - u16 regData; - int result; - - result = xc4000_readreg(priv, XREG_HSYNC_FREQ, ®Data); - if (result != 0) - return result; - - (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; - return result; -} - -static int xc_get_frame_lines(struct xc4000_priv *priv, u16 *frame_lines) -{ - return xc4000_readreg(priv, XREG_FRAME_LINES, frame_lines); -} - -static int xc_get_quality(struct xc4000_priv *priv, u16 *quality) -{ - return xc4000_readreg(priv, XREG_QUALITY, quality); -} - -static int xc_get_signal_level(struct xc4000_priv *priv, u16 *signal) -{ - return xc4000_readreg(priv, XREG_SIGNAL_LEVEL, signal); -} - -static int xc_get_noise_level(struct xc4000_priv *priv, u16 *noise) -{ - return xc4000_readreg(priv, XREG_NOISE_LEVEL, noise); -} - -static u16 xc_wait_for_lock(struct xc4000_priv *priv) -{ - u16 lock_state = 0; - int watchdog_count = 40; - - while ((lock_state == 0) && (watchdog_count > 0)) { - xc_get_lock_status(priv, &lock_state); - if (lock_state != 1) { - msleep(5); - watchdog_count--; - } - } - return lock_state; -} - -static int xc_tune_channel(struct xc4000_priv *priv, u32 freq_hz) -{ - int found = 1; - int result; - - dprintk(1, "%s(%u)\n", __func__, freq_hz); - - /* Don't complain when the request fails because of i2c stretching */ - priv->ignore_i2c_write_errors = 1; - result = xc_set_rf_frequency(priv, freq_hz); - priv->ignore_i2c_write_errors = 0; - - if (result != 0) - return 0; - - /* wait for lock only in analog TV mode */ - if ((priv->cur_fw.type & (FM | DTV6 | DTV7 | DTV78 | DTV8)) == 0) { - if (xc_wait_for_lock(priv) != 1) - found = 0; - } - - /* Wait for stats to stabilize. - * Frame Lines needs two frame times after initial lock - * before it is valid. - */ - msleep(debug ? 100 : 10); - - if (debug) - xc_debug_dump(priv); - - return found; -} - -static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val) -{ - u8 buf[2] = { reg >> 8, reg & 0xff }; - u8 bval[2] = { 0, 0 }; - struct i2c_msg msg[2] = { - { .addr = priv->i2c_props.addr, - .flags = 0, .buf = &buf[0], .len = 2 }, - { .addr = priv->i2c_props.addr, - .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, - }; - - if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) { - printk(KERN_ERR "xc4000: I2C read failed\n"); - return -EREMOTEIO; - } - - *val = (bval[0] << 8) | bval[1]; - return 0; -} - -#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) -static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) -{ - if (type & BASE) - printk(KERN_CONT "BASE "); - if (type & INIT1) - printk(KERN_CONT "INIT1 "); - if (type & F8MHZ) - printk(KERN_CONT "F8MHZ "); - if (type & MTS) - printk(KERN_CONT "MTS "); - if (type & D2620) - printk(KERN_CONT "D2620 "); - if (type & D2633) - printk(KERN_CONT "D2633 "); - if (type & DTV6) - printk(KERN_CONT "DTV6 "); - if (type & QAM) - printk(KERN_CONT "QAM "); - if (type & DTV7) - printk(KERN_CONT "DTV7 "); - if (type & DTV78) - printk(KERN_CONT "DTV78 "); - if (type & DTV8) - printk(KERN_CONT "DTV8 "); - if (type & FM) - printk(KERN_CONT "FM "); - if (type & INPUT1) - printk(KERN_CONT "INPUT1 "); - if (type & LCD) - printk(KERN_CONT "LCD "); - if (type & NOGD) - printk(KERN_CONT "NOGD "); - if (type & MONO) - printk(KERN_CONT "MONO "); - if (type & ATSC) - printk(KERN_CONT "ATSC "); - if (type & IF) - printk(KERN_CONT "IF "); - if (type & LG60) - printk(KERN_CONT "LG60 "); - if (type & ATI638) - printk(KERN_CONT "ATI638 "); - if (type & OREN538) - printk(KERN_CONT "OREN538 "); - if (type & OREN36) - printk(KERN_CONT "OREN36 "); - if (type & TOYOTA388) - printk(KERN_CONT "TOYOTA388 "); - if (type & TOYOTA794) - printk(KERN_CONT "TOYOTA794 "); - if (type & DIBCOM52) - printk(KERN_CONT "DIBCOM52 "); - if (type & ZARLINK456) - printk(KERN_CONT "ZARLINK456 "); - if (type & CHINA) - printk(KERN_CONT "CHINA "); - if (type & F6MHZ) - printk(KERN_CONT "F6MHZ "); - if (type & INPUT2) - printk(KERN_CONT "INPUT2 "); - if (type & SCODE) - printk(KERN_CONT "SCODE "); - if (type & HAS_IF) - printk(KERN_CONT "HAS_IF_%d ", int_freq); -} - -static int seek_firmware(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id *id) -{ - struct xc4000_priv *priv = fe->tuner_priv; - int i, best_i = -1; - unsigned int best_nr_diffs = 255U; - - if (!priv->firm) { - printk(KERN_ERR "Error! firmware not loaded\n"); - return -EINVAL; - } - - if (((type & ~SCODE) == 0) && (*id == 0)) - *id = V4L2_STD_PAL; - - /* Seek for generic video standard match */ - for (i = 0; i < priv->firm_size; i++) { - v4l2_std_id id_diff_mask = - (priv->firm[i].id ^ (*id)) & (*id); - unsigned int type_diff_mask = - (priv->firm[i].type ^ type) - & (BASE_TYPES | DTV_TYPES | LCD | NOGD | MONO | SCODE); - unsigned int nr_diffs; - - if (type_diff_mask - & (BASE | INIT1 | FM | DTV6 | DTV7 | DTV78 | DTV8 | SCODE)) - continue; - - nr_diffs = hweight64(id_diff_mask) + hweight32(type_diff_mask); - if (!nr_diffs) /* Supports all the requested standards */ - goto found; - - if (nr_diffs < best_nr_diffs) { - best_nr_diffs = nr_diffs; - best_i = i; - } - } - - /* FIXME: Would make sense to seek for type "hint" match ? */ - if (best_i < 0) { - i = -ENOENT; - goto ret; - } - - if (best_nr_diffs > 0U) { - printk(KERN_WARNING - "Selecting best matching firmware (%u bits differ) for " - "type=(%x), id %016llx:\n", - best_nr_diffs, type, (unsigned long long)*id); - i = best_i; - } - -found: - *id = priv->firm[i].id; - -ret: - if (debug) { - printk(KERN_DEBUG "%s firmware for type=", - (i < 0) ? "Can't find" : "Found"); - dump_firm_type(type); - printk(KERN_DEBUG "(%x), id %016llx.\n", type, (unsigned long long)*id); - } - return i; -} - -static int load_firmware(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id *id) -{ - struct xc4000_priv *priv = fe->tuner_priv; - int pos, rc; - unsigned char *p; - - pos = seek_firmware(fe, type, id); - if (pos < 0) - return pos; - - p = priv->firm[pos].ptr; - - /* Don't complain when the request fails because of i2c stretching */ - priv->ignore_i2c_write_errors = 1; - - rc = xc_load_i2c_sequence(fe, p); - - priv->ignore_i2c_write_errors = 0; - - return rc; -} - -static int xc4000_fwupload(struct dvb_frontend *fe) -{ - struct xc4000_priv *priv = fe->tuner_priv; - const struct firmware *fw = NULL; - const unsigned char *p, *endp; - int rc = 0; - int n, n_array; - char name[33]; - const char *fname; - - if (firmware_name[0] != '\0') - fname = firmware_name; - else - fname = XC4000_DEFAULT_FIRMWARE; - - dprintk(1, "Reading firmware %s\n", fname); - rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent); - if (rc < 0) { - if (rc == -ENOENT) - printk(KERN_ERR "Error: firmware %s not found.\n", fname); - else - printk(KERN_ERR "Error %d while requesting firmware %s\n", - rc, fname); - - return rc; - } - p = fw->data; - endp = p + fw->size; - - if (fw->size < sizeof(name) - 1 + 2 + 2) { - printk(KERN_ERR "Error: firmware file %s has invalid size!\n", - fname); - goto corrupt; - } - - memcpy(name, p, sizeof(name) - 1); - name[sizeof(name) - 1] = '\0'; - p += sizeof(name) - 1; - - priv->firm_version = get_unaligned_le16(p); - p += 2; - - n_array = get_unaligned_le16(p); - p += 2; - - dprintk(1, "Loading %d firmware images from %s, type: %s, ver %d.%d\n", - n_array, fname, name, - priv->firm_version >> 8, priv->firm_version & 0xff); - - priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL); - if (priv->firm == NULL) { - printk(KERN_ERR "Not enough memory to load firmware file.\n"); - rc = -ENOMEM; - goto done; - } - priv->firm_size = n_array; - - n = -1; - while (p < endp) { - __u32 type, size; - v4l2_std_id id; - __u16 int_freq = 0; - - n++; - if (n >= n_array) { - printk(KERN_ERR "More firmware images in file than " - "were expected!\n"); - goto corrupt; - } - - /* Checks if there's enough bytes to read */ - if (endp - p < sizeof(type) + sizeof(id) + sizeof(size)) - goto header; - - type = get_unaligned_le32(p); - p += sizeof(type); - - id = get_unaligned_le64(p); - p += sizeof(id); - - if (type & HAS_IF) { - int_freq = get_unaligned_le16(p); - p += sizeof(int_freq); - if (endp - p < sizeof(size)) - goto header; - } - - size = get_unaligned_le32(p); - p += sizeof(size); - - if (!size || size > endp - p) { - printk(KERN_ERR "Firmware type (%x), id %llx is corrupted (size=%d, expected %d)\n", - type, (unsigned long long)id, - (unsigned)(endp - p), size); - goto corrupt; - } - - priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); - if (priv->firm[n].ptr == NULL) { - printk(KERN_ERR "Not enough memory to load firmware file.\n"); - rc = -ENOMEM; - goto done; - } - - if (debug) { - printk(KERN_DEBUG "Reading firmware type "); - dump_firm_type_and_int_freq(type, int_freq); - printk(KERN_DEBUG "(%x), id %llx, size=%d.\n", - type, (unsigned long long)id, size); - } - - memcpy(priv->firm[n].ptr, p, size); - priv->firm[n].type = type; - priv->firm[n].id = id; - priv->firm[n].size = size; - priv->firm[n].int_freq = int_freq; - - p += size; - } - - if (n + 1 != priv->firm_size) { - printk(KERN_ERR "Firmware file is incomplete!\n"); - goto corrupt; - } - - goto done; - -header: - printk(KERN_ERR "Firmware header is incomplete!\n"); -corrupt: - rc = -EINVAL; - printk(KERN_ERR "Error: firmware file is corrupted!\n"); - -done: - release_firmware(fw); - if (rc == 0) - dprintk(1, "Firmware files loaded.\n"); - - return rc; -} - -static int load_scode(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id *id, __u16 int_freq, int scode) -{ - struct xc4000_priv *priv = fe->tuner_priv; - int pos, rc; - unsigned char *p; - u8 scode_buf[13]; - u8 indirect_mode[5]; - - dprintk(1, "%s called int_freq=%d\n", __func__, int_freq); - - if (!int_freq) { - pos = seek_firmware(fe, type, id); - if (pos < 0) - return pos; - } else { - for (pos = 0; pos < priv->firm_size; pos++) { - if ((priv->firm[pos].int_freq == int_freq) && - (priv->firm[pos].type & HAS_IF)) - break; - } - if (pos == priv->firm_size) - return -ENOENT; - } - - p = priv->firm[pos].ptr; - - if (priv->firm[pos].size != 12 * 16 || scode >= 16) - return -EINVAL; - p += 12 * scode; - - if (debug) { - tuner_info("Loading SCODE for type="); - dump_firm_type_and_int_freq(priv->firm[pos].type, - priv->firm[pos].int_freq); - printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type, - (unsigned long long)*id); - } - - scode_buf[0] = 0x00; - memcpy(&scode_buf[1], p, 12); - - /* Enter direct-mode */ - rc = xc_write_reg(priv, XREG_DIRECTSITTING_MODE, 0); - if (rc < 0) { - printk(KERN_ERR "failed to put device into direct mode!\n"); - return -EIO; - } - - rc = xc_send_i2c_data(priv, scode_buf, 13); - if (rc != 0) { - /* Even if the send failed, make sure we set back to indirect - mode */ - printk(KERN_ERR "Failed to set scode %d\n", rc); - } - - /* Switch back to indirect-mode */ - memset(indirect_mode, 0, sizeof(indirect_mode)); - indirect_mode[4] = 0x88; - xc_send_i2c_data(priv, indirect_mode, sizeof(indirect_mode)); - msleep(10); - - return 0; -} - -static int check_firmware(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id std, __u16 int_freq) -{ - struct xc4000_priv *priv = fe->tuner_priv; - struct firmware_properties new_fw; - int rc = 0, is_retry = 0; - u16 hwmodel; - v4l2_std_id std0; - u8 hw_major, hw_minor, fw_major, fw_minor; - - dprintk(1, "%s called\n", __func__); - - if (!priv->firm) { - rc = xc4000_fwupload(fe); - if (rc < 0) - return rc; - } - -retry: - new_fw.type = type; - new_fw.id = std; - new_fw.std_req = std; - new_fw.scode_table = SCODE; - new_fw.scode_nr = 0; - new_fw.int_freq = int_freq; - - dprintk(1, "checking firmware, user requested type="); - if (debug) { - dump_firm_type(new_fw.type); - printk(KERN_CONT "(%x), id %016llx, ", new_fw.type, - (unsigned long long)new_fw.std_req); - if (!int_freq) - printk(KERN_CONT "scode_tbl "); - else - printk(KERN_CONT "int_freq %d, ", new_fw.int_freq); - printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr); - } - - /* No need to reload base firmware if it matches */ - if (priv->cur_fw.type & BASE) { - dprintk(1, "BASE firmware not changed.\n"); - goto skip_base; - } - - /* Updating BASE - forget about all currently loaded firmware */ - memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); - - /* Reset is needed before loading firmware */ - rc = xc4000_tuner_reset(fe); - if (rc < 0) - goto fail; - - /* BASE firmwares are all std0 */ - std0 = 0; - rc = load_firmware(fe, BASE, &std0); - if (rc < 0) { - printk(KERN_ERR "Error %d while loading base firmware\n", rc); - goto fail; - } - - /* Load INIT1, if needed */ - dprintk(1, "Load init1 firmware, if exists\n"); - - rc = load_firmware(fe, BASE | INIT1, &std0); - if (rc == -ENOENT) - rc = load_firmware(fe, BASE | INIT1, &std0); - if (rc < 0 && rc != -ENOENT) { - tuner_err("Error %d while loading init1 firmware\n", - rc); - goto fail; - } - -skip_base: - /* - * No need to reload standard specific firmware if base firmware - * was not reloaded and requested video standards have not changed. - */ - if (priv->cur_fw.type == (BASE | new_fw.type) && - priv->cur_fw.std_req == std) { - dprintk(1, "Std-specific firmware already loaded.\n"); - goto skip_std_specific; - } - - /* Reloading std-specific firmware forces a SCODE update */ - priv->cur_fw.scode_table = 0; - - /* Load the standard firmware */ - rc = load_firmware(fe, new_fw.type, &new_fw.id); - - if (rc < 0) - goto fail; - -skip_std_specific: - if (priv->cur_fw.scode_table == new_fw.scode_table && - priv->cur_fw.scode_nr == new_fw.scode_nr) { - dprintk(1, "SCODE firmware already loaded.\n"); - goto check_device; - } - - /* Load SCODE firmware, if exists */ - rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, - new_fw.int_freq, new_fw.scode_nr); - if (rc != 0) - dprintk(1, "load scode failed %d\n", rc); - -check_device: - rc = xc4000_readreg(priv, XREG_PRODUCT_ID, &hwmodel); - - if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major, - &fw_minor) != 0) { - printk(KERN_ERR "Unable to read tuner registers.\n"); - goto fail; - } - - dprintk(1, "Device is Xceive %d version %d.%d, " - "firmware version %d.%d\n", - hwmodel, hw_major, hw_minor, fw_major, fw_minor); - - /* Check firmware version against what we downloaded. */ - if (priv->firm_version != ((fw_major << 8) | fw_minor)) { - printk(KERN_WARNING - "Incorrect readback of firmware version %d.%d.\n", - fw_major, fw_minor); - goto fail; - } - - /* Check that the tuner hardware model remains consistent over time. */ - if (priv->hwmodel == 0 && - (hwmodel == XC_PRODUCT_ID_XC4000 || - hwmodel == XC_PRODUCT_ID_XC4100)) { - priv->hwmodel = hwmodel; - priv->hwvers = (hw_major << 8) | hw_minor; - } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || - priv->hwvers != ((hw_major << 8) | hw_minor)) { - printk(KERN_WARNING - "Read invalid device hardware information - tuner " - "hung?\n"); - goto fail; - } - - memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); - - /* - * By setting BASE in cur_fw.type only after successfully loading all - * firmwares, we can: - * 1. Identify that BASE firmware with type=0 has been loaded; - * 2. Tell whether BASE firmware was just changed the next time through. - */ - priv->cur_fw.type |= BASE; - - return 0; - -fail: - memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); - if (!is_retry) { - msleep(50); - is_retry = 1; - dprintk(1, "Retrying firmware load\n"); - goto retry; - } - - if (rc == -ENOENT) - rc = -EINVAL; - return rc; -} - -static void xc_debug_dump(struct xc4000_priv *priv) -{ - u16 adc_envelope; - u32 freq_error_hz = 0; - u16 lock_status; - u32 hsync_freq_hz = 0; - u16 frame_lines; - u16 quality; - u16 signal = 0; - u16 noise = 0; - u8 hw_majorversion = 0, hw_minorversion = 0; - u8 fw_majorversion = 0, fw_minorversion = 0; - - xc_get_adc_envelope(priv, &adc_envelope); - dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); - - xc_get_frequency_error(priv, &freq_error_hz); - dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); - - xc_get_lock_status(priv, &lock_status); - dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", - lock_status); - - xc_get_version(priv, &hw_majorversion, &hw_minorversion, - &fw_majorversion, &fw_minorversion); - dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n", - hw_majorversion, hw_minorversion, - fw_majorversion, fw_minorversion); - - if (priv->video_standard < XC4000_DTV6) { - xc_get_hsync_freq(priv, &hsync_freq_hz); - dprintk(1, "*** Horizontal sync frequency = %d Hz\n", - hsync_freq_hz); - - xc_get_frame_lines(priv, &frame_lines); - dprintk(1, "*** Frame lines = %d\n", frame_lines); - } - - xc_get_quality(priv, &quality); - dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); - - xc_get_signal_level(priv, &signal); - dprintk(1, "*** Signal level = -%ddB (%d)\n", signal >> 8, signal); - - xc_get_noise_level(priv, &noise); - dprintk(1, "*** Noise level = %ddB (%d)\n", noise >> 8, noise); -} - -static int xc4000_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u32 delsys = c->delivery_system; - u32 bw = c->bandwidth_hz; - struct xc4000_priv *priv = fe->tuner_priv; - unsigned int type; - int ret = -EREMOTEIO; - - dprintk(1, "%s() frequency=%d (Hz)\n", __func__, c->frequency); - - mutex_lock(&priv->lock); - - switch (delsys) { - case SYS_ATSC: - dprintk(1, "%s() VSB modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_AIR; - priv->freq_hz = c->frequency - 1750000; - priv->video_standard = XC4000_DTV6; - type = DTV6; - break; - case SYS_DVBC_ANNEX_B: - dprintk(1, "%s() QAM modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_CABLE; - priv->freq_hz = c->frequency - 1750000; - priv->video_standard = XC4000_DTV6; - type = DTV6; - break; - case SYS_DVBT: - case SYS_DVBT2: - dprintk(1, "%s() OFDM\n", __func__); - if (bw == 0) { - if (c->frequency < 400000000) { - priv->freq_hz = c->frequency - 2250000; - } else { - priv->freq_hz = c->frequency - 2750000; - } - priv->video_standard = XC4000_DTV7_8; - type = DTV78; - } else if (bw <= 6000000) { - priv->video_standard = XC4000_DTV6; - priv->freq_hz = c->frequency - 1750000; - type = DTV6; - } else if (bw <= 7000000) { - priv->video_standard = XC4000_DTV7; - priv->freq_hz = c->frequency - 2250000; - type = DTV7; - } else { - priv->video_standard = XC4000_DTV8; - priv->freq_hz = c->frequency - 2750000; - type = DTV8; - } - priv->rf_mode = XC_RF_MODE_AIR; - break; - default: - printk(KERN_ERR "xc4000 delivery system not supported!\n"); - ret = -EINVAL; - goto fail; - } - - dprintk(1, "%s() frequency=%d (compensated)\n", - __func__, priv->freq_hz); - - /* Make sure the correct firmware type is loaded */ - if (check_firmware(fe, type, 0, priv->if_khz) != 0) - goto fail; - - priv->bandwidth = c->bandwidth_hz; - - ret = xc_set_signal_source(priv, priv->rf_mode); - if (ret != 0) { - printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n", - priv->rf_mode); - goto fail; - } else { - u16 video_mode, audio_mode; - video_mode = xc4000_standard[priv->video_standard].video_mode; - audio_mode = xc4000_standard[priv->video_standard].audio_mode; - if (type == DTV6 && priv->firm_version != 0x0102) - video_mode |= 0x0001; - ret = xc_set_tv_standard(priv, video_mode, audio_mode); - if (ret != 0) { - printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n"); - /* DJH - do not return when it fails... */ - /* goto fail; */ - } - } - - if (xc_write_reg(priv, XREG_D_CODE, 0) == 0) - ret = 0; - if (priv->dvb_amplitude != 0) { - if (xc_write_reg(priv, XREG_AMPLITUDE, - (priv->firm_version != 0x0102 || - priv->dvb_amplitude != 134 ? - priv->dvb_amplitude : 132)) != 0) - ret = -EREMOTEIO; - } - if (priv->set_smoothedcvbs != 0) { - if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0) - ret = -EREMOTEIO; - } - if (ret != 0) { - printk(KERN_ERR "xc4000: setting registers failed\n"); - /* goto fail; */ - } - - xc_tune_channel(priv, priv->freq_hz); - - ret = 0; - -fail: - mutex_unlock(&priv->lock); - - return ret; -} - -static int xc4000_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct xc4000_priv *priv = fe->tuner_priv; - unsigned int type = 0; - int ret = -EREMOTEIO; - - if (params->mode == V4L2_TUNER_RADIO) { - dprintk(1, "%s() frequency=%d (in units of 62.5Hz)\n", - __func__, params->frequency); - - mutex_lock(&priv->lock); - - params->std = 0; - priv->freq_hz = params->frequency * 125L / 2; - - if (audio_std & XC4000_AUDIO_STD_INPUT1) { - priv->video_standard = XC4000_FM_Radio_INPUT1; - type = FM | INPUT1; - } else { - priv->video_standard = XC4000_FM_Radio_INPUT2; - type = FM | INPUT2; - } - - goto tune_channel; - } - - dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", - __func__, params->frequency); - - mutex_lock(&priv->lock); - - /* params->frequency is in units of 62.5khz */ - priv->freq_hz = params->frequency * 62500; - - params->std &= V4L2_STD_ALL; - /* if std is not defined, choose one */ - if (!params->std) - params->std = V4L2_STD_PAL_BG; - - if (audio_std & XC4000_AUDIO_STD_MONO) - type = MONO; - - if (params->std & V4L2_STD_MN) { - params->std = V4L2_STD_MN; - if (audio_std & XC4000_AUDIO_STD_MONO) { - priv->video_standard = XC4000_MN_NTSC_PAL_Mono; - } else if (audio_std & XC4000_AUDIO_STD_A2) { - params->std |= V4L2_STD_A2; - priv->video_standard = XC4000_MN_NTSC_PAL_A2; - } else { - params->std |= V4L2_STD_BTSC; - priv->video_standard = XC4000_MN_NTSC_PAL_BTSC; - } - goto tune_channel; - } - - if (params->std & V4L2_STD_PAL_BG) { - params->std = V4L2_STD_PAL_BG; - if (audio_std & XC4000_AUDIO_STD_MONO) { - priv->video_standard = XC4000_BG_PAL_MONO; - } else if (!(audio_std & XC4000_AUDIO_STD_A2)) { - if (!(audio_std & XC4000_AUDIO_STD_B)) { - params->std |= V4L2_STD_NICAM_A; - priv->video_standard = XC4000_BG_PAL_NICAM; - } else { - params->std |= V4L2_STD_NICAM_B; - priv->video_standard = XC4000_BG_PAL_NICAM; - } - } else { - if (!(audio_std & XC4000_AUDIO_STD_B)) { - params->std |= V4L2_STD_A2_A; - priv->video_standard = XC4000_BG_PAL_A2; - } else { - params->std |= V4L2_STD_A2_B; - priv->video_standard = XC4000_BG_PAL_A2; - } - } - goto tune_channel; - } - - if (params->std & V4L2_STD_PAL_I) { - /* default to NICAM audio standard */ - params->std = V4L2_STD_PAL_I | V4L2_STD_NICAM; - if (audio_std & XC4000_AUDIO_STD_MONO) - priv->video_standard = XC4000_I_PAL_NICAM_MONO; - else - priv->video_standard = XC4000_I_PAL_NICAM; - goto tune_channel; - } - - if (params->std & V4L2_STD_PAL_DK) { - params->std = V4L2_STD_PAL_DK; - if (audio_std & XC4000_AUDIO_STD_MONO) { - priv->video_standard = XC4000_DK_PAL_MONO; - } else if (audio_std & XC4000_AUDIO_STD_A2) { - params->std |= V4L2_STD_A2; - priv->video_standard = XC4000_DK_PAL_A2; - } else { - params->std |= V4L2_STD_NICAM; - priv->video_standard = XC4000_DK_PAL_NICAM; - } - goto tune_channel; - } - - if (params->std & V4L2_STD_SECAM_DK) { - /* default to A2 audio standard */ - params->std = V4L2_STD_SECAM_DK | V4L2_STD_A2; - if (audio_std & XC4000_AUDIO_STD_L) { - type = 0; - priv->video_standard = XC4000_DK_SECAM_NICAM; - } else if (audio_std & XC4000_AUDIO_STD_MONO) { - priv->video_standard = XC4000_DK_SECAM_A2MONO; - } else if (audio_std & XC4000_AUDIO_STD_K3) { - params->std |= V4L2_STD_SECAM_K3; - priv->video_standard = XC4000_DK_SECAM_A2LDK3; - } else { - priv->video_standard = XC4000_DK_SECAM_A2DK1; - } - goto tune_channel; - } - - if (params->std & V4L2_STD_SECAM_L) { - /* default to NICAM audio standard */ - type = 0; - params->std = V4L2_STD_SECAM_L | V4L2_STD_NICAM; - priv->video_standard = XC4000_L_SECAM_NICAM; - goto tune_channel; - } - - if (params->std & V4L2_STD_SECAM_LC) { - /* default to NICAM audio standard */ - type = 0; - params->std = V4L2_STD_SECAM_LC | V4L2_STD_NICAM; - priv->video_standard = XC4000_LC_SECAM_NICAM; - goto tune_channel; - } - -tune_channel: - /* FIXME: it could be air. */ - priv->rf_mode = XC_RF_MODE_CABLE; - - if (check_firmware(fe, type, params->std, - xc4000_standard[priv->video_standard].int_freq) != 0) - goto fail; - - ret = xc_set_signal_source(priv, priv->rf_mode); - if (ret != 0) { - printk(KERN_ERR - "xc4000: xc_set_signal_source(%d) failed\n", - priv->rf_mode); - goto fail; - } else { - u16 video_mode, audio_mode; - video_mode = xc4000_standard[priv->video_standard].video_mode; - audio_mode = xc4000_standard[priv->video_standard].audio_mode; - if (priv->video_standard < XC4000_BG_PAL_A2) { - if (type & NOGD) - video_mode &= 0xFF7F; - } else if (priv->video_standard < XC4000_I_PAL_NICAM) { - if (priv->firm_version == 0x0102) - video_mode &= 0xFEFF; - if (audio_std & XC4000_AUDIO_STD_B) - video_mode |= 0x0080; - } - ret = xc_set_tv_standard(priv, video_mode, audio_mode); - if (ret != 0) { - printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n"); - goto fail; - } - } - - if (xc_write_reg(priv, XREG_D_CODE, 0) == 0) - ret = 0; - if (xc_write_reg(priv, XREG_AMPLITUDE, 1) != 0) - ret = -EREMOTEIO; - if (priv->set_smoothedcvbs != 0) { - if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0) - ret = -EREMOTEIO; - } - if (ret != 0) { - printk(KERN_ERR "xc4000: setting registers failed\n"); - goto fail; - } - - xc_tune_channel(priv, priv->freq_hz); - - ret = 0; - -fail: - mutex_unlock(&priv->lock); - - return ret; -} - -static int xc4000_get_signal(struct dvb_frontend *fe, u16 *strength) -{ - struct xc4000_priv *priv = fe->tuner_priv; - u16 value = 0; - int rc; - - mutex_lock(&priv->lock); - rc = xc4000_readreg(priv, XREG_SIGNAL_LEVEL, &value); - mutex_unlock(&priv->lock); - - if (rc < 0) - goto ret; - - /* Informations from real testing of DVB-T and radio part, - coeficient for one dB is 0xff. - */ - tuner_dbg("Signal strength: -%ddB (%05d)\n", value >> 8, value); - - /* all known digital modes */ - if ((priv->video_standard == XC4000_DTV6) || - (priv->video_standard == XC4000_DTV7) || - (priv->video_standard == XC4000_DTV7_8) || - (priv->video_standard == XC4000_DTV8)) - goto digital; - - /* Analog mode has NOISE LEVEL important, signal - depends only on gain of antenna and amplifiers, - but it doesn't tell anything about real quality - of reception. - */ - mutex_lock(&priv->lock); - rc = xc4000_readreg(priv, XREG_NOISE_LEVEL, &value); - mutex_unlock(&priv->lock); - - tuner_dbg("Noise level: %ddB (%05d)\n", value >> 8, value); - - /* highest noise level: 32dB */ - if (value >= 0x2000) { - value = 0; - } else { - value = ~value << 3; - } - - goto ret; - - /* Digital mode has SIGNAL LEVEL important and real - noise level is stored in demodulator registers. - */ -digital: - /* best signal: -50dB */ - if (value <= 0x3200) { - value = 0xffff; - /* minimum: -114dB - should be 0x7200 but real zero is 0x713A */ - } else if (value >= 0x713A) { - value = 0; - } else { - value = ~(value - 0x3200) << 2; - } - -ret: - *strength = value; - - return rc; -} - -static int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq) -{ - struct xc4000_priv *priv = fe->tuner_priv; - - *freq = priv->freq_hz; - - if (debug) { - mutex_lock(&priv->lock); - if ((priv->cur_fw.type - & (BASE | FM | DTV6 | DTV7 | DTV78 | DTV8)) == BASE) { - u16 snr = 0; - if (xc4000_readreg(priv, XREG_SNR, &snr) == 0) { - mutex_unlock(&priv->lock); - dprintk(1, "%s() freq = %u, SNR = %d\n", - __func__, *freq, snr); - return 0; - } - } - mutex_unlock(&priv->lock); - } - - dprintk(1, "%s()\n", __func__); - - return 0; -} - -static int xc4000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) -{ - struct xc4000_priv *priv = fe->tuner_priv; - dprintk(1, "%s()\n", __func__); - - *bw = priv->bandwidth; - return 0; -} - -static int xc4000_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct xc4000_priv *priv = fe->tuner_priv; - u16 lock_status = 0; - - mutex_lock(&priv->lock); - - if (priv->cur_fw.type & BASE) - xc_get_lock_status(priv, &lock_status); - - *status = (lock_status == 1 ? - TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO : 0); - if (priv->cur_fw.type & (DTV6 | DTV7 | DTV78 | DTV8)) - *status &= (~TUNER_STATUS_STEREO); - - mutex_unlock(&priv->lock); - - dprintk(2, "%s() lock_status = %d\n", __func__, lock_status); - - return 0; -} - -static int xc4000_sleep(struct dvb_frontend *fe) -{ - struct xc4000_priv *priv = fe->tuner_priv; - int ret = 0; - - dprintk(1, "%s()\n", __func__); - - mutex_lock(&priv->lock); - - /* Avoid firmware reload on slow devices */ - if ((no_poweroff == 2 || - (no_poweroff == 0 && priv->default_pm != 0)) && - (priv->cur_fw.type & BASE) != 0) { - /* force reset and firmware reload */ - priv->cur_fw.type = XC_POWERED_DOWN; - - if (xc_write_reg(priv, XREG_POWER_DOWN, 0) != 0) { - printk(KERN_ERR - "xc4000: %s() unable to shutdown tuner\n", - __func__); - ret = -EREMOTEIO; - } - msleep(20); - } - - mutex_unlock(&priv->lock); - - return ret; -} - -static int xc4000_init(struct dvb_frontend *fe) -{ - dprintk(1, "%s()\n", __func__); - - return 0; -} - -static int xc4000_release(struct dvb_frontend *fe) -{ - struct xc4000_priv *priv = fe->tuner_priv; - - dprintk(1, "%s()\n", __func__); - - mutex_lock(&xc4000_list_mutex); - - if (priv) - hybrid_tuner_release_state(priv); - - mutex_unlock(&xc4000_list_mutex); - - fe->tuner_priv = NULL; - - return 0; -} - -static const struct dvb_tuner_ops xc4000_tuner_ops = { - .info = { - .name = "Xceive XC4000", - .frequency_min = 1000000, - .frequency_max = 1023000000, - .frequency_step = 50000, - }, - - .release = xc4000_release, - .init = xc4000_init, - .sleep = xc4000_sleep, - - .set_params = xc4000_set_params, - .set_analog_params = xc4000_set_analog_params, - .get_frequency = xc4000_get_frequency, - .get_rf_strength = xc4000_get_signal, - .get_bandwidth = xc4000_get_bandwidth, - .get_status = xc4000_get_status -}; - -struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct xc4000_config *cfg) -{ - struct xc4000_priv *priv = NULL; - int instance; - u16 id = 0; - - dprintk(1, "%s(%d-%04x)\n", __func__, - i2c ? i2c_adapter_id(i2c) : -1, - cfg ? cfg->i2c_address : -1); - - mutex_lock(&xc4000_list_mutex); - - instance = hybrid_tuner_request_state(struct xc4000_priv, priv, - hybrid_tuner_instance_list, - i2c, cfg->i2c_address, "xc4000"); - switch (instance) { - case 0: - goto fail; - break; - case 1: - /* new tuner instance */ - priv->bandwidth = 6000000; - /* set default configuration */ - priv->if_khz = 4560; - priv->default_pm = 0; - priv->dvb_amplitude = 134; - priv->set_smoothedcvbs = 1; - mutex_init(&priv->lock); - fe->tuner_priv = priv; - break; - default: - /* existing tuner instance */ - fe->tuner_priv = priv; - break; - } - - if (cfg->if_khz != 0) { - /* copy configuration if provided by the caller */ - priv->if_khz = cfg->if_khz; - priv->default_pm = cfg->default_pm; - priv->dvb_amplitude = cfg->dvb_amplitude; - priv->set_smoothedcvbs = cfg->set_smoothedcvbs; - } - - /* Check if firmware has been loaded. It is possible that another - instance of the driver has loaded the firmware. - */ - - if (instance == 1) { - if (xc4000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) - goto fail; - } else { - id = ((priv->cur_fw.type & BASE) != 0 ? - priv->hwmodel : XC_PRODUCT_ID_FW_NOT_LOADED); - } - - switch (id) { - case XC_PRODUCT_ID_XC4000: - case XC_PRODUCT_ID_XC4100: - printk(KERN_INFO - "xc4000: Successfully identified at address 0x%02x\n", - cfg->i2c_address); - printk(KERN_INFO - "xc4000: Firmware has been loaded previously\n"); - break; - case XC_PRODUCT_ID_FW_NOT_LOADED: - printk(KERN_INFO - "xc4000: Successfully identified at address 0x%02x\n", - cfg->i2c_address); - printk(KERN_INFO - "xc4000: Firmware has not been loaded previously\n"); - break; - default: - printk(KERN_ERR - "xc4000: Device not found at addr 0x%02x (0x%x)\n", - cfg->i2c_address, id); - goto fail; - } - - mutex_unlock(&xc4000_list_mutex); - - memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - if (instance == 1) { - int ret; - mutex_lock(&priv->lock); - ret = xc4000_fwupload(fe); - mutex_unlock(&priv->lock); - if (ret != 0) - goto fail2; - } - - return fe; -fail: - mutex_unlock(&xc4000_list_mutex); -fail2: - xc4000_release(fe); - return NULL; -} -EXPORT_SYMBOL(xc4000_attach); - -MODULE_AUTHOR("Steven Toth, Davide Ferri"); -MODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/xc4000.h b/drivers/media/common/tuners/xc4000.h deleted file mode 100644 index e6a44d151cbd..000000000000 --- a/drivers/media/common/tuners/xc4000.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Driver for Xceive XC4000 "QAM/8VSB single chip tuner" - * - * Copyright (c) 2007 Steven Toth - * - * 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 __XC4000_H__ -#define __XC4000_H__ - -#include - -struct dvb_frontend; -struct i2c_adapter; - -struct xc4000_config { - u8 i2c_address; - /* if non-zero, power management is enabled by default */ - u8 default_pm; - /* value to be written to XREG_AMPLITUDE in DVB-T mode (0: no write) */ - u8 dvb_amplitude; - /* if non-zero, register 0x0E is set to filter analog TV video output */ - u8 set_smoothedcvbs; - /* IF for DVB-T */ - u32 if_khz; -}; - -/* xc4000 callback command */ -#define XC4000_TUNER_RESET 0 - -/* For each bridge framework, when it attaches either analog or digital, - * it has to store a reference back to its _core equivalent structure, - * so that it can service the hardware by steering gpio's etc. - * Each bridge implementation is different so cast devptr accordingly. - * The xc4000 driver cares not for this value, other than ensuring - * it's passed back to a bridge during tuner_callback(). - */ - -#if defined(CONFIG_MEDIA_TUNER_XC4000) || (defined(CONFIG_MEDIA_TUNER_XC4000_MODULE) && defined(MODULE)) -extern struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct xc4000_config *cfg); -#else -static inline struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct xc4000_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c deleted file mode 100644 index dc93cf338f36..000000000000 --- a/drivers/media/common/tuners/xc5000.c +++ /dev/null @@ -1,1366 +0,0 @@ -/* - * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" - * - * Copyright (c) 2007 Xceive Corporation - * Copyright (c) 2007 Steven Toth - * Copyright (c) 2009 Devin Heitmueller - * - * 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 -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" - -#include "xc5000.h" -#include "tuner-i2c.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -static int no_poweroff; -module_param(no_poweroff, int, 0644); -MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" - "\t\t1 keep device energized and with tuner ready all the times.\n" - "\t\tFaster, but consumes more power and keeps the device hotter"); - -static DEFINE_MUTEX(xc5000_list_mutex); -static LIST_HEAD(hybrid_tuner_instance_list); - -#define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) - -struct xc5000_priv { - struct tuner_i2c_props i2c_props; - struct list_head hybrid_tuner_instance_list; - - u32 if_khz; - u16 xtal_khz; - u32 freq_hz; - u32 bandwidth; - u8 video_standard; - u8 rf_mode; - u8 radio_input; - - int chip_id; - u16 pll_register_no; - u8 init_status_supported; - u8 fw_checksum_supported; -}; - -/* Misc Defines */ -#define MAX_TV_STANDARD 24 -#define XC_MAX_I2C_WRITE_LENGTH 64 - -/* Signal Types */ -#define XC_RF_MODE_AIR 0 -#define XC_RF_MODE_CABLE 1 - -/* Result codes */ -#define XC_RESULT_SUCCESS 0 -#define XC_RESULT_RESET_FAILURE 1 -#define XC_RESULT_I2C_WRITE_FAILURE 2 -#define XC_RESULT_I2C_READ_FAILURE 3 -#define XC_RESULT_OUT_OF_RANGE 5 - -/* Product id */ -#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 -#define XC_PRODUCT_ID_FW_LOADED 0x1388 - -/* Registers */ -#define XREG_INIT 0x00 -#define XREG_VIDEO_MODE 0x01 -#define XREG_AUDIO_MODE 0x02 -#define XREG_RF_FREQ 0x03 -#define XREG_D_CODE 0x04 -#define XREG_IF_OUT 0x05 -#define XREG_SEEK_MODE 0x07 -#define XREG_POWER_DOWN 0x0A /* Obsolete */ -/* Set the output amplitude - SIF for analog, DTVP/DTVN for digital */ -#define XREG_OUTPUT_AMP 0x0B -#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */ -#define XREG_SMOOTHEDCVBS 0x0E -#define XREG_XTALFREQ 0x0F -#define XREG_FINERFREQ 0x10 -#define XREG_DDIMODE 0x11 - -#define XREG_ADC_ENV 0x00 -#define XREG_QUALITY 0x01 -#define XREG_FRAME_LINES 0x02 -#define XREG_HSYNC_FREQ 0x03 -#define XREG_LOCK 0x04 -#define XREG_FREQ_ERROR 0x05 -#define XREG_SNR 0x06 -#define XREG_VERSION 0x07 -#define XREG_PRODUCT_ID 0x08 -#define XREG_BUSY 0x09 -#define XREG_BUILD 0x0D -#define XREG_TOTALGAIN 0x0F -#define XREG_FW_CHECKSUM 0x12 -#define XREG_INIT_STATUS 0x13 - -/* - Basic firmware description. This will remain with - the driver for documentation purposes. - - This represents an I2C firmware file encoded as a - string of unsigned char. Format is as follows: - - char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB - char[1 ]=len0_LSB -> length of first write transaction - char[2 ]=data0 -> first byte to be sent - char[3 ]=data1 - char[4 ]=data2 - char[ ]=... - char[M ]=dataN -> last byte to be sent - char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB - char[M+2]=len1_LSB -> length of second write transaction - char[M+3]=data0 - char[M+4]=data1 - ... - etc. - - The [len] value should be interpreted as follows: - - len= len_MSB _ len_LSB - len=1111_1111_1111_1111 : End of I2C_SEQUENCE - len=0000_0000_0000_0000 : Reset command: Do hardware reset - len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) - len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms - - For the RESET and WAIT commands, the two following bytes will contain - immediately the length of the following transaction. - -*/ -struct XC_TV_STANDARD { - char *Name; - u16 AudioMode; - u16 VideoMode; -}; - -/* Tuner standards */ -#define MN_NTSC_PAL_BTSC 0 -#define MN_NTSC_PAL_A2 1 -#define MN_NTSC_PAL_EIAJ 2 -#define MN_NTSC_PAL_Mono 3 -#define BG_PAL_A2 4 -#define BG_PAL_NICAM 5 -#define BG_PAL_MONO 6 -#define I_PAL_NICAM 7 -#define I_PAL_NICAM_MONO 8 -#define DK_PAL_A2 9 -#define DK_PAL_NICAM 10 -#define DK_PAL_MONO 11 -#define DK_SECAM_A2DK1 12 -#define DK_SECAM_A2LDK3 13 -#define DK_SECAM_A2MONO 14 -#define L_SECAM_NICAM 15 -#define LC_SECAM_NICAM 16 -#define DTV6 17 -#define DTV8 18 -#define DTV7_8 19 -#define DTV7 20 -#define FM_Radio_INPUT2 21 -#define FM_Radio_INPUT1 22 -#define FM_Radio_INPUT1_MONO 23 - -static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { - {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020}, - {"M/N-NTSC/PAL-A2", 0x0600, 0x8020}, - {"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020}, - {"M/N-NTSC/PAL-Mono", 0x0478, 0x8020}, - {"B/G-PAL-A2", 0x0A00, 0x8049}, - {"B/G-PAL-NICAM", 0x0C04, 0x8049}, - {"B/G-PAL-MONO", 0x0878, 0x8059}, - {"I-PAL-NICAM", 0x1080, 0x8009}, - {"I-PAL-NICAM-MONO", 0x0E78, 0x8009}, - {"D/K-PAL-A2", 0x1600, 0x8009}, - {"D/K-PAL-NICAM", 0x0E80, 0x8009}, - {"D/K-PAL-MONO", 0x1478, 0x8009}, - {"D/K-SECAM-A2 DK1", 0x1200, 0x8009}, - {"D/K-SECAM-A2 L/DK3", 0x0E00, 0x8009}, - {"D/K-SECAM-A2 MONO", 0x1478, 0x8009}, - {"L-SECAM-NICAM", 0x8E82, 0x0009}, - {"L'-SECAM-NICAM", 0x8E82, 0x4009}, - {"DTV6", 0x00C0, 0x8002}, - {"DTV8", 0x00C0, 0x800B}, - {"DTV7/8", 0x00C0, 0x801B}, - {"DTV7", 0x00C0, 0x8007}, - {"FM Radio-INPUT2", 0x9802, 0x9002}, - {"FM Radio-INPUT1", 0x0208, 0x9002}, - {"FM Radio-INPUT1_MONO", 0x0278, 0x9002} -}; - - -struct xc5000_fw_cfg { - char *name; - u16 size; - u16 pll_reg; - u8 init_status_supported; - u8 fw_checksum_supported; -}; - -#define XC5000A_FIRMWARE "dvb-fe-xc5000-1.6.114.fw" -static const struct xc5000_fw_cfg xc5000a_1_6_114 = { - .name = XC5000A_FIRMWARE, - .size = 12401, - .pll_reg = 0x806c, -}; - -#define XC5000C_FIRMWARE "dvb-fe-xc5000c-4.1.30.7.fw" -static const struct xc5000_fw_cfg xc5000c_41_024_5 = { - .name = XC5000C_FIRMWARE, - .size = 16497, - .pll_reg = 0x13, - .init_status_supported = 1, - .fw_checksum_supported = 1, -}; - -static inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id) -{ - switch (chip_id) { - default: - case XC5000A: - return &xc5000a_1_6_114; - case XC5000C: - return &xc5000c_41_024_5; - } -} - -static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force); -static int xc5000_is_firmware_loaded(struct dvb_frontend *fe); -static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val); -static int xc5000_TunerReset(struct dvb_frontend *fe); - -static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) -{ - struct i2c_msg msg = { .addr = priv->i2c_props.addr, - .flags = 0, .buf = buf, .len = len }; - - if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { - printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len); - return XC_RESULT_I2C_WRITE_FAILURE; - } - return XC_RESULT_SUCCESS; -} - -#if 0 -/* This routine is never used because the only time we read data from the - i2c bus is when we read registers, and we want that to be an atomic i2c - transaction in case we are on a multi-master bus */ -static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) -{ - struct i2c_msg msg = { .addr = priv->i2c_props.addr, - .flags = I2C_M_RD, .buf = buf, .len = len }; - - if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { - printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len); - return -EREMOTEIO; - } - return 0; -} -#endif - -static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) -{ - u8 buf[2] = { reg >> 8, reg & 0xff }; - u8 bval[2] = { 0, 0 }; - struct i2c_msg msg[2] = { - { .addr = priv->i2c_props.addr, - .flags = 0, .buf = &buf[0], .len = 2 }, - { .addr = priv->i2c_props.addr, - .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, - }; - - if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) { - printk(KERN_WARNING "xc5000: I2C read failed\n"); - return -EREMOTEIO; - } - - *val = (bval[0] << 8) | bval[1]; - return XC_RESULT_SUCCESS; -} - -static void xc_wait(int wait_ms) -{ - msleep(wait_ms); -} - -static int xc5000_TunerReset(struct dvb_frontend *fe) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret; - - dprintk(1, "%s()\n", __func__); - - if (fe->callback) { - ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ? - fe->dvb->priv : - priv->i2c_props.adap->algo_data, - DVB_FRONTEND_COMPONENT_TUNER, - XC5000_TUNER_RESET, 0); - if (ret) { - printk(KERN_ERR "xc5000: reset failed\n"); - return XC_RESULT_RESET_FAILURE; - } - } else { - printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n"); - return XC_RESULT_RESET_FAILURE; - } - return XC_RESULT_SUCCESS; -} - -static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) -{ - u8 buf[4]; - int WatchDogTimer = 100; - int result; - - buf[0] = (regAddr >> 8) & 0xFF; - buf[1] = regAddr & 0xFF; - buf[2] = (i2cData >> 8) & 0xFF; - buf[3] = i2cData & 0xFF; - result = xc_send_i2c_data(priv, buf, 4); - if (result == XC_RESULT_SUCCESS) { - /* wait for busy flag to clear */ - while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) { - result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf); - if (result == XC_RESULT_SUCCESS) { - if ((buf[0] == 0) && (buf[1] == 0)) { - /* busy flag cleared */ - break; - } else { - xc_wait(5); /* wait 5 ms */ - WatchDogTimer--; - } - } - } - } - if (WatchDogTimer <= 0) - result = XC_RESULT_I2C_WRITE_FAILURE; - - return result; -} - -static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) -{ - struct xc5000_priv *priv = fe->tuner_priv; - - int i, nbytes_to_send, result; - unsigned int len, pos, index; - u8 buf[XC_MAX_I2C_WRITE_LENGTH]; - - index = 0; - while ((i2c_sequence[index] != 0xFF) || - (i2c_sequence[index + 1] != 0xFF)) { - len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; - if (len == 0x0000) { - /* RESET command */ - result = xc5000_TunerReset(fe); - index += 2; - if (result != XC_RESULT_SUCCESS) - return result; - } else if (len & 0x8000) { - /* WAIT command */ - xc_wait(len & 0x7FFF); - index += 2; - } else { - /* Send i2c data whilst ensuring individual transactions - * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. - */ - index += 2; - buf[0] = i2c_sequence[index]; - buf[1] = i2c_sequence[index + 1]; - pos = 2; - while (pos < len) { - if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) - nbytes_to_send = - XC_MAX_I2C_WRITE_LENGTH; - else - nbytes_to_send = (len - pos + 2); - for (i = 2; i < nbytes_to_send; i++) { - buf[i] = i2c_sequence[index + pos + - i - 2]; - } - result = xc_send_i2c_data(priv, buf, - nbytes_to_send); - - if (result != XC_RESULT_SUCCESS) - return result; - - pos += nbytes_to_send - 2; - } - index += len; - } - } - return XC_RESULT_SUCCESS; -} - -static int xc_initialize(struct xc5000_priv *priv) -{ - dprintk(1, "%s()\n", __func__); - return xc_write_reg(priv, XREG_INIT, 0); -} - -static int xc_SetTVStandard(struct xc5000_priv *priv, - u16 VideoMode, u16 AudioMode) -{ - int ret; - dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, VideoMode, AudioMode); - dprintk(1, "%s() Standard = %s\n", - __func__, - XC5000_Standard[priv->video_standard].Name); - - ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode); - if (ret == XC_RESULT_SUCCESS) - ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode); - - return ret; -} - -static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) -{ - dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, - rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); - - if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) { - rf_mode = XC_RF_MODE_CABLE; - printk(KERN_ERR - "%s(), Invalid mode, defaulting to CABLE", - __func__); - } - return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); -} - -static const struct dvb_tuner_ops xc5000_tuner_ops; - -static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz) -{ - u16 freq_code; - - dprintk(1, "%s(%u)\n", __func__, freq_hz); - - if ((freq_hz > xc5000_tuner_ops.info.frequency_max) || - (freq_hz < xc5000_tuner_ops.info.frequency_min)) - return XC_RESULT_OUT_OF_RANGE; - - freq_code = (u16)(freq_hz / 15625); - - /* Starting in firmware version 1.1.44, Xceive recommends using the - FINERFREQ for all normal tuning (the doc indicates reg 0x03 should - only be used for fast scanning for channel lock) */ - return xc_write_reg(priv, XREG_FINERFREQ, freq_code); -} - - -static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz) -{ - u32 freq_code = (freq_khz * 1024)/1000; - dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n", - __func__, freq_khz, freq_code); - - return xc_write_reg(priv, XREG_IF_OUT, freq_code); -} - - -static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope) -{ - return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope); -} - -static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) -{ - int result; - u16 regData; - u32 tmp; - - result = xc5000_readreg(priv, XREG_FREQ_ERROR, ®Data); - if (result != XC_RESULT_SUCCESS) - return result; - - tmp = (u32)regData; - (*freq_error_hz) = (tmp * 15625) / 1000; - return result; -} - -static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status) -{ - return xc5000_readreg(priv, XREG_LOCK, lock_status); -} - -static int xc_get_version(struct xc5000_priv *priv, - u8 *hw_majorversion, u8 *hw_minorversion, - u8 *fw_majorversion, u8 *fw_minorversion) -{ - u16 data; - int result; - - result = xc5000_readreg(priv, XREG_VERSION, &data); - if (result != XC_RESULT_SUCCESS) - return result; - - (*hw_majorversion) = (data >> 12) & 0x0F; - (*hw_minorversion) = (data >> 8) & 0x0F; - (*fw_majorversion) = (data >> 4) & 0x0F; - (*fw_minorversion) = data & 0x0F; - - return 0; -} - -static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev) -{ - return xc5000_readreg(priv, XREG_BUILD, buildrev); -} - -static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz) -{ - u16 regData; - int result; - - result = xc5000_readreg(priv, XREG_HSYNC_FREQ, ®Data); - if (result != XC_RESULT_SUCCESS) - return result; - - (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; - return result; -} - -static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines) -{ - return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines); -} - -static int xc_get_quality(struct xc5000_priv *priv, u16 *quality) -{ - return xc5000_readreg(priv, XREG_QUALITY, quality); -} - -static int xc_get_analogsnr(struct xc5000_priv *priv, u16 *snr) -{ - return xc5000_readreg(priv, XREG_SNR, snr); -} - -static int xc_get_totalgain(struct xc5000_priv *priv, u16 *totalgain) -{ - return xc5000_readreg(priv, XREG_TOTALGAIN, totalgain); -} - -static u16 WaitForLock(struct xc5000_priv *priv) -{ - u16 lockState = 0; - int watchDogCount = 40; - - while ((lockState == 0) && (watchDogCount > 0)) { - xc_get_lock_status(priv, &lockState); - if (lockState != 1) { - xc_wait(5); - watchDogCount--; - } - } - return lockState; -} - -#define XC_TUNE_ANALOG 0 -#define XC_TUNE_DIGITAL 1 -static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode) -{ - int found = 0; - - dprintk(1, "%s(%u)\n", __func__, freq_hz); - - if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS) - return 0; - - if (mode == XC_TUNE_ANALOG) { - if (WaitForLock(priv) == 1) - found = 1; - } - - return found; -} - -static int xc_set_xtal(struct dvb_frontend *fe) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret = XC_RESULT_SUCCESS; - - switch (priv->chip_id) { - default: - case XC5000A: - /* 32.000 MHz xtal is default */ - break; - case XC5000C: - switch (priv->xtal_khz) { - default: - case 32000: - /* 32.000 MHz xtal is default */ - break; - case 31875: - /* 31.875 MHz xtal configuration */ - ret = xc_write_reg(priv, 0x000f, 0x8081); - break; - } - break; - } - return ret; -} - -static int xc5000_fwupload(struct dvb_frontend *fe) -{ - struct xc5000_priv *priv = fe->tuner_priv; - const struct firmware *fw; - int ret; - const struct xc5000_fw_cfg *desired_fw = - xc5000_assign_firmware(priv->chip_id); - priv->pll_register_no = desired_fw->pll_reg; - priv->init_status_supported = desired_fw->init_status_supported; - priv->fw_checksum_supported = desired_fw->fw_checksum_supported; - - /* request the firmware, this will block and timeout */ - printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", - desired_fw->name); - - ret = request_firmware(&fw, desired_fw->name, - priv->i2c_props.adap->dev.parent); - if (ret) { - printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); - ret = XC_RESULT_RESET_FAILURE; - goto out; - } else { - printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n", - fw->size); - ret = XC_RESULT_SUCCESS; - } - - if (fw->size != desired_fw->size) { - printk(KERN_ERR "xc5000: firmware incorrect size\n"); - ret = XC_RESULT_RESET_FAILURE; - } else { - printk(KERN_INFO "xc5000: firmware uploading...\n"); - ret = xc_load_i2c_sequence(fe, fw->data); - if (XC_RESULT_SUCCESS == ret) - ret = xc_set_xtal(fe); - if (XC_RESULT_SUCCESS == ret) - printk(KERN_INFO "xc5000: firmware upload complete...\n"); - else - printk(KERN_ERR "xc5000: firmware upload failed...\n"); - } - -out: - release_firmware(fw); - return ret; -} - -static void xc_debug_dump(struct xc5000_priv *priv) -{ - u16 adc_envelope; - u32 freq_error_hz = 0; - u16 lock_status; - u32 hsync_freq_hz = 0; - u16 frame_lines; - u16 quality; - u16 snr; - u16 totalgain; - u8 hw_majorversion = 0, hw_minorversion = 0; - u8 fw_majorversion = 0, fw_minorversion = 0; - u16 fw_buildversion = 0; - u16 regval; - - /* Wait for stats to stabilize. - * Frame Lines needs two frame times after initial lock - * before it is valid. - */ - xc_wait(100); - - xc_get_ADC_Envelope(priv, &adc_envelope); - dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); - - xc_get_frequency_error(priv, &freq_error_hz); - dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); - - xc_get_lock_status(priv, &lock_status); - dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", - lock_status); - - xc_get_version(priv, &hw_majorversion, &hw_minorversion, - &fw_majorversion, &fw_minorversion); - xc_get_buildversion(priv, &fw_buildversion); - dprintk(1, "*** HW: V%d.%d, FW: V %d.%d.%d\n", - hw_majorversion, hw_minorversion, - fw_majorversion, fw_minorversion, fw_buildversion); - - xc_get_hsync_freq(priv, &hsync_freq_hz); - dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz); - - xc_get_frame_lines(priv, &frame_lines); - dprintk(1, "*** Frame lines = %d\n", frame_lines); - - xc_get_quality(priv, &quality); - dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality & 0x07); - - xc_get_analogsnr(priv, &snr); - dprintk(1, "*** Unweighted analog SNR = %d dB\n", snr & 0x3f); - - xc_get_totalgain(priv, &totalgain); - dprintk(1, "*** Total gain = %d.%d dB\n", totalgain / 256, - (totalgain % 256) * 100 / 256); - - if (priv->pll_register_no) { - xc5000_readreg(priv, priv->pll_register_no, ®val); - dprintk(1, "*** PLL lock status = 0x%04x\n", regval); - } -} - -static int xc5000_set_params(struct dvb_frontend *fe) -{ - int ret, b; - struct xc5000_priv *priv = fe->tuner_priv; - u32 bw = fe->dtv_property_cache.bandwidth_hz; - u32 freq = fe->dtv_property_cache.frequency; - u32 delsys = fe->dtv_property_cache.delivery_system; - - if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) { - dprintk(1, "Unable to load firmware and init tuner\n"); - return -EINVAL; - } - - dprintk(1, "%s() frequency=%d (Hz)\n", __func__, freq); - - switch (delsys) { - case SYS_ATSC: - dprintk(1, "%s() VSB modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_AIR; - priv->freq_hz = freq - 1750000; - priv->video_standard = DTV6; - break; - case SYS_DVBC_ANNEX_B: - dprintk(1, "%s() QAM modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_CABLE; - priv->freq_hz = freq - 1750000; - priv->video_standard = DTV6; - break; - case SYS_ISDBT: - /* All ISDB-T are currently for 6 MHz bw */ - if (!bw) - bw = 6000000; - /* fall to OFDM handling */ - case SYS_DMBTH: - case SYS_DVBT: - case SYS_DVBT2: - dprintk(1, "%s() OFDM\n", __func__); - switch (bw) { - case 6000000: - priv->video_standard = DTV6; - priv->freq_hz = freq - 1750000; - break; - case 7000000: - priv->video_standard = DTV7; - priv->freq_hz = freq - 2250000; - break; - case 8000000: - priv->video_standard = DTV8; - priv->freq_hz = freq - 2750000; - break; - default: - printk(KERN_ERR "xc5000 bandwidth not set!\n"); - return -EINVAL; - } - priv->rf_mode = XC_RF_MODE_AIR; - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - dprintk(1, "%s() QAM modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_CABLE; - if (bw <= 6000000) { - priv->video_standard = DTV6; - priv->freq_hz = freq - 1750000; - b = 6; - } else if (bw <= 7000000) { - priv->video_standard = DTV7; - priv->freq_hz = freq - 2250000; - b = 7; - } else { - priv->video_standard = DTV7_8; - priv->freq_hz = freq - 2750000; - b = 8; - } - dprintk(1, "%s() Bandwidth %dMHz (%d)\n", __func__, - b, bw); - break; - default: - printk(KERN_ERR "xc5000: delivery system is not supported!\n"); - return -EINVAL; - } - - dprintk(1, "%s() frequency=%d (compensated to %d)\n", - __func__, freq, priv->freq_hz); - - ret = xc_SetSignalSource(priv, priv->rf_mode); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR - "xc5000: xc_SetSignalSource(%d) failed\n", - priv->rf_mode); - return -EREMOTEIO; - } - - ret = xc_SetTVStandard(priv, - XC5000_Standard[priv->video_standard].VideoMode, - XC5000_Standard[priv->video_standard].AudioMode); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); - return -EREMOTEIO; - } - - ret = xc_set_IF_frequency(priv, priv->if_khz); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", - priv->if_khz); - return -EIO; - } - - xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a); - - xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); - - if (debug) - xc_debug_dump(priv); - - priv->bandwidth = bw; - - return 0; -} - -static int xc5000_is_firmware_loaded(struct dvb_frontend *fe) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret; - u16 id; - - ret = xc5000_readreg(priv, XREG_PRODUCT_ID, &id); - if (ret == XC_RESULT_SUCCESS) { - if (id == XC_PRODUCT_ID_FW_NOT_LOADED) - ret = XC_RESULT_RESET_FAILURE; - else - ret = XC_RESULT_SUCCESS; - } - - dprintk(1, "%s() returns %s id = 0x%x\n", __func__, - ret == XC_RESULT_SUCCESS ? "True" : "False", id); - return ret; -} - -static int xc5000_set_tv_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct xc5000_priv *priv = fe->tuner_priv; - u16 pll_lock_status; - int ret; - - dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", - __func__, params->frequency); - - /* Fix me: it could be air. */ - priv->rf_mode = params->mode; - if (params->mode > XC_RF_MODE_CABLE) - priv->rf_mode = XC_RF_MODE_CABLE; - - /* params->frequency is in units of 62.5khz */ - priv->freq_hz = params->frequency * 62500; - - /* FIX ME: Some video standards may have several possible audio - standards. We simply default to one of them here. - */ - if (params->std & V4L2_STD_MN) { - /* default to BTSC audio standard */ - priv->video_standard = MN_NTSC_PAL_BTSC; - goto tune_channel; - } - - if (params->std & V4L2_STD_PAL_BG) { - /* default to NICAM audio standard */ - priv->video_standard = BG_PAL_NICAM; - goto tune_channel; - } - - if (params->std & V4L2_STD_PAL_I) { - /* default to NICAM audio standard */ - priv->video_standard = I_PAL_NICAM; - goto tune_channel; - } - - if (params->std & V4L2_STD_PAL_DK) { - /* default to NICAM audio standard */ - priv->video_standard = DK_PAL_NICAM; - goto tune_channel; - } - - if (params->std & V4L2_STD_SECAM_DK) { - /* default to A2 DK1 audio standard */ - priv->video_standard = DK_SECAM_A2DK1; - goto tune_channel; - } - - if (params->std & V4L2_STD_SECAM_L) { - priv->video_standard = L_SECAM_NICAM; - goto tune_channel; - } - - if (params->std & V4L2_STD_SECAM_LC) { - priv->video_standard = LC_SECAM_NICAM; - goto tune_channel; - } - -tune_channel: - ret = xc_SetSignalSource(priv, priv->rf_mode); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR - "xc5000: xc_SetSignalSource(%d) failed\n", - priv->rf_mode); - return -EREMOTEIO; - } - - ret = xc_SetTVStandard(priv, - XC5000_Standard[priv->video_standard].VideoMode, - XC5000_Standard[priv->video_standard].AudioMode); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); - return -EREMOTEIO; - } - - xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); - - xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); - - if (debug) - xc_debug_dump(priv); - - if (priv->pll_register_no != 0) { - msleep(20); - xc5000_readreg(priv, priv->pll_register_no, &pll_lock_status); - if (pll_lock_status > 63) { - /* PLL is unlocked, force reload of the firmware */ - dprintk(1, "xc5000: PLL not locked (0x%x). Reloading...\n", - pll_lock_status); - if (xc_load_fw_and_init_tuner(fe, 1) != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: Unable to reload fw\n"); - return -EREMOTEIO; - } - goto tune_channel; - } - } - - return 0; -} - -static int xc5000_set_radio_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret = -EINVAL; - u8 radio_input; - - dprintk(1, "%s() frequency=%d (in units of khz)\n", - __func__, params->frequency); - - if (priv->radio_input == XC5000_RADIO_NOT_CONFIGURED) { - dprintk(1, "%s() radio input not configured\n", __func__); - return -EINVAL; - } - - if (priv->radio_input == XC5000_RADIO_FM1) - radio_input = FM_Radio_INPUT1; - else if (priv->radio_input == XC5000_RADIO_FM2) - radio_input = FM_Radio_INPUT2; - else if (priv->radio_input == XC5000_RADIO_FM1_MONO) - radio_input = FM_Radio_INPUT1_MONO; - else { - dprintk(1, "%s() unknown radio input %d\n", __func__, - priv->radio_input); - return -EINVAL; - } - - priv->freq_hz = params->frequency * 125 / 2; - - priv->rf_mode = XC_RF_MODE_AIR; - - ret = xc_SetTVStandard(priv, XC5000_Standard[radio_input].VideoMode, - XC5000_Standard[radio_input].AudioMode); - - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); - return -EREMOTEIO; - } - - ret = xc_SetSignalSource(priv, priv->rf_mode); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR - "xc5000: xc_SetSignalSource(%d) failed\n", - priv->rf_mode); - return -EREMOTEIO; - } - - if ((priv->radio_input == XC5000_RADIO_FM1) || - (priv->radio_input == XC5000_RADIO_FM2)) - xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); - else if (priv->radio_input == XC5000_RADIO_FM1_MONO) - xc_write_reg(priv, XREG_OUTPUT_AMP, 0x06); - - xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); - - return 0; -} - -static int xc5000_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret = -EINVAL; - - if (priv->i2c_props.adap == NULL) - return -EINVAL; - - if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) { - dprintk(1, "Unable to load firmware and init tuner\n"); - return -EINVAL; - } - - switch (params->mode) { - case V4L2_TUNER_RADIO: - ret = xc5000_set_radio_freq(fe, params); - break; - case V4L2_TUNER_ANALOG_TV: - case V4L2_TUNER_DIGITAL_TV: - ret = xc5000_set_tv_freq(fe, params); - break; - } - - return ret; -} - - -static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) -{ - struct xc5000_priv *priv = fe->tuner_priv; - dprintk(1, "%s()\n", __func__); - *freq = priv->freq_hz; - return 0; -} - -static int xc5000_get_if_frequency(struct dvb_frontend *fe, u32 *freq) -{ - struct xc5000_priv *priv = fe->tuner_priv; - dprintk(1, "%s()\n", __func__); - *freq = priv->if_khz * 1000; - return 0; -} - -static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) -{ - struct xc5000_priv *priv = fe->tuner_priv; - dprintk(1, "%s()\n", __func__); - - *bw = priv->bandwidth; - return 0; -} - -static int xc5000_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct xc5000_priv *priv = fe->tuner_priv; - u16 lock_status = 0; - - xc_get_lock_status(priv, &lock_status); - - dprintk(1, "%s() lock_status = 0x%08x\n", __func__, lock_status); - - *status = lock_status; - - return 0; -} - -static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret = XC_RESULT_SUCCESS; - u16 pll_lock_status; - u16 fw_ck; - - if (force || xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) { - -fw_retry: - - ret = xc5000_fwupload(fe); - if (ret != XC_RESULT_SUCCESS) - return ret; - - msleep(20); - - if (priv->fw_checksum_supported) { - if (xc5000_readreg(priv, XREG_FW_CHECKSUM, &fw_ck) - != XC_RESULT_SUCCESS) { - dprintk(1, "%s() FW checksum reading failed.\n", - __func__); - goto fw_retry; - } - - if (fw_ck == 0) { - dprintk(1, "%s() FW checksum failed = 0x%04x\n", - __func__, fw_ck); - goto fw_retry; - } - } - - /* Start the tuner self-calibration process */ - ret |= xc_initialize(priv); - - if (ret != XC_RESULT_SUCCESS) - goto fw_retry; - - /* Wait for calibration to complete. - * We could continue but XC5000 will clock stretch subsequent - * I2C transactions until calibration is complete. This way we - * don't have to rely on clock stretching working. - */ - xc_wait(100); - - if (priv->init_status_supported) { - if (xc5000_readreg(priv, XREG_INIT_STATUS, &fw_ck) != XC_RESULT_SUCCESS) { - dprintk(1, "%s() FW failed reading init status.\n", - __func__); - goto fw_retry; - } - - if (fw_ck == 0) { - dprintk(1, "%s() FW init status failed = 0x%04x\n", __func__, fw_ck); - goto fw_retry; - } - } - - if (priv->pll_register_no) { - xc5000_readreg(priv, priv->pll_register_no, - &pll_lock_status); - if (pll_lock_status > 63) { - /* PLL is unlocked, force reload of the firmware */ - printk(KERN_ERR "xc5000: PLL not running after fwload.\n"); - goto fw_retry; - } - } - - /* Default to "CABLE" mode */ - ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE); - } - - return ret; -} - -static int xc5000_sleep(struct dvb_frontend *fe) -{ - int ret; - - dprintk(1, "%s()\n", __func__); - - /* Avoid firmware reload on slow devices */ - if (no_poweroff) - return 0; - - /* According to Xceive technical support, the "powerdown" register - was removed in newer versions of the firmware. The "supported" - way to sleep the tuner is to pull the reset pin low for 10ms */ - ret = xc5000_TunerReset(fe); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR - "xc5000: %s() unable to shutdown tuner\n", - __func__); - return -EREMOTEIO; - } else - return XC_RESULT_SUCCESS; -} - -static int xc5000_init(struct dvb_frontend *fe) -{ - struct xc5000_priv *priv = fe->tuner_priv; - dprintk(1, "%s()\n", __func__); - - if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: Unable to initialise tuner\n"); - return -EREMOTEIO; - } - - if (debug) - xc_debug_dump(priv); - - return 0; -} - -static int xc5000_release(struct dvb_frontend *fe) -{ - struct xc5000_priv *priv = fe->tuner_priv; - - dprintk(1, "%s()\n", __func__); - - mutex_lock(&xc5000_list_mutex); - - if (priv) - hybrid_tuner_release_state(priv); - - mutex_unlock(&xc5000_list_mutex); - - fe->tuner_priv = NULL; - - return 0; -} - -static int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg) -{ - struct xc5000_priv *priv = fe->tuner_priv; - struct xc5000_config *p = priv_cfg; - - dprintk(1, "%s()\n", __func__); - - if (p->if_khz) - priv->if_khz = p->if_khz; - - if (p->radio_input) - priv->radio_input = p->radio_input; - - return 0; -} - - -static const struct dvb_tuner_ops xc5000_tuner_ops = { - .info = { - .name = "Xceive XC5000", - .frequency_min = 1000000, - .frequency_max = 1023000000, - .frequency_step = 50000, - }, - - .release = xc5000_release, - .init = xc5000_init, - .sleep = xc5000_sleep, - - .set_config = xc5000_set_config, - .set_params = xc5000_set_params, - .set_analog_params = xc5000_set_analog_params, - .get_frequency = xc5000_get_frequency, - .get_if_frequency = xc5000_get_if_frequency, - .get_bandwidth = xc5000_get_bandwidth, - .get_status = xc5000_get_status -}; - -struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - const struct xc5000_config *cfg) -{ - struct xc5000_priv *priv = NULL; - int instance; - u16 id = 0; - - dprintk(1, "%s(%d-%04x)\n", __func__, - i2c ? i2c_adapter_id(i2c) : -1, - cfg ? cfg->i2c_address : -1); - - mutex_lock(&xc5000_list_mutex); - - instance = hybrid_tuner_request_state(struct xc5000_priv, priv, - hybrid_tuner_instance_list, - i2c, cfg->i2c_address, "xc5000"); - switch (instance) { - case 0: - goto fail; - break; - case 1: - /* new tuner instance */ - priv->bandwidth = 6000000; - fe->tuner_priv = priv; - break; - default: - /* existing tuner instance */ - fe->tuner_priv = priv; - break; - } - - if (priv->if_khz == 0) { - /* If the IF hasn't been set yet, use the value provided by - the caller (occurs in hybrid devices where the analog - call to xc5000_attach occurs before the digital side) */ - priv->if_khz = cfg->if_khz; - } - - if (priv->xtal_khz == 0) - priv->xtal_khz = cfg->xtal_khz; - - if (priv->radio_input == 0) - priv->radio_input = cfg->radio_input; - - /* don't override chip id if it's already been set - unless explicitly specified */ - if ((priv->chip_id == 0) || (cfg->chip_id)) - /* use default chip id if none specified, set to 0 so - it can be overridden if this is a hybrid driver */ - priv->chip_id = (cfg->chip_id) ? cfg->chip_id : 0; - - /* Check if firmware has been loaded. It is possible that another - instance of the driver has loaded the firmware. - */ - if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS) - goto fail; - - switch (id) { - case XC_PRODUCT_ID_FW_LOADED: - printk(KERN_INFO - "xc5000: Successfully identified at address 0x%02x\n", - cfg->i2c_address); - printk(KERN_INFO - "xc5000: Firmware has been loaded previously\n"); - break; - case XC_PRODUCT_ID_FW_NOT_LOADED: - printk(KERN_INFO - "xc5000: Successfully identified at address 0x%02x\n", - cfg->i2c_address); - printk(KERN_INFO - "xc5000: Firmware has not been loaded previously\n"); - break; - default: - printk(KERN_ERR - "xc5000: Device not found at addr 0x%02x (0x%x)\n", - cfg->i2c_address, id); - goto fail; - } - - mutex_unlock(&xc5000_list_mutex); - - memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - return fe; -fail: - mutex_unlock(&xc5000_list_mutex); - - xc5000_release(fe); - return NULL; -} -EXPORT_SYMBOL(xc5000_attach); - -MODULE_AUTHOR("Steven Toth"); -MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(XC5000A_FIRMWARE); -MODULE_FIRMWARE(XC5000C_FIRMWARE); diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h deleted file mode 100644 index b1a547494625..000000000000 --- a/drivers/media/common/tuners/xc5000.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" - * - * Copyright (c) 2007 Steven Toth - * - * 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 __XC5000_H__ -#define __XC5000_H__ - -#include - -struct dvb_frontend; -struct i2c_adapter; - -#define XC5000A 1 -#define XC5000C 2 - -struct xc5000_config { - u8 i2c_address; - u32 if_khz; - u8 radio_input; - u16 xtal_khz; - - int chip_id; -}; - -/* xc5000 callback command */ -#define XC5000_TUNER_RESET 0 - -/* Possible Radio inputs */ -#define XC5000_RADIO_NOT_CONFIGURED 0 -#define XC5000_RADIO_FM1 1 -#define XC5000_RADIO_FM2 2 -#define XC5000_RADIO_FM1_MONO 3 - -/* For each bridge framework, when it attaches either analog or digital, - * it has to store a reference back to its _core equivalent structure, - * so that it can service the hardware by steering gpio's etc. - * Each bridge implementation is different so cast devptr accordingly. - * The xc5000 driver cares not for this value, other than ensuring - * it's passed back to a bridge during tuner_callback(). - */ - -#if defined(CONFIG_MEDIA_TUNER_XC5000) || \ - (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE)) -extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - const struct xc5000_config *cfg); -#else -static inline struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - const struct xc5000_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index a378c5293764..208bc496b90a 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile @@ -3,7 +3,7 @@ # ccflags-y += -I$(srctree)/drivers/media/dvb-core/ -ccflags-y += -I$(srctree)/drivers/media/common/tuners/ +ccflags-y += -I$(srctree)/drivers/media/tuners/ stb0899-objs = stb0899_drv.o stb0899_algo.o stv0900-objs = stv0900_core.o stv0900_sw.o diff --git a/drivers/media/pci/bt8xx/Makefile b/drivers/media/pci/bt8xx/Makefile index 36591ae505f4..c008d0c135d6 100644 --- a/drivers/media/pci/bt8xx/Makefile +++ b/drivers/media/pci/bt8xx/Makefile @@ -3,4 +3,4 @@ obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o ccflags-y += -Idrivers/media/dvb-core ccflags-y += -Idrivers/media/dvb-frontends ccflags-y += -Idrivers/media/video/bt8xx -ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/tuners diff --git a/drivers/media/pci/ddbridge/Makefile b/drivers/media/pci/ddbridge/Makefile index 9d083c98ce58..7446c8b677b5 100644 --- a/drivers/media/pci/ddbridge/Makefile +++ b/drivers/media/pci/ddbridge/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o ccflags-y += -Idrivers/media/dvb-core/ ccflags-y += -Idrivers/media/dvb-frontends/ -ccflags-y += -Idrivers/media/common/tuners/ +ccflags-y += -Idrivers/media/tuners/ # For the staging CI driver cxd2099 ccflags-y += -Idrivers/staging/media/cxd2099/ diff --git a/drivers/media/pci/ngene/Makefile b/drivers/media/pci/ngene/Makefile index 63997089f9d1..5c0b5d6b9d69 100644 --- a/drivers/media/pci/ngene/Makefile +++ b/drivers/media/pci/ngene/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_DVB_NGENE) += ngene.o ccflags-y += -Idrivers/media/dvb-core/ ccflags-y += -Idrivers/media/dvb-frontends/ -ccflags-y += -Idrivers/media/common/tuners/ +ccflags-y += -Idrivers/media/tuners/ # For the staging CI driver cxd2099 ccflags-y += -Idrivers/staging/media/cxd2099/ diff --git a/drivers/media/pci/ttpci/Makefile b/drivers/media/pci/ttpci/Makefile index 22a235f3cc48..98905963ff08 100644 --- a/drivers/media/pci/ttpci/Makefile +++ b/drivers/media/pci/ttpci/Makefile @@ -18,4 +18,4 @@ obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/ -ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/tuners diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig new file mode 100644 index 000000000000..94c6ff7a5da3 --- /dev/null +++ b/drivers/media/tuners/Kconfig @@ -0,0 +1,243 @@ +config MEDIA_ATTACH + bool "Load and attach frontend and tuner driver modules as needed" + depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT + depends on MODULES + default y if !EXPERT + help + Remove the static dependency of DVB card drivers on all + frontend modules for all possible card variants. Instead, + allow the card drivers to only load the frontend modules + they require. + + Also, tuner module will automatically load a tuner driver + when needed, for analog mode. + + This saves several KBytes of memory. + + Note: You will need module-init-tools v3.2 or later for this feature. + + If unsure say Y. + +config MEDIA_TUNER + tristate + depends on (MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT) && I2C + default y + select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT && EXPERIMENTAL + select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE + +config MEDIA_TUNER_CUSTOMISE + bool "Customize analog and hybrid tuner modules to build" + depends on MEDIA_TUNER + default y if EXPERT + help + This allows the user to deselect tuner drivers unnecessary + for their hardware from the build. Use this option with care + as deselecting tuner drivers which are in fact necessary will + result in V4L/DVB devices which cannot be tuned due to lack of + driver support + + If unsure say N. + +menu "Customize TV tuners" + visible if MEDIA_TUNER_CUSTOMISE + depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT + +config MEDIA_TUNER_SIMPLE + tristate "Simple tuner support" + depends on MEDIA_SUPPORT && I2C + select MEDIA_TUNER_TDA9887 + default m if MEDIA_TUNER_CUSTOMISE + help + Say Y here to include support for various simple tuners. + +config MEDIA_TUNER_TDA8290 + tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" + depends on MEDIA_SUPPORT && I2C + select MEDIA_TUNER_TDA827X + select MEDIA_TUNER_TDA18271 + default m if MEDIA_TUNER_CUSTOMISE + help + Say Y here to include support for Philips TDA8290+8275(a) tuner. + +config MEDIA_TUNER_TDA827X + tristate "Philips TDA827X silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A DVB-T silicon tuner module. Say Y when you want to support this tuner. + +config MEDIA_TUNER_TDA18271 + tristate "NXP TDA18271 silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A silicon tuner module. Say Y when you want to support this tuner. + +config MEDIA_TUNER_TDA9887 + tristate "TDA 9885/6/7 analog IF demodulator" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + Say Y here to include support for Philips TDA9885/6/7 + analog IF demodulator. + +config MEDIA_TUNER_TEA5761 + tristate "TEA 5761 radio tuner (EXPERIMENTAL)" + depends on MEDIA_SUPPORT && I2C + depends on EXPERIMENTAL + default m if MEDIA_TUNER_CUSTOMISE + help + Say Y here to include support for the Philips TEA5761 radio tuner. + +config MEDIA_TUNER_TEA5767 + tristate "TEA 5767 radio tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + Say Y here to include support for the Philips TEA5767 radio tuner. + +config MEDIA_TUNER_MT20XX + tristate "Microtune 2032 / 2050 tuners" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + Say Y here to include support for the MT2032 / MT2050 tuner. + +config MEDIA_TUNER_MT2060 + tristate "Microtune MT2060 silicon IF tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon IF tuner MT2060 from Microtune. + +config MEDIA_TUNER_MT2063 + tristate "Microtune MT2063 silicon IF tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon IF tuner MT2063 from Microtune. + +config MEDIA_TUNER_MT2266 + tristate "Microtune MT2266 silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon baseband tuner MT2266 from Microtune. + +config MEDIA_TUNER_MT2131 + tristate "Microtune MT2131 silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon baseband tuner MT2131 from Microtune. + +config MEDIA_TUNER_QT1010 + tristate "Quantek QT1010 silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon tuner QT1010 from Quantek. + +config MEDIA_TUNER_XC2028 + tristate "XCeive xc2028/xc3028 tuners" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + Say Y here to include support for the xc2028/xc3028 tuners. + +config MEDIA_TUNER_XC5000 + tristate "Xceive XC5000 silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon tuner XC5000 from Xceive. + This device is only used inside a SiP called together with a + demodulator for now. + +config MEDIA_TUNER_XC4000 + tristate "Xceive XC4000 silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon tuner XC4000 from Xceive. + This device is only used inside a SiP called together with a + demodulator for now. + +config MEDIA_TUNER_MXL5005S + tristate "MaxLinear MSL5005S silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon tuner MXL5005S from MaxLinear. + +config MEDIA_TUNER_MXL5007T + tristate "MaxLinear MxL5007T silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon tuner MxL5007T from MaxLinear. + +config MEDIA_TUNER_MC44S803 + tristate "Freescale MC44S803 Low Power CMOS Broadband tuners" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Freescale MC44S803 based tuners + +config MEDIA_TUNER_MAX2165 + tristate "Maxim MAX2165 silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon tuner MAX2165 from Maxim. + +config MEDIA_TUNER_TDA18218 + tristate "NXP TDA18218 silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + NXP TDA18218 silicon tuner driver. + +config MEDIA_TUNER_FC0011 + tristate "Fitipower FC0011 silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + Fitipower FC0011 silicon tuner driver. + +config MEDIA_TUNER_FC0012 + tristate "Fitipower FC0012 silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + Fitipower FC0012 silicon tuner driver. + +config MEDIA_TUNER_FC0013 + tristate "Fitipower FC0013 silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + Fitipower FC0013 silicon tuner driver. + +config MEDIA_TUNER_TDA18212 + tristate "NXP TDA18212 silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + NXP TDA18212 silicon tuner driver. + +config MEDIA_TUNER_TUA9001 + tristate "Infineon TUA 9001 silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + Infineon TUA 9001 silicon tuner driver. +endmenu diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile new file mode 100644 index 000000000000..112aeee90202 --- /dev/null +++ b/drivers/media/tuners/Makefile @@ -0,0 +1,37 @@ +# +# Makefile for common V4L/DVB tuners +# + +tda18271-objs := tda18271-maps.o tda18271-common.o tda18271-fe.o + +obj-$(CONFIG_MEDIA_TUNER_XC2028) += tuner-xc2028.o +obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-simple.o +# tuner-types will be merged into tuner-simple, in the future +obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-types.o +obj-$(CONFIG_MEDIA_TUNER_MT20XX) += mt20xx.o +obj-$(CONFIG_MEDIA_TUNER_TDA8290) += tda8290.o +obj-$(CONFIG_MEDIA_TUNER_TEA5767) += tea5767.o +obj-$(CONFIG_MEDIA_TUNER_TEA5761) += tea5761.o +obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o +obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o +obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o +obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o +obj-$(CONFIG_MEDIA_TUNER_XC4000) += xc4000.o +obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o +obj-$(CONFIG_MEDIA_TUNER_MT2063) += mt2063.o +obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o +obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o +obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o +obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o +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 +obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o +obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o +obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o +obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o +obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o + +ccflags-y += -I$(srctree)/drivers/media/dvb-core +ccflags-y += -I$(srctree)/drivers/media/dvb-frontends diff --git a/drivers/media/tuners/fc0011.c b/drivers/media/tuners/fc0011.c new file mode 100644 index 000000000000..e4882546c283 --- /dev/null +++ b/drivers/media/tuners/fc0011.c @@ -0,0 +1,524 @@ +/* + * Fitipower FC0011 tuner driver + * + * Copyright (C) 2012 Michael Buesch + * + * Derived from FC0012 tuner driver: + * Copyright (C) 2012 Hans-Frieder Vogt + * + * 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 "fc0011.h" + + +/* Tuner registers */ +enum { + FC11_REG_0, + FC11_REG_FA, /* FA */ + FC11_REG_FP, /* FP */ + FC11_REG_XINHI, /* XIN high 8 bit */ + FC11_REG_XINLO, /* XIN low 8 bit */ + FC11_REG_VCO, /* VCO */ + FC11_REG_VCOSEL, /* VCO select */ + FC11_REG_7, /* Unknown tuner reg 7 */ + FC11_REG_8, /* Unknown tuner reg 8 */ + FC11_REG_9, + FC11_REG_10, /* Unknown tuner reg 10 */ + FC11_REG_11, /* Unknown tuner reg 11 */ + FC11_REG_12, + FC11_REG_RCCAL, /* RC calibrate */ + FC11_REG_VCOCAL, /* VCO calibrate */ + FC11_REG_15, + FC11_REG_16, /* Unknown tuner reg 16 */ + FC11_REG_17, + + FC11_NR_REGS, /* Number of registers */ +}; + +enum FC11_REG_VCOSEL_bits { + FC11_VCOSEL_2 = 0x08, /* VCO select 2 */ + FC11_VCOSEL_1 = 0x10, /* VCO select 1 */ + FC11_VCOSEL_CLKOUT = 0x20, /* Fix clock out */ + FC11_VCOSEL_BW7M = 0x40, /* 7MHz bw */ + FC11_VCOSEL_BW6M = 0x80, /* 6MHz bw */ +}; + +enum FC11_REG_RCCAL_bits { + FC11_RCCAL_FORCE = 0x10, /* force */ +}; + +enum FC11_REG_VCOCAL_bits { + FC11_VCOCAL_RUN = 0, /* VCO calibration run */ + FC11_VCOCAL_VALUEMASK = 0x3F, /* VCO calibration value mask */ + FC11_VCOCAL_OK = 0x40, /* VCO calibration Ok */ + FC11_VCOCAL_RESET = 0x80, /* VCO calibration reset */ +}; + + +struct fc0011_priv { + struct i2c_adapter *i2c; + u8 addr; + + u32 frequency; + u32 bandwidth; +}; + + +static int fc0011_writereg(struct fc0011_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { .addr = priv->addr, + .flags = 0, .buf = buf, .len = 2 }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + dev_err(&priv->i2c->dev, + "I2C write reg failed, reg: %02x, val: %02x\n", + reg, val); + return -EIO; + } + + return 0; +} + +static int fc0011_readreg(struct fc0011_priv *priv, u8 reg, u8 *val) +{ + u8 dummy; + struct i2c_msg msg[2] = { + { .addr = priv->addr, + .flags = 0, .buf = ®, .len = 1 }, + { .addr = priv->addr, + .flags = I2C_M_RD, .buf = val ? : &dummy, .len = 1 }, + }; + + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + dev_err(&priv->i2c->dev, + "I2C read failed, reg: %02x\n", reg); + return -EIO; + } + + return 0; +} + +static int fc0011_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; +} + +static int fc0011_init(struct dvb_frontend *fe) +{ + struct fc0011_priv *priv = fe->tuner_priv; + int err; + + if (WARN_ON(!fe->callback)) + return -EINVAL; + + err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, + FC0011_FE_CALLBACK_POWER, priv->addr); + if (err) { + dev_err(&priv->i2c->dev, "Power-on callback failed\n"); + return err; + } + err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, + FC0011_FE_CALLBACK_RESET, priv->addr); + if (err) { + dev_err(&priv->i2c->dev, "Reset callback failed\n"); + return err; + } + + return 0; +} + +/* Initiate VCO calibration */ +static int fc0011_vcocal_trigger(struct fc0011_priv *priv) +{ + int err; + + err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RESET); + if (err) + return err; + err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN); + if (err) + return err; + + return 0; +} + +/* Read VCO calibration value */ +static int fc0011_vcocal_read(struct fc0011_priv *priv, u8 *value) +{ + int err; + + err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN); + if (err) + return err; + usleep_range(10000, 20000); + err = fc0011_readreg(priv, FC11_REG_VCOCAL, value); + if (err) + return err; + + return 0; +} + +static int fc0011_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct fc0011_priv *priv = fe->tuner_priv; + int err; + unsigned int i, vco_retries; + u32 freq = p->frequency / 1000; + u32 bandwidth = p->bandwidth_hz / 1000; + u32 fvco, xin, xdiv, xdivr; + u16 frac; + u8 fa, fp, vco_sel, vco_cal; + u8 regs[FC11_NR_REGS] = { }; + + regs[FC11_REG_7] = 0x0F; + regs[FC11_REG_8] = 0x3E; + regs[FC11_REG_10] = 0xB8; + regs[FC11_REG_11] = 0x80; + regs[FC11_REG_RCCAL] = 0x04; + err = fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]); + err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]); + err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]); + err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]); + err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); + if (err) + return -EIO; + + /* Set VCO freq and VCO div */ + if (freq < 54000) { + fvco = freq * 64; + regs[FC11_REG_VCO] = 0x82; + } else if (freq < 108000) { + fvco = freq * 32; + regs[FC11_REG_VCO] = 0x42; + } else if (freq < 216000) { + fvco = freq * 16; + regs[FC11_REG_VCO] = 0x22; + } else if (freq < 432000) { + fvco = freq * 8; + regs[FC11_REG_VCO] = 0x12; + } else { + fvco = freq * 4; + regs[FC11_REG_VCO] = 0x0A; + } + + /* Calc XIN. The PLL reference frequency is 18 MHz. */ + xdiv = fvco / 18000; + frac = fvco - xdiv * 18000; + frac = (frac << 15) / 18000; + if (frac >= 16384) + frac += 32786; + if (!frac) + xin = 0; + else if (frac < 511) + xin = 512; + else if (frac < 65026) + xin = frac; + else + xin = 65024; + regs[FC11_REG_XINHI] = xin >> 8; + regs[FC11_REG_XINLO] = xin; + + /* Calc FP and FA */ + xdivr = xdiv; + if (fvco - xdiv * 18000 >= 9000) + xdivr += 1; /* round */ + fp = xdivr / 8; + fa = xdivr - fp * 8; + if (fa < 2) { + fp -= 1; + fa += 8; + } + if (fp > 0x1F) { + fp &= 0x1F; + fa &= 0xF; + } + if (fa >= fp) { + dev_warn(&priv->i2c->dev, + "fa %02X >= fp %02X, but trying to continue\n", + (unsigned int)(u8)fa, (unsigned int)(u8)fp); + } + regs[FC11_REG_FA] = fa; + regs[FC11_REG_FP] = fp; + + /* Select bandwidth */ + switch (bandwidth) { + case 8000: + break; + case 7000: + regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW7M; + break; + default: + dev_warn(&priv->i2c->dev, "Unsupported bandwidth %u kHz. " + "Using 6000 kHz.\n", + bandwidth); + bandwidth = 6000; + /* fallthrough */ + case 6000: + regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW6M; + break; + } + + /* Pre VCO select */ + if (fvco < 2320000) { + vco_sel = 0; + regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); + } else if (fvco < 3080000) { + vco_sel = 1; + regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); + regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; + } else { + vco_sel = 2; + regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); + regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; + } + + /* Fix for low freqs */ + if (freq < 45000) { + regs[FC11_REG_FA] = 0x6; + regs[FC11_REG_FP] = 0x11; + } + + /* Clock out fix */ + regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_CLKOUT; + + /* Write the cached registers */ + for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) { + err = fc0011_writereg(priv, i, regs[i]); + if (err) + return err; + } + + /* VCO calibration */ + err = fc0011_vcocal_trigger(priv); + if (err) + return err; + err = fc0011_vcocal_read(priv, &vco_cal); + if (err) + return err; + vco_retries = 0; + while (!(vco_cal & FC11_VCOCAL_OK) && vco_retries < 3) { + /* Reset the tuner and try again */ + err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, + FC0011_FE_CALLBACK_RESET, priv->addr); + if (err) { + dev_err(&priv->i2c->dev, "Failed to reset tuner\n"); + return err; + } + /* Reinit tuner config */ + err = 0; + for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) + err |= fc0011_writereg(priv, i, regs[i]); + err |= fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]); + err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]); + err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]); + err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]); + err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); + if (err) + return -EIO; + /* VCO calibration */ + err = fc0011_vcocal_trigger(priv); + if (err) + return err; + err = fc0011_vcocal_read(priv, &vco_cal); + if (err) + return err; + vco_retries++; + } + if (!(vco_cal & FC11_VCOCAL_OK)) { + dev_err(&priv->i2c->dev, + "Failed to read VCO calibration value (got %02X)\n", + (unsigned int)vco_cal); + return -EIO; + } + vco_cal &= FC11_VCOCAL_VALUEMASK; + + switch (vco_sel) { + case 0: + if (vco_cal < 8) { + regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); + regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; + err = fc0011_writereg(priv, FC11_REG_VCOSEL, + regs[FC11_REG_VCOSEL]); + if (err) + return err; + err = fc0011_vcocal_trigger(priv); + if (err) + return err; + } else { + regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); + err = fc0011_writereg(priv, FC11_REG_VCOSEL, + regs[FC11_REG_VCOSEL]); + if (err) + return err; + } + break; + case 1: + if (vco_cal < 5) { + regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); + regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; + err = fc0011_writereg(priv, FC11_REG_VCOSEL, + regs[FC11_REG_VCOSEL]); + if (err) + return err; + err = fc0011_vcocal_trigger(priv); + if (err) + return err; + } else if (vco_cal <= 48) { + regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); + regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; + err = fc0011_writereg(priv, FC11_REG_VCOSEL, + regs[FC11_REG_VCOSEL]); + if (err) + return err; + } else { + regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); + err = fc0011_writereg(priv, FC11_REG_VCOSEL, + regs[FC11_REG_VCOSEL]); + if (err) + return err; + err = fc0011_vcocal_trigger(priv); + if (err) + return err; + } + break; + case 2: + if (vco_cal > 53) { + regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); + regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; + err = fc0011_writereg(priv, FC11_REG_VCOSEL, + regs[FC11_REG_VCOSEL]); + if (err) + return err; + err = fc0011_vcocal_trigger(priv); + if (err) + return err; + } else { + regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); + regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; + err = fc0011_writereg(priv, FC11_REG_VCOSEL, + regs[FC11_REG_VCOSEL]); + if (err) + return err; + } + break; + } + err = fc0011_vcocal_read(priv, NULL); + if (err) + return err; + usleep_range(10000, 50000); + + err = fc0011_readreg(priv, FC11_REG_RCCAL, ®s[FC11_REG_RCCAL]); + if (err) + return err; + regs[FC11_REG_RCCAL] |= FC11_RCCAL_FORCE; + err = fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); + if (err) + return err; + err = fc0011_writereg(priv, FC11_REG_16, 0xB); + if (err) + return err; + + dev_dbg(&priv->i2c->dev, "Tuned to " + "fa=%02X fp=%02X xin=%02X%02X vco=%02X vcosel=%02X " + "vcocal=%02X(%u) bw=%u\n", + (unsigned int)regs[FC11_REG_FA], + (unsigned int)regs[FC11_REG_FP], + (unsigned int)regs[FC11_REG_XINHI], + (unsigned int)regs[FC11_REG_XINLO], + (unsigned int)regs[FC11_REG_VCO], + (unsigned int)regs[FC11_REG_VCOSEL], + (unsigned int)vco_cal, vco_retries, + (unsigned int)bandwidth); + + priv->frequency = p->frequency; + priv->bandwidth = p->bandwidth_hz; + + return 0; +} + +static int fc0011_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct fc0011_priv *priv = fe->tuner_priv; + + *frequency = priv->frequency; + + return 0; +} + +static int fc0011_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + *frequency = 0; + + return 0; +} + +static int fc0011_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct fc0011_priv *priv = fe->tuner_priv; + + *bandwidth = priv->bandwidth; + + return 0; +} + +static const struct dvb_tuner_ops fc0011_tuner_ops = { + .info = { + .name = "Fitipower FC0011", + + .frequency_min = 45000000, + .frequency_max = 1000000000, + }, + + .release = fc0011_release, + .init = fc0011_init, + + .set_params = fc0011_set_params, + + .get_frequency = fc0011_get_frequency, + .get_if_frequency = fc0011_get_if_frequency, + .get_bandwidth = fc0011_get_bandwidth, +}; + +struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct fc0011_config *config) +{ + struct fc0011_priv *priv; + + priv = kzalloc(sizeof(struct fc0011_priv), GFP_KERNEL); + if (!priv) + return NULL; + + priv->i2c = i2c; + priv->addr = config->i2c_address; + + fe->tuner_priv = priv; + fe->ops.tuner_ops = fc0011_tuner_ops; + + dev_info(&priv->i2c->dev, "Fitipower FC0011 tuner attached\n"); + + return fe; +} +EXPORT_SYMBOL(fc0011_attach); + +MODULE_DESCRIPTION("Fitipower FC0011 silicon tuner driver"); +MODULE_AUTHOR("Michael Buesch "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/fc0011.h b/drivers/media/tuners/fc0011.h new file mode 100644 index 000000000000..0ee581f122d2 --- /dev/null +++ b/drivers/media/tuners/fc0011.h @@ -0,0 +1,41 @@ +#ifndef LINUX_FC0011_H_ +#define LINUX_FC0011_H_ + +#include "dvb_frontend.h" + + +/** struct fc0011_config - fc0011 hardware config + * + * @i2c_address: I2C bus address. + */ +struct fc0011_config { + u8 i2c_address; +}; + +/** enum fc0011_fe_callback_commands - Frontend callbacks + * + * @FC0011_FE_CALLBACK_POWER: Power on tuner hardware. + * @FC0011_FE_CALLBACK_RESET: Request a tuner reset. + */ +enum fc0011_fe_callback_commands { + FC0011_FE_CALLBACK_POWER, + FC0011_FE_CALLBACK_RESET, +}; + +#if defined(CONFIG_MEDIA_TUNER_FC0011) ||\ + defined(CONFIG_MEDIA_TUNER_FC0011_MODULE) +struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct fc0011_config *config); +#else +static inline +struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct fc0011_config *config) +{ + dev_err(&i2c->dev, "fc0011 driver disabled in Kconfig\n"); + return NULL; +} +#endif + +#endif /* LINUX_FC0011_H_ */ diff --git a/drivers/media/tuners/fc0012-priv.h b/drivers/media/tuners/fc0012-priv.h new file mode 100644 index 000000000000..4577c917e616 --- /dev/null +++ b/drivers/media/tuners/fc0012-priv.h @@ -0,0 +1,43 @@ +/* + * Fitipower FC0012 tuner driver - private includes + * + * Copyright (C) 2012 Hans-Frieder Vogt + * + * 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 _FC0012_PRIV_H_ +#define _FC0012_PRIV_H_ + +#define LOG_PREFIX "fc0012" + +#undef err +#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) +#undef info +#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef warn +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) + +struct fc0012_priv { + struct i2c_adapter *i2c; + u8 addr; + u8 dual_master; + u8 xtal_freq; + + u32 frequency; + u32 bandwidth; +}; + +#endif diff --git a/drivers/media/tuners/fc0012.c b/drivers/media/tuners/fc0012.c new file mode 100644 index 000000000000..308135abd54c --- /dev/null +++ b/drivers/media/tuners/fc0012.c @@ -0,0 +1,467 @@ +/* + * Fitipower FC0012 tuner driver + * + * Copyright (C) 2012 Hans-Frieder Vogt + * + * 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 "fc0012.h" +#include "fc0012-priv.h" + +static int fc0012_writereg(struct fc0012_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = {reg, val}; + struct i2c_msg msg = { + .addr = priv->addr, .flags = 0, .buf = buf, .len = 2 + }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + err("I2C write reg failed, reg: %02x, val: %02x", reg, val); + return -EREMOTEIO; + } + return 0; +} + +static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->addr, .flags = 0, .buf = ®, .len = 1 }, + { .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + err("I2C read reg failed, reg: %02x", reg); + return -EREMOTEIO; + } + return 0; +} + +static int fc0012_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int fc0012_init(struct dvb_frontend *fe) +{ + struct fc0012_priv *priv = fe->tuner_priv; + int i, ret = 0; + unsigned char reg[] = { + 0x00, /* dummy reg. 0 */ + 0x05, /* reg. 0x01 */ + 0x10, /* reg. 0x02 */ + 0x00, /* reg. 0x03 */ + 0x00, /* reg. 0x04 */ + 0x0f, /* reg. 0x05: may also be 0x0a */ + 0x00, /* reg. 0x06: divider 2, VCO slow */ + 0x00, /* reg. 0x07: may also be 0x0f */ + 0xff, /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256, + Loop Bw 1/8 */ + 0x6e, /* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */ + 0xb8, /* reg. 0x0a: Disable LO Test Buffer */ + 0x82, /* reg. 0x0b: Output Clock is same as clock frequency, + may also be 0x83 */ + 0xfc, /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */ + 0x02, /* reg. 0x0d: AGC Not Forcing & LNA Forcing, 0x02 for DVB-T */ + 0x00, /* reg. 0x0e */ + 0x00, /* reg. 0x0f */ + 0x00, /* reg. 0x10: may also be 0x0d */ + 0x00, /* reg. 0x11 */ + 0x1f, /* reg. 0x12: Set to maximum gain */ + 0x08, /* reg. 0x13: Set to Middle Gain: 0x08, + Low Gain: 0x00, High Gain: 0x10, enable IX2: 0x80 */ + 0x00, /* reg. 0x14 */ + 0x04, /* reg. 0x15: Enable LNA COMPS */ + }; + + switch (priv->xtal_freq) { + case FC_XTAL_27_MHZ: + case FC_XTAL_28_8_MHZ: + reg[0x07] |= 0x20; + break; + case FC_XTAL_36_MHZ: + default: + break; + } + + if (priv->dual_master) + reg[0x0c] |= 0x02; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + for (i = 1; i < sizeof(reg); i++) { + ret = fc0012_writereg(priv, i, reg[i]); + if (ret) + break; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + if (ret) + err("fc0012_writereg failed: %d", ret); + + return ret; +} + +static int fc0012_sleep(struct dvb_frontend *fe) +{ + /* nothing to do here */ + return 0; +} + +static int fc0012_set_params(struct dvb_frontend *fe) +{ + struct fc0012_priv *priv = fe->tuner_priv; + int i, ret = 0; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u32 freq = p->frequency / 1000; + u32 delsys = p->delivery_system; + unsigned char reg[7], am, pm, multi, tmp; + unsigned long f_vco; + unsigned short xtal_freq_khz_2, xin, xdiv; + int vco_select = false; + + if (fe->callback) { + ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, + FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1)); + if (ret) + goto exit; + } + + switch (priv->xtal_freq) { + case FC_XTAL_27_MHZ: + xtal_freq_khz_2 = 27000 / 2; + break; + case FC_XTAL_36_MHZ: + xtal_freq_khz_2 = 36000 / 2; + break; + case FC_XTAL_28_8_MHZ: + default: + xtal_freq_khz_2 = 28800 / 2; + break; + } + + /* select frequency divider and the frequency of VCO */ + if (freq < 37084) { /* freq * 96 < 3560000 */ + multi = 96; + reg[5] = 0x82; + reg[6] = 0x00; + } else if (freq < 55625) { /* freq * 64 < 3560000 */ + multi = 64; + reg[5] = 0x82; + reg[6] = 0x02; + } else if (freq < 74167) { /* freq * 48 < 3560000 */ + multi = 48; + reg[5] = 0x42; + reg[6] = 0x00; + } else if (freq < 111250) { /* freq * 32 < 3560000 */ + multi = 32; + reg[5] = 0x42; + reg[6] = 0x02; + } else if (freq < 148334) { /* freq * 24 < 3560000 */ + multi = 24; + reg[5] = 0x22; + reg[6] = 0x00; + } else if (freq < 222500) { /* freq * 16 < 3560000 */ + multi = 16; + reg[5] = 0x22; + reg[6] = 0x02; + } else if (freq < 296667) { /* freq * 12 < 3560000 */ + multi = 12; + reg[5] = 0x12; + reg[6] = 0x00; + } else if (freq < 445000) { /* freq * 8 < 3560000 */ + multi = 8; + reg[5] = 0x12; + reg[6] = 0x02; + } else if (freq < 593334) { /* freq * 6 < 3560000 */ + multi = 6; + reg[5] = 0x0a; + reg[6] = 0x00; + } else { + multi = 4; + reg[5] = 0x0a; + reg[6] = 0x02; + } + + f_vco = freq * multi; + + if (f_vco >= 3060000) { + reg[6] |= 0x08; + vco_select = true; + } + + if (freq >= 45000) { + /* From divided value (XDIV) determined the FA and FP value */ + xdiv = (unsigned short)(f_vco / xtal_freq_khz_2); + if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2)) + xdiv++; + + pm = (unsigned char)(xdiv / 8); + am = (unsigned char)(xdiv - (8 * pm)); + + if (am < 2) { + reg[1] = am + 8; + reg[2] = pm - 1; + } else { + reg[1] = am; + reg[2] = pm; + } + } else { + /* fix for frequency less than 45 MHz */ + reg[1] = 0x06; + reg[2] = 0x11; + } + + /* fix clock out */ + reg[6] |= 0x20; + + /* From VCO frequency determines the XIN ( fractional part of Delta + Sigma PLL) and divided value (XDIV) */ + xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2); + xin = (xin << 15) / xtal_freq_khz_2; + if (xin >= 16384) + xin += 32768; + + reg[3] = xin >> 8; /* xin with 9 bit resolution */ + reg[4] = xin & 0xff; + + if (delsys == SYS_DVBT) { + reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */ + switch (p->bandwidth_hz) { + case 6000000: + reg[6] |= 0x80; + break; + case 7000000: + reg[6] |= 0x40; + break; + case 8000000: + default: + break; + } + } else { + err("%s: modulation type not supported!", __func__); + return -EINVAL; + } + + /* modified for Realtek demod */ + reg[5] |= 0x07; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + for (i = 1; i <= 6; i++) { + ret = fc0012_writereg(priv, i, reg[i]); + if (ret) + goto exit; + } + + /* VCO Calibration */ + ret = fc0012_writereg(priv, 0x0e, 0x80); + if (!ret) + ret = fc0012_writereg(priv, 0x0e, 0x00); + + /* VCO Re-Calibration if needed */ + if (!ret) + ret = fc0012_writereg(priv, 0x0e, 0x00); + + if (!ret) { + msleep(10); + ret = fc0012_readreg(priv, 0x0e, &tmp); + } + if (ret) + goto exit; + + /* vco selection */ + tmp &= 0x3f; + + if (vco_select) { + if (tmp > 0x3c) { + reg[6] &= ~0x08; + ret = fc0012_writereg(priv, 0x06, reg[6]); + if (!ret) + ret = fc0012_writereg(priv, 0x0e, 0x80); + if (!ret) + ret = fc0012_writereg(priv, 0x0e, 0x00); + } + } else { + if (tmp < 0x02) { + reg[6] |= 0x08; + ret = fc0012_writereg(priv, 0x06, reg[6]); + if (!ret) + ret = fc0012_writereg(priv, 0x0e, 0x80); + if (!ret) + ret = fc0012_writereg(priv, 0x0e, 0x00); + } + } + + priv->frequency = p->frequency; + priv->bandwidth = p->bandwidth_hz; + +exit: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + if (ret) + warn("%s: failed: %d", __func__, ret); + return ret; +} + +static int fc0012_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct fc0012_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int fc0012_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + /* CHECK: always ? */ + *frequency = 0; + return 0; +} + +static int fc0012_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct fc0012_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +#define INPUT_ADC_LEVEL -8 + +static int fc0012_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct fc0012_priv *priv = fe->tuner_priv; + int ret; + unsigned char tmp; + int int_temp, lna_gain, int_lna, tot_agc_gain, power; + const int fc0012_lna_gain_table[] = { + /* low gain */ + -63, -58, -99, -73, + -63, -65, -54, -60, + /* middle gain */ + 71, 70, 68, 67, + 65, 63, 61, 58, + /* high gain */ + 197, 191, 188, 186, + 184, 182, 181, 179, + }; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + ret = fc0012_writereg(priv, 0x12, 0x00); + if (ret) + goto err; + + ret = fc0012_readreg(priv, 0x12, &tmp); + if (ret) + goto err; + int_temp = tmp; + + ret = fc0012_readreg(priv, 0x13, &tmp); + if (ret) + goto err; + lna_gain = tmp & 0x1f; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + if (lna_gain < ARRAY_SIZE(fc0012_lna_gain_table)) { + int_lna = fc0012_lna_gain_table[lna_gain]; + tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 + + (int_temp & 0x1f)) * 2; + power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10; + + if (power >= 45) + *strength = 255; /* 100% */ + else if (power < -95) + *strength = 0; + else + *strength = (power + 95) * 255 / 140; + + *strength |= *strength << 8; + } else { + ret = -1; + } + + goto exit; + +err: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ +exit: + if (ret) + warn("%s: failed: %d", __func__, ret); + return ret; +} + +static const struct dvb_tuner_ops fc0012_tuner_ops = { + .info = { + .name = "Fitipower FC0012", + + .frequency_min = 37000000, /* estimate */ + .frequency_max = 862000000, /* estimate */ + .frequency_step = 0, + }, + + .release = fc0012_release, + + .init = fc0012_init, + .sleep = fc0012_sleep, + + .set_params = fc0012_set_params, + + .get_frequency = fc0012_get_frequency, + .get_if_frequency = fc0012_get_if_frequency, + .get_bandwidth = fc0012_get_bandwidth, + + .get_rf_strength = fc0012_get_rf_strength, +}; + +struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 i2c_address, int dual_master, + enum fc001x_xtal_freq xtal_freq) +{ + struct fc0012_priv *priv = NULL; + + priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->i2c = i2c; + priv->dual_master = dual_master; + priv->addr = i2c_address; + priv->xtal_freq = xtal_freq; + + info("Fitipower FC0012 successfully attached."); + + fe->tuner_priv = priv; + + memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + return fe; +} +EXPORT_SYMBOL(fc0012_attach); + +MODULE_DESCRIPTION("Fitipower FC0012 silicon tuner driver"); +MODULE_AUTHOR("Hans-Frieder Vogt "); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.6"); diff --git a/drivers/media/tuners/fc0012.h b/drivers/media/tuners/fc0012.h new file mode 100644 index 000000000000..4dbd5efe8845 --- /dev/null +++ b/drivers/media/tuners/fc0012.h @@ -0,0 +1,44 @@ +/* + * Fitipower FC0012 tuner driver - include + * + * Copyright (C) 2012 Hans-Frieder Vogt + * + * 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 _FC0012_H_ +#define _FC0012_H_ + +#include "dvb_frontend.h" +#include "fc001x-common.h" + +#if defined(CONFIG_MEDIA_TUNER_FC0012) || \ + (defined(CONFIG_MEDIA_TUNER_FC0012_MODULE) && defined(MODULE)) +extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + u8 i2c_address, int dual_master, + enum fc001x_xtal_freq xtal_freq); +#else +static inline struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + u8 i2c_address, int dual_master, + enum fc001x_xtal_freq xtal_freq) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff --git a/drivers/media/tuners/fc0013-priv.h b/drivers/media/tuners/fc0013-priv.h new file mode 100644 index 000000000000..bfd49dedea22 --- /dev/null +++ b/drivers/media/tuners/fc0013-priv.h @@ -0,0 +1,44 @@ +/* + * Fitipower FC0013 tuner driver + * + * Copyright (C) 2012 Hans-Frieder Vogt + * + * 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 _FC0013_PRIV_H_ +#define _FC0013_PRIV_H_ + +#define LOG_PREFIX "fc0013" + +#undef err +#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) +#undef info +#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef warn +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) + +struct fc0013_priv { + struct i2c_adapter *i2c; + u8 addr; + u8 dual_master; + u8 xtal_freq; + + u32 frequency; + u32 bandwidth; +}; + +#endif diff --git a/drivers/media/tuners/fc0013.c b/drivers/media/tuners/fc0013.c new file mode 100644 index 000000000000..bd8f0f1e8f3b --- /dev/null +++ b/drivers/media/tuners/fc0013.c @@ -0,0 +1,634 @@ +/* + * Fitipower FC0013 tuner driver + * + * Copyright (C) 2012 Hans-Frieder Vogt + * partially based on driver code from Fitipower + * Copyright (C) 2010 Fitipower Integrated Technology Inc + * + * 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 "fc0013.h" +#include "fc0013-priv.h" + +static int fc0013_writereg(struct fc0013_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = {reg, val}; + struct i2c_msg msg = { + .addr = priv->addr, .flags = 0, .buf = buf, .len = 2 + }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + err("I2C write reg failed, reg: %02x, val: %02x", reg, val); + return -EREMOTEIO; + } + return 0; +} + +static int fc0013_readreg(struct fc0013_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->addr, .flags = 0, .buf = ®, .len = 1 }, + { .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + err("I2C read reg failed, reg: %02x", reg); + return -EREMOTEIO; + } + return 0; +} + +static int fc0013_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int fc0013_init(struct dvb_frontend *fe) +{ + struct fc0013_priv *priv = fe->tuner_priv; + int i, ret = 0; + unsigned char reg[] = { + 0x00, /* reg. 0x00: dummy */ + 0x09, /* reg. 0x01 */ + 0x16, /* reg. 0x02 */ + 0x00, /* reg. 0x03 */ + 0x00, /* reg. 0x04 */ + 0x17, /* reg. 0x05 */ + 0x02, /* reg. 0x06 */ + 0x0a, /* reg. 0x07: CHECK */ + 0xff, /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256, + Loop Bw 1/8 */ + 0x6f, /* reg. 0x09: enable LoopThrough */ + 0xb8, /* reg. 0x0a: Disable LO Test Buffer */ + 0x82, /* reg. 0x0b: CHECK */ + 0xfc, /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */ + 0x01, /* reg. 0x0d: AGC Not Forcing & LNA Forcing, may need 0x02 */ + 0x00, /* reg. 0x0e */ + 0x00, /* reg. 0x0f */ + 0x00, /* reg. 0x10 */ + 0x00, /* reg. 0x11 */ + 0x00, /* reg. 0x12 */ + 0x00, /* reg. 0x13 */ + 0x50, /* reg. 0x14: DVB-t High Gain, UHF. + Middle Gain: 0x48, Low Gain: 0x40 */ + 0x01, /* reg. 0x15 */ + }; + + switch (priv->xtal_freq) { + case FC_XTAL_27_MHZ: + case FC_XTAL_28_8_MHZ: + reg[0x07] |= 0x20; + break; + case FC_XTAL_36_MHZ: + default: + break; + } + + if (priv->dual_master) + reg[0x0c] |= 0x02; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + for (i = 1; i < sizeof(reg); i++) { + ret = fc0013_writereg(priv, i, reg[i]); + if (ret) + break; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + if (ret) + err("fc0013_writereg failed: %d", ret); + + return ret; +} + +static int fc0013_sleep(struct dvb_frontend *fe) +{ + /* nothing to do here */ + return 0; +} + +int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val) +{ + struct fc0013_priv *priv = fe->tuner_priv; + int ret; + u8 rc_cal; + int val; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + /* push rc_cal value, get rc_cal value */ + ret = fc0013_writereg(priv, 0x10, 0x00); + if (ret) + goto error_out; + + /* get rc_cal value */ + ret = fc0013_readreg(priv, 0x10, &rc_cal); + if (ret) + goto error_out; + + rc_cal &= 0x0f; + + val = (int)rc_cal + rc_val; + + /* forcing rc_cal */ + ret = fc0013_writereg(priv, 0x0d, 0x11); + if (ret) + goto error_out; + + /* modify rc_cal value */ + if (val > 15) + ret = fc0013_writereg(priv, 0x10, 0x0f); + else if (val < 0) + ret = fc0013_writereg(priv, 0x10, 0x00); + else + ret = fc0013_writereg(priv, 0x10, (u8)val); + +error_out: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + return ret; +} +EXPORT_SYMBOL(fc0013_rc_cal_add); + +int fc0013_rc_cal_reset(struct dvb_frontend *fe) +{ + struct fc0013_priv *priv = fe->tuner_priv; + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + ret = fc0013_writereg(priv, 0x0d, 0x01); + if (!ret) + ret = fc0013_writereg(priv, 0x10, 0x00); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + return ret; +} +EXPORT_SYMBOL(fc0013_rc_cal_reset); + +static int fc0013_set_vhf_track(struct fc0013_priv *priv, u32 freq) +{ + int ret; + u8 tmp; + + ret = fc0013_readreg(priv, 0x1d, &tmp); + if (ret) + goto error_out; + tmp &= 0xe3; + if (freq <= 177500) { /* VHF Track: 7 */ + ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c); + } else if (freq <= 184500) { /* VHF Track: 6 */ + ret = fc0013_writereg(priv, 0x1d, tmp | 0x18); + } else if (freq <= 191500) { /* VHF Track: 5 */ + ret = fc0013_writereg(priv, 0x1d, tmp | 0x14); + } else if (freq <= 198500) { /* VHF Track: 4 */ + ret = fc0013_writereg(priv, 0x1d, tmp | 0x10); + } else if (freq <= 205500) { /* VHF Track: 3 */ + ret = fc0013_writereg(priv, 0x1d, tmp | 0x0c); + } else if (freq <= 219500) { /* VHF Track: 2 */ + ret = fc0013_writereg(priv, 0x1d, tmp | 0x08); + } else if (freq < 300000) { /* VHF Track: 1 */ + ret = fc0013_writereg(priv, 0x1d, tmp | 0x04); + } else { /* UHF and GPS */ + ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c); + } + if (ret) + goto error_out; +error_out: + return ret; +} + +static int fc0013_set_params(struct dvb_frontend *fe) +{ + struct fc0013_priv *priv = fe->tuner_priv; + int i, ret = 0; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u32 freq = p->frequency / 1000; + u32 delsys = p->delivery_system; + unsigned char reg[7], am, pm, multi, tmp; + unsigned long f_vco; + unsigned short xtal_freq_khz_2, xin, xdiv; + int vco_select = false; + + if (fe->callback) { + ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, + FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1)); + if (ret) + goto exit; + } + + switch (priv->xtal_freq) { + case FC_XTAL_27_MHZ: + xtal_freq_khz_2 = 27000 / 2; + break; + case FC_XTAL_36_MHZ: + xtal_freq_khz_2 = 36000 / 2; + break; + case FC_XTAL_28_8_MHZ: + default: + xtal_freq_khz_2 = 28800 / 2; + break; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + /* set VHF track */ + ret = fc0013_set_vhf_track(priv, freq); + if (ret) + goto exit; + + if (freq < 300000) { + /* enable VHF filter */ + ret = fc0013_readreg(priv, 0x07, &tmp); + if (ret) + goto exit; + ret = fc0013_writereg(priv, 0x07, tmp | 0x10); + if (ret) + goto exit; + + /* disable UHF & disable GPS */ + ret = fc0013_readreg(priv, 0x14, &tmp); + if (ret) + goto exit; + ret = fc0013_writereg(priv, 0x14, tmp & 0x1f); + if (ret) + goto exit; + } else if (freq <= 862000) { + /* disable VHF filter */ + ret = fc0013_readreg(priv, 0x07, &tmp); + if (ret) + goto exit; + ret = fc0013_writereg(priv, 0x07, tmp & 0xef); + if (ret) + goto exit; + + /* enable UHF & disable GPS */ + ret = fc0013_readreg(priv, 0x14, &tmp); + if (ret) + goto exit; + ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x40); + if (ret) + goto exit; + } else { + /* disable VHF filter */ + ret = fc0013_readreg(priv, 0x07, &tmp); + if (ret) + goto exit; + ret = fc0013_writereg(priv, 0x07, tmp & 0xef); + if (ret) + goto exit; + + /* disable UHF & enable GPS */ + ret = fc0013_readreg(priv, 0x14, &tmp); + if (ret) + goto exit; + ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x20); + if (ret) + goto exit; + } + + /* select frequency divider and the frequency of VCO */ + if (freq < 37084) { /* freq * 96 < 3560000 */ + multi = 96; + reg[5] = 0x82; + reg[6] = 0x00; + } else if (freq < 55625) { /* freq * 64 < 3560000 */ + multi = 64; + reg[5] = 0x02; + reg[6] = 0x02; + } else if (freq < 74167) { /* freq * 48 < 3560000 */ + multi = 48; + reg[5] = 0x42; + reg[6] = 0x00; + } else if (freq < 111250) { /* freq * 32 < 3560000 */ + multi = 32; + reg[5] = 0x82; + reg[6] = 0x02; + } else if (freq < 148334) { /* freq * 24 < 3560000 */ + multi = 24; + reg[5] = 0x22; + reg[6] = 0x00; + } else if (freq < 222500) { /* freq * 16 < 3560000 */ + multi = 16; + reg[5] = 0x42; + reg[6] = 0x02; + } else if (freq < 296667) { /* freq * 12 < 3560000 */ + multi = 12; + reg[5] = 0x12; + reg[6] = 0x00; + } else if (freq < 445000) { /* freq * 8 < 3560000 */ + multi = 8; + reg[5] = 0x22; + reg[6] = 0x02; + } else if (freq < 593334) { /* freq * 6 < 3560000 */ + multi = 6; + reg[5] = 0x0a; + reg[6] = 0x00; + } else if (freq < 950000) { /* freq * 4 < 3800000 */ + multi = 4; + reg[5] = 0x12; + reg[6] = 0x02; + } else { + multi = 2; + reg[5] = 0x0a; + reg[6] = 0x02; + } + + f_vco = freq * multi; + + if (f_vco >= 3060000) { + reg[6] |= 0x08; + vco_select = true; + } + + if (freq >= 45000) { + /* From divided value (XDIV) determined the FA and FP value */ + xdiv = (unsigned short)(f_vco / xtal_freq_khz_2); + if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2)) + xdiv++; + + pm = (unsigned char)(xdiv / 8); + am = (unsigned char)(xdiv - (8 * pm)); + + if (am < 2) { + reg[1] = am + 8; + reg[2] = pm - 1; + } else { + reg[1] = am; + reg[2] = pm; + } + } else { + /* fix for frequency less than 45 MHz */ + reg[1] = 0x06; + reg[2] = 0x11; + } + + /* fix clock out */ + reg[6] |= 0x20; + + /* From VCO frequency determines the XIN ( fractional part of Delta + Sigma PLL) and divided value (XDIV) */ + xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2); + xin = (xin << 15) / xtal_freq_khz_2; + if (xin >= 16384) + xin += 32768; + + reg[3] = xin >> 8; + reg[4] = xin & 0xff; + + if (delsys == SYS_DVBT) { + reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */ + switch (p->bandwidth_hz) { + case 6000000: + reg[6] |= 0x80; + break; + case 7000000: + reg[6] |= 0x40; + break; + case 8000000: + default: + break; + } + } else { + err("%s: modulation type not supported!", __func__); + return -EINVAL; + } + + /* modified for Realtek demod */ + reg[5] |= 0x07; + + for (i = 1; i <= 6; i++) { + ret = fc0013_writereg(priv, i, reg[i]); + if (ret) + goto exit; + } + + ret = fc0013_readreg(priv, 0x11, &tmp); + if (ret) + goto exit; + if (multi == 64) + ret = fc0013_writereg(priv, 0x11, tmp | 0x04); + else + ret = fc0013_writereg(priv, 0x11, tmp & 0xfb); + if (ret) + goto exit; + + /* VCO Calibration */ + ret = fc0013_writereg(priv, 0x0e, 0x80); + if (!ret) + ret = fc0013_writereg(priv, 0x0e, 0x00); + + /* VCO Re-Calibration if needed */ + if (!ret) + ret = fc0013_writereg(priv, 0x0e, 0x00); + + if (!ret) { + msleep(10); + ret = fc0013_readreg(priv, 0x0e, &tmp); + } + if (ret) + goto exit; + + /* vco selection */ + tmp &= 0x3f; + + if (vco_select) { + if (tmp > 0x3c) { + reg[6] &= ~0x08; + ret = fc0013_writereg(priv, 0x06, reg[6]); + if (!ret) + ret = fc0013_writereg(priv, 0x0e, 0x80); + if (!ret) + ret = fc0013_writereg(priv, 0x0e, 0x00); + } + } else { + if (tmp < 0x02) { + reg[6] |= 0x08; + ret = fc0013_writereg(priv, 0x06, reg[6]); + if (!ret) + ret = fc0013_writereg(priv, 0x0e, 0x80); + if (!ret) + ret = fc0013_writereg(priv, 0x0e, 0x00); + } + } + + priv->frequency = p->frequency; + priv->bandwidth = p->bandwidth_hz; + +exit: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + if (ret) + warn("%s: failed: %d", __func__, ret); + return ret; +} + +static int fc0013_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct fc0013_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int fc0013_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + /* always ? */ + *frequency = 0; + return 0; +} + +static int fc0013_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct fc0013_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +#define INPUT_ADC_LEVEL -8 + +static int fc0013_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct fc0013_priv *priv = fe->tuner_priv; + int ret; + unsigned char tmp; + int int_temp, lna_gain, int_lna, tot_agc_gain, power; + const int fc0013_lna_gain_table[] = { + /* low gain */ + -63, -58, -99, -73, + -63, -65, -54, -60, + /* middle gain */ + 71, 70, 68, 67, + 65, 63, 61, 58, + /* high gain */ + 197, 191, 188, 186, + 184, 182, 181, 179, + }; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + ret = fc0013_writereg(priv, 0x13, 0x00); + if (ret) + goto err; + + ret = fc0013_readreg(priv, 0x13, &tmp); + if (ret) + goto err; + int_temp = tmp; + + ret = fc0013_readreg(priv, 0x14, &tmp); + if (ret) + goto err; + lna_gain = tmp & 0x1f; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + if (lna_gain < ARRAY_SIZE(fc0013_lna_gain_table)) { + int_lna = fc0013_lna_gain_table[lna_gain]; + tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 + + (int_temp & 0x1f)) * 2; + power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10; + + if (power >= 45) + *strength = 255; /* 100% */ + else if (power < -95) + *strength = 0; + else + *strength = (power + 95) * 255 / 140; + + *strength |= *strength << 8; + } else { + ret = -1; + } + + goto exit; + +err: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ +exit: + if (ret) + warn("%s: failed: %d", __func__, ret); + return ret; +} + +static const struct dvb_tuner_ops fc0013_tuner_ops = { + .info = { + .name = "Fitipower FC0013", + + .frequency_min = 37000000, /* estimate */ + .frequency_max = 1680000000, /* CHECK */ + .frequency_step = 0, + }, + + .release = fc0013_release, + + .init = fc0013_init, + .sleep = fc0013_sleep, + + .set_params = fc0013_set_params, + + .get_frequency = fc0013_get_frequency, + .get_if_frequency = fc0013_get_if_frequency, + .get_bandwidth = fc0013_get_bandwidth, + + .get_rf_strength = fc0013_get_rf_strength, +}; + +struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 i2c_address, int dual_master, + enum fc001x_xtal_freq xtal_freq) +{ + struct fc0013_priv *priv = NULL; + + priv = kzalloc(sizeof(struct fc0013_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->i2c = i2c; + priv->dual_master = dual_master; + priv->addr = i2c_address; + priv->xtal_freq = xtal_freq; + + info("Fitipower FC0013 successfully attached."); + + fe->tuner_priv = priv; + + memcpy(&fe->ops.tuner_ops, &fc0013_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + return fe; +} +EXPORT_SYMBOL(fc0013_attach); + +MODULE_DESCRIPTION("Fitipower FC0013 silicon tuner driver"); +MODULE_AUTHOR("Hans-Frieder Vogt "); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.2"); diff --git a/drivers/media/tuners/fc0013.h b/drivers/media/tuners/fc0013.h new file mode 100644 index 000000000000..594efd64aeec --- /dev/null +++ b/drivers/media/tuners/fc0013.h @@ -0,0 +1,57 @@ +/* + * Fitipower FC0013 tuner driver + * + * Copyright (C) 2012 Hans-Frieder Vogt + * + * 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 _FC0013_H_ +#define _FC0013_H_ + +#include "dvb_frontend.h" +#include "fc001x-common.h" + +#if defined(CONFIG_MEDIA_TUNER_FC0013) || \ + (defined(CONFIG_MEDIA_TUNER_FC0013_MODULE) && defined(MODULE)) +extern struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + u8 i2c_address, int dual_master, + enum fc001x_xtal_freq xtal_freq); +extern int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val); +extern int fc0013_rc_cal_reset(struct dvb_frontend *fe); +#else +static inline struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + u8 i2c_address, int dual_master, + enum fc001x_xtal_freq xtal_freq) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val) +{ + return 0; +} + +static inline int fc0013_rc_cal_reset(struct dvb_frontend *fe) +{ + return 0; +} +#endif + +#endif diff --git a/drivers/media/tuners/fc001x-common.h b/drivers/media/tuners/fc001x-common.h new file mode 100644 index 000000000000..718818156934 --- /dev/null +++ b/drivers/media/tuners/fc001x-common.h @@ -0,0 +1,39 @@ +/* + * Fitipower FC0012 & FC0013 tuner driver - common defines + * + * Copyright (C) 2012 Hans-Frieder Vogt + * + * 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 _FC001X_COMMON_H_ +#define _FC001X_COMMON_H_ + +enum fc001x_xtal_freq { + FC_XTAL_27_MHZ, /* 27000000 */ + FC_XTAL_28_8_MHZ, /* 28800000 */ + FC_XTAL_36_MHZ, /* 36000000 */ +}; + +/* + * enum fc001x_fe_callback_commands - Frontend callbacks + * + * @FC_FE_CALLBACK_VHF_ENABLE: enable VHF or UHF + */ +enum fc001x_fe_callback_commands { + FC_FE_CALLBACK_VHF_ENABLE, +}; + +#endif diff --git a/drivers/media/tuners/max2165.c b/drivers/media/tuners/max2165.c new file mode 100644 index 000000000000..ba84936aafd6 --- /dev/null +++ b/drivers/media/tuners/max2165.c @@ -0,0 +1,433 @@ +/* + * Driver for Maxim MAX2165 silicon tuner + * + * Copyright (c) 2009 David T. L. Wong + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "max2165.h" +#include "max2165_priv.h" +#include "tuner-i2c.h" + +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "max2165: " args); \ + } while (0) + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +static int max2165_write_reg(struct max2165_priv *priv, u8 reg, u8 data) +{ + int ret; + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 }; + + msg.addr = priv->config->i2c_address; + + if (debug >= 2) + dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data); + + ret = i2c_transfer(priv->i2c, &msg, 1); + + if (ret != 1) + dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n", + __func__, reg, data, ret); + + return (ret != 1) ? -EIO : 0; +} + +static int max2165_read_reg(struct max2165_priv *priv, u8 reg, u8 *p_data) +{ + int ret; + u8 dev_addr = priv->config->i2c_address; + + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { + { .addr = dev_addr, .flags = 0, .buf = b0, .len = 1 }, + { .addr = dev_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }, + }; + + ret = i2c_transfer(priv->i2c, msg, 2); + if (ret != 2) { + dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret); + return -EIO; + } + + *p_data = b1[0]; + if (debug >= 2) + dprintk("%s: reg=0x%02X, data=0x%02X\n", + __func__, reg, b1[0]); + return 0; +} + +static int max2165_mask_write_reg(struct max2165_priv *priv, u8 reg, + u8 mask, u8 data) +{ + int ret; + u8 v; + + data &= mask; + ret = max2165_read_reg(priv, reg, &v); + if (ret != 0) + return ret; + v &= ~mask; + v |= data; + ret = max2165_write_reg(priv, reg, v); + + return ret; +} + +static int max2165_read_rom_table(struct max2165_priv *priv) +{ + u8 dat[3]; + int i; + + for (i = 0; i < 3; i++) { + max2165_write_reg(priv, REG_ROM_TABLE_ADDR, i + 1); + max2165_read_reg(priv, REG_ROM_TABLE_DATA, &dat[i]); + } + + priv->tf_ntch_low_cfg = dat[0] >> 4; + priv->tf_ntch_hi_cfg = dat[0] & 0x0F; + priv->tf_balun_low_ref = dat[1] & 0x0F; + priv->tf_balun_hi_ref = dat[1] >> 4; + priv->bb_filter_7mhz_cfg = dat[2] & 0x0F; + priv->bb_filter_8mhz_cfg = dat[2] >> 4; + + dprintk("tf_ntch_low_cfg = 0x%X\n", priv->tf_ntch_low_cfg); + dprintk("tf_ntch_hi_cfg = 0x%X\n", priv->tf_ntch_hi_cfg); + dprintk("tf_balun_low_ref = 0x%X\n", priv->tf_balun_low_ref); + dprintk("tf_balun_hi_ref = 0x%X\n", priv->tf_balun_hi_ref); + dprintk("bb_filter_7mhz_cfg = 0x%X\n", priv->bb_filter_7mhz_cfg); + dprintk("bb_filter_8mhz_cfg = 0x%X\n", priv->bb_filter_8mhz_cfg); + + return 0; +} + +static int max2165_set_osc(struct max2165_priv *priv, u8 osc /*MHz*/) +{ + u8 v; + + v = (osc / 2); + if (v == 2) + v = 0x7; + else + v -= 8; + + max2165_mask_write_reg(priv, REG_PLL_CFG, 0x07, v); + + return 0; +} + +static int max2165_set_bandwidth(struct max2165_priv *priv, u32 bw) +{ + u8 val; + + if (bw == 8000000) + val = priv->bb_filter_8mhz_cfg; + else + val = priv->bb_filter_7mhz_cfg; + + max2165_mask_write_reg(priv, REG_BASEBAND_CTRL, 0xF0, val << 4); + + return 0; +} + +int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction) +{ + u32 remainder; + u32 q, f = 0; + int i; + + if (0 == divisor) + return -EINVAL; + + q = dividend / divisor; + remainder = dividend - q * divisor; + + for (i = 0; i < 31; i++) { + remainder <<= 1; + if (remainder >= divisor) { + f += 1; + remainder -= divisor; + } + f <<= 1; + } + + *quotient = q; + *fraction = f; + + return 0; +} + +static int max2165_set_rf(struct max2165_priv *priv, u32 freq) +{ + u8 tf; + u8 tf_ntch; + u32 t; + u32 quotient, fraction; + int ret; + + /* Set PLL divider according to RF frequency */ + ret = fixpt_div32(freq / 1000, priv->config->osc_clk * 1000, + "ient, &fraction); + if (ret != 0) + return ret; + + /* 20-bit fraction */ + fraction >>= 12; + + max2165_write_reg(priv, REG_NDIV_INT, quotient); + max2165_mask_write_reg(priv, REG_NDIV_FRAC2, 0x0F, fraction >> 16); + max2165_write_reg(priv, REG_NDIV_FRAC1, fraction >> 8); + max2165_write_reg(priv, REG_NDIV_FRAC0, fraction); + + /* Norch Filter */ + tf_ntch = (freq < 725000000) ? + priv->tf_ntch_low_cfg : priv->tf_ntch_hi_cfg; + + /* Tracking filter balun */ + t = priv->tf_balun_low_ref; + t += (priv->tf_balun_hi_ref - priv->tf_balun_low_ref) + * (freq / 1000 - 470000) / (780000 - 470000); + + tf = t; + dprintk("tf = %X\n", tf); + tf |= tf_ntch << 4; + + max2165_write_reg(priv, REG_TRACK_FILTER, tf); + + return 0; +} + +static void max2165_debug_status(struct max2165_priv *priv) +{ + u8 status, autotune; + u8 auto_vco_success, auto_vco_active; + u8 pll_locked; + u8 dc_offset_low, dc_offset_hi; + u8 signal_lv_over_threshold; + u8 vco, vco_sub_band, adc; + + max2165_read_reg(priv, REG_STATUS, &status); + max2165_read_reg(priv, REG_AUTOTUNE, &autotune); + + auto_vco_success = (status >> 6) & 0x01; + auto_vco_active = (status >> 5) & 0x01; + pll_locked = (status >> 4) & 0x01; + dc_offset_low = (status >> 3) & 0x01; + dc_offset_hi = (status >> 2) & 0x01; + signal_lv_over_threshold = status & 0x01; + + vco = autotune >> 6; + vco_sub_band = (autotune >> 3) & 0x7; + adc = autotune & 0x7; + + dprintk("auto VCO active: %d, auto VCO success: %d\n", + auto_vco_active, auto_vco_success); + dprintk("PLL locked: %d\n", pll_locked); + dprintk("DC offset low: %d, DC offset high: %d\n", + dc_offset_low, dc_offset_hi); + dprintk("Signal lvl over threshold: %d\n", signal_lv_over_threshold); + dprintk("VCO: %d, VCO Sub-band: %d, ADC: %d\n", vco, vco_sub_band, adc); +} + +static int max2165_set_params(struct dvb_frontend *fe) +{ + struct max2165_priv *priv = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + + switch (c->bandwidth_hz) { + case 7000000: + case 8000000: + priv->frequency = c->frequency; + break; + default: + printk(KERN_INFO "MAX2165: bandwidth %d Hz not supported.\n", + c->bandwidth_hz); + return -EINVAL; + } + + dprintk("%s() frequency=%d\n", __func__, c->frequency); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + max2165_set_bandwidth(priv, c->bandwidth_hz); + ret = max2165_set_rf(priv, priv->frequency); + mdelay(50); + max2165_debug_status(priv); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (ret != 0) + return -EREMOTEIO; + + return 0; +} + +static int max2165_get_frequency(struct dvb_frontend *fe, u32 *freq) +{ + struct max2165_priv *priv = fe->tuner_priv; + dprintk("%s()\n", __func__); + *freq = priv->frequency; + return 0; +} + +static int max2165_get_bandwidth(struct dvb_frontend *fe, u32 *bw) +{ + struct max2165_priv *priv = fe->tuner_priv; + dprintk("%s()\n", __func__); + + *bw = priv->bandwidth; + return 0; +} + +static int max2165_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct max2165_priv *priv = fe->tuner_priv; + u16 lock_status = 0; + + dprintk("%s()\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + max2165_debug_status(priv); + *status = lock_status; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return 0; +} + +static int max2165_sleep(struct dvb_frontend *fe) +{ + dprintk("%s()\n", __func__); + return 0; +} + +static int max2165_init(struct dvb_frontend *fe) +{ + struct max2165_priv *priv = fe->tuner_priv; + dprintk("%s()\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + /* Setup initial values */ + /* Fractional Mode on */ + max2165_write_reg(priv, REG_NDIV_FRAC2, 0x18); + /* LNA on */ + max2165_write_reg(priv, REG_LNA, 0x01); + max2165_write_reg(priv, REG_PLL_CFG, 0x7A); + max2165_write_reg(priv, REG_TEST, 0x08); + max2165_write_reg(priv, REG_SHUTDOWN, 0x40); + max2165_write_reg(priv, REG_VCO_CTRL, 0x84); + max2165_write_reg(priv, REG_BASEBAND_CTRL, 0xC3); + max2165_write_reg(priv, REG_DC_OFFSET_CTRL, 0x75); + max2165_write_reg(priv, REG_DC_OFFSET_DAC, 0x00); + max2165_write_reg(priv, REG_ROM_TABLE_ADDR, 0x00); + + max2165_set_osc(priv, priv->config->osc_clk); + + max2165_read_rom_table(priv); + + max2165_set_bandwidth(priv, 8000000); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return 0; +} + +static int max2165_release(struct dvb_frontend *fe) +{ + struct max2165_priv *priv = fe->tuner_priv; + dprintk("%s()\n", __func__); + + kfree(priv); + fe->tuner_priv = NULL; + + return 0; +} + +static const struct dvb_tuner_ops max2165_tuner_ops = { + .info = { + .name = "Maxim MAX2165", + .frequency_min = 470000000, + .frequency_max = 780000000, + .frequency_step = 50000, + }, + + .release = max2165_release, + .init = max2165_init, + .sleep = max2165_sleep, + + .set_params = max2165_set_params, + .set_analog_params = NULL, + .get_frequency = max2165_get_frequency, + .get_bandwidth = max2165_get_bandwidth, + .get_status = max2165_get_status +}; + +struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct max2165_config *cfg) +{ + struct max2165_priv *priv = NULL; + + dprintk("%s(%d-%04x)\n", __func__, + i2c ? i2c_adapter_id(i2c) : -1, + cfg ? cfg->i2c_address : -1); + + priv = kzalloc(sizeof(struct max2165_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + memcpy(&fe->ops.tuner_ops, &max2165_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + priv->config = cfg; + priv->i2c = i2c; + fe->tuner_priv = priv; + + max2165_init(fe); + max2165_debug_status(priv); + + return fe; +} +EXPORT_SYMBOL(max2165_attach); + +MODULE_AUTHOR("David T. L. Wong "); +MODULE_DESCRIPTION("Maxim MAX2165 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/max2165.h b/drivers/media/tuners/max2165.h new file mode 100644 index 000000000000..c063c36a93d3 --- /dev/null +++ b/drivers/media/tuners/max2165.h @@ -0,0 +1,48 @@ +/* + * Driver for Maxim MAX2165 silicon tuner + * + * Copyright (c) 2009 David T. L. Wong + * + * 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 __MAX2165_H__ +#define __MAX2165_H__ + +struct dvb_frontend; +struct i2c_adapter; + +struct max2165_config { + u8 i2c_address; + u8 osc_clk; /* in MHz, selectable values: 4,16,18,20,22,24,26,28 */ +}; + +#if defined(CONFIG_MEDIA_TUNER_MAX2165) || \ + (defined(CONFIG_MEDIA_TUNER_MAX2165_MODULE) && defined(MODULE)) +extern struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct max2165_config *cfg); +#else +static inline struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct max2165_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff --git a/drivers/media/tuners/max2165_priv.h b/drivers/media/tuners/max2165_priv.h new file mode 100644 index 000000000000..91bbe021a08d --- /dev/null +++ b/drivers/media/tuners/max2165_priv.h @@ -0,0 +1,60 @@ +/* + * Driver for Maxim MAX2165 silicon tuner + * + * Copyright (c) 2009 David T. L. Wong + * + * 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 __MAX2165_PRIV_H__ +#define __MAX2165_PRIV_H__ + +#define REG_NDIV_INT 0x00 +#define REG_NDIV_FRAC2 0x01 +#define REG_NDIV_FRAC1 0x02 +#define REG_NDIV_FRAC0 0x03 +#define REG_TRACK_FILTER 0x04 +#define REG_LNA 0x05 +#define REG_PLL_CFG 0x06 +#define REG_TEST 0x07 +#define REG_SHUTDOWN 0x08 +#define REG_VCO_CTRL 0x09 +#define REG_BASEBAND_CTRL 0x0A +#define REG_DC_OFFSET_CTRL 0x0B +#define REG_DC_OFFSET_DAC 0x0C +#define REG_ROM_TABLE_ADDR 0x0D + +/* Read Only Registers */ +#define REG_ROM_TABLE_DATA 0x10 +#define REG_STATUS 0x11 +#define REG_AUTOTUNE 0x12 + +struct max2165_priv { + struct max2165_config *config; + struct i2c_adapter *i2c; + + u32 frequency; + u32 bandwidth; + + u8 tf_ntch_low_cfg; + u8 tf_ntch_hi_cfg; + u8 tf_balun_low_ref; + u8 tf_balun_hi_ref; + u8 bb_filter_7mhz_cfg; + u8 bb_filter_8mhz_cfg; +}; + +#endif diff --git a/drivers/media/tuners/mc44s803.c b/drivers/media/tuners/mc44s803.c new file mode 100644 index 000000000000..5ddce7e326f7 --- /dev/null +++ b/drivers/media/tuners/mc44s803.c @@ -0,0 +1,372 @@ +/* + * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner + * + * Copyright (c) 2009 Jochen Friedrich + * + * 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 +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "mc44s803.h" +#include "mc44s803_priv.h" + +#define mc_printk(level, format, arg...) \ + printk(level "mc44s803: " format , ## arg) + +/* Writes a single register */ +static int mc44s803_writereg(struct mc44s803_priv *priv, u32 val) +{ + u8 buf[3]; + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 3 + }; + + buf[0] = (val & 0xff0000) >> 16; + buf[1] = (val & 0xff00) >> 8; + buf[2] = (val & 0xff); + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + mc_printk(KERN_WARNING, "I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +/* Reads a single register */ +static int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val) +{ + u32 wval; + u8 buf[3]; + int ret; + struct i2c_msg msg[] = { + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, + .buf = buf, .len = 3 }, + }; + + wval = MC44S803_REG_SM(MC44S803_REG_DATAREG, MC44S803_ADDR) | + MC44S803_REG_SM(reg, MC44S803_D); + + ret = mc44s803_writereg(priv, wval); + if (ret) + return ret; + + if (i2c_transfer(priv->i2c, msg, 1) != 1) { + mc_printk(KERN_WARNING, "I2C read failed\n"); + return -EREMOTEIO; + } + + *val = (buf[0] << 16) | (buf[1] << 8) | buf[2]; + + return 0; +} + +static int mc44s803_release(struct dvb_frontend *fe) +{ + struct mc44s803_priv *priv = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(priv); + + return 0; +} + +static int mc44s803_init(struct dvb_frontend *fe) +{ + struct mc44s803_priv *priv = fe->tuner_priv; + u32 val; + int err; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + +/* Reset chip */ + val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR) | + MC44S803_REG_SM(1, MC44S803_RS); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + +/* Power Up and Start Osc */ + + val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) | + MC44S803_REG_SM(0xC0, MC44S803_REFOSC) | + MC44S803_REG_SM(1, MC44S803_OSCSEL); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + val = MC44S803_REG_SM(MC44S803_REG_POWER, MC44S803_ADDR) | + MC44S803_REG_SM(0x200, MC44S803_POWER); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + msleep(10); + + val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) | + MC44S803_REG_SM(0x40, MC44S803_REFOSC) | + MC44S803_REG_SM(1, MC44S803_OSCSEL); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + msleep(20); + +/* Setup Mixer */ + + val = MC44S803_REG_SM(MC44S803_REG_MIXER, MC44S803_ADDR) | + MC44S803_REG_SM(1, MC44S803_TRI_STATE) | + MC44S803_REG_SM(0x7F, MC44S803_MIXER_RES); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + +/* Setup Cirquit Adjust */ + + val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) | + MC44S803_REG_SM(1, MC44S803_G1) | + MC44S803_REG_SM(1, MC44S803_G3) | + MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) | + MC44S803_REG_SM(1, MC44S803_G6) | + MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) | + MC44S803_REG_SM(0x3, MC44S803_LP) | + MC44S803_REG_SM(1, MC44S803_CLRF) | + MC44S803_REG_SM(1, MC44S803_CLIF); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) | + MC44S803_REG_SM(1, MC44S803_G1) | + MC44S803_REG_SM(1, MC44S803_G3) | + MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) | + MC44S803_REG_SM(1, MC44S803_G6) | + MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) | + MC44S803_REG_SM(0x3, MC44S803_LP); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + +/* Setup Digtune */ + + val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | + MC44S803_REG_SM(3, MC44S803_XOD); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + +/* Setup AGC */ + + val = MC44S803_REG_SM(MC44S803_REG_LNAAGC, MC44S803_ADDR) | + MC44S803_REG_SM(1, MC44S803_AT1) | + MC44S803_REG_SM(1, MC44S803_AT2) | + MC44S803_REG_SM(1, MC44S803_AGC_AN_DIG) | + MC44S803_REG_SM(1, MC44S803_AGC_READ_EN) | + MC44S803_REG_SM(1, MC44S803_LNA0); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + return 0; + +exit: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + mc_printk(KERN_WARNING, "I/O Error\n"); + return err; +} + +static int mc44s803_set_params(struct dvb_frontend *fe) +{ + struct mc44s803_priv *priv = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 r1, r2, n1, n2, lo1, lo2, freq, val; + int err; + + priv->frequency = c->frequency; + + r1 = MC44S803_OSC / 1000000; + r2 = MC44S803_OSC / 100000; + + n1 = (c->frequency + MC44S803_IF1 + 500000) / 1000000; + freq = MC44S803_OSC / r1 * n1; + lo1 = ((60 * n1) + (r1 / 2)) / r1; + freq = freq - c->frequency; + + n2 = (freq - MC44S803_IF2 + 50000) / 100000; + lo2 = ((60 * n2) + (r2 / 2)) / r2; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + val = MC44S803_REG_SM(MC44S803_REG_REFDIV, MC44S803_ADDR) | + MC44S803_REG_SM(r1-1, MC44S803_R1) | + MC44S803_REG_SM(r2-1, MC44S803_R2) | + MC44S803_REG_SM(1, MC44S803_REFBUF_EN); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + val = MC44S803_REG_SM(MC44S803_REG_LO1, MC44S803_ADDR) | + MC44S803_REG_SM(n1-2, MC44S803_LO1); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + val = MC44S803_REG_SM(MC44S803_REG_LO2, MC44S803_ADDR) | + MC44S803_REG_SM(n2-2, MC44S803_LO2); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | + MC44S803_REG_SM(1, MC44S803_DA) | + MC44S803_REG_SM(lo1, MC44S803_LO_REF) | + MC44S803_REG_SM(1, MC44S803_AT); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | + MC44S803_REG_SM(2, MC44S803_DA) | + MC44S803_REG_SM(lo2, MC44S803_LO_REF) | + MC44S803_REG_SM(1, MC44S803_AT); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return 0; + +exit: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + mc_printk(KERN_WARNING, "I/O Error\n"); + return err; +} + +static int mc44s803_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mc44s803_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static const struct dvb_tuner_ops mc44s803_tuner_ops = { + .info = { + .name = "Freescale MC44S803", + .frequency_min = 48000000, + .frequency_max = 1000000000, + .frequency_step = 100000, + }, + + .release = mc44s803_release, + .init = mc44s803_init, + .set_params = mc44s803_set_params, + .get_frequency = mc44s803_get_frequency +}; + +/* This functions tries to identify a MC44S803 tuner by reading the ID + register. This is hasty. */ +struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct mc44s803_config *cfg) +{ + struct mc44s803_priv *priv; + u32 reg; + u8 id; + int ret; + + reg = 0; + + priv = kzalloc(sizeof(struct mc44s803_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + priv->fe = fe; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + ret = mc44s803_readreg(priv, MC44S803_REG_ID, ®); + if (ret) + goto error; + + id = MC44S803_REG_MS(reg, MC44S803_ID); + + if (id != 0x14) { + mc_printk(KERN_ERR, "unsupported ID " + "(%x should be 0x14)\n", id); + goto error; + } + + mc_printk(KERN_INFO, "successfully identified (ID = %x)\n", id); + memcpy(&fe->ops.tuner_ops, &mc44s803_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + return fe; + +error: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + kfree(priv); + return NULL; +} +EXPORT_SYMBOL(mc44s803_attach); + +MODULE_AUTHOR("Jochen Friedrich"); +MODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/mc44s803.h b/drivers/media/tuners/mc44s803.h new file mode 100644 index 000000000000..34f3892d3f6d --- /dev/null +++ b/drivers/media/tuners/mc44s803.h @@ -0,0 +1,46 @@ +/* + * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner + * + * Copyright (c) 2009 Jochen Friedrich + * + * 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 MC44S803_H +#define MC44S803_H + +struct dvb_frontend; +struct i2c_adapter; + +struct mc44s803_config { + u8 i2c_address; + u8 dig_out; +}; + +#if defined(CONFIG_MEDIA_TUNER_MC44S803) || \ + (defined(CONFIG_MEDIA_TUNER_MC44S803_MODULE) && defined(MODULE)) +extern struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct mc44s803_config *cfg); +#else +static inline struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct mc44s803_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_MEDIA_TUNER_MC44S803 */ + +#endif diff --git a/drivers/media/tuners/mc44s803_priv.h b/drivers/media/tuners/mc44s803_priv.h new file mode 100644 index 000000000000..14a92780906d --- /dev/null +++ b/drivers/media/tuners/mc44s803_priv.h @@ -0,0 +1,208 @@ +/* + * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner + * + * Copyright (c) 2009 Jochen Friedrich + * + * 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 MC44S803_PRIV_H +#define MC44S803_PRIV_H + +/* This driver is based on the information available in the datasheet + http://www.freescale.com/files/rf_if/doc/data_sheet/MC44S803.pdf + + SPI or I2C Address : 0xc0-0xc6 + + Reg.No | Function + ------------------------------------------- + 00 | Power Down + 01 | Reference Oszillator + 02 | Reference Dividers + 03 | Mixer and Reference Buffer + 04 | Reset/Serial Out + 05 | LO 1 + 06 | LO 2 + 07 | Circuit Adjust + 08 | Test + 09 | Digital Tune + 0A | LNA AGC + 0B | Data Register Address + 0C | Regulator Test + 0D | VCO Test + 0E | LNA Gain/Input Power + 0F | ID Bits + +*/ + +#define MC44S803_OSC 26000000 /* 26 MHz */ +#define MC44S803_IF1 1086000000 /* 1086 MHz */ +#define MC44S803_IF2 36125000 /* 36.125 MHz */ + +#define MC44S803_REG_POWER 0 +#define MC44S803_REG_REFOSC 1 +#define MC44S803_REG_REFDIV 2 +#define MC44S803_REG_MIXER 3 +#define MC44S803_REG_RESET 4 +#define MC44S803_REG_LO1 5 +#define MC44S803_REG_LO2 6 +#define MC44S803_REG_CIRCADJ 7 +#define MC44S803_REG_TEST 8 +#define MC44S803_REG_DIGTUNE 9 +#define MC44S803_REG_LNAAGC 0x0A +#define MC44S803_REG_DATAREG 0x0B +#define MC44S803_REG_REGTEST 0x0C +#define MC44S803_REG_VCOTEST 0x0D +#define MC44S803_REG_LNAGAIN 0x0E +#define MC44S803_REG_ID 0x0F + +/* Register definitions */ +#define MC44S803_ADDR 0x0F +#define MC44S803_ADDR_S 0 +/* REG_POWER */ +#define MC44S803_POWER 0xFFFFF0 +#define MC44S803_POWER_S 4 +/* REG_REFOSC */ +#define MC44S803_REFOSC 0x1FF0 +#define MC44S803_REFOSC_S 4 +#define MC44S803_OSCSEL 0x2000 +#define MC44S803_OSCSEL_S 13 +/* REG_REFDIV */ +#define MC44S803_R2 0x1FF0 +#define MC44S803_R2_S 4 +#define MC44S803_REFBUF_EN 0x2000 +#define MC44S803_REFBUF_EN_S 13 +#define MC44S803_R1 0x7C000 +#define MC44S803_R1_S 14 +/* REG_MIXER */ +#define MC44S803_R3 0x70 +#define MC44S803_R3_S 4 +#define MC44S803_MUX3 0x80 +#define MC44S803_MUX3_S 7 +#define MC44S803_MUX4 0x100 +#define MC44S803_MUX4_S 8 +#define MC44S803_OSC_SCR 0x200 +#define MC44S803_OSC_SCR_S 9 +#define MC44S803_TRI_STATE 0x400 +#define MC44S803_TRI_STATE_S 10 +#define MC44S803_BUF_GAIN 0x800 +#define MC44S803_BUF_GAIN_S 11 +#define MC44S803_BUF_IO 0x1000 +#define MC44S803_BUF_IO_S 12 +#define MC44S803_MIXER_RES 0xFE000 +#define MC44S803_MIXER_RES_S 13 +/* REG_RESET */ +#define MC44S803_RS 0x10 +#define MC44S803_RS_S 4 +#define MC44S803_SO 0x20 +#define MC44S803_SO_S 5 +/* REG_LO1 */ +#define MC44S803_LO1 0xFFF0 +#define MC44S803_LO1_S 4 +/* REG_LO2 */ +#define MC44S803_LO2 0x7FFF0 +#define MC44S803_LO2_S 4 +/* REG_CIRCADJ */ +#define MC44S803_G1 0x20 +#define MC44S803_G1_S 5 +#define MC44S803_G3 0x80 +#define MC44S803_G3_S 7 +#define MC44S803_CIRCADJ_RES 0x300 +#define MC44S803_CIRCADJ_RES_S 8 +#define MC44S803_G6 0x400 +#define MC44S803_G6_S 10 +#define MC44S803_G7 0x800 +#define MC44S803_G7_S 11 +#define MC44S803_S1 0x1000 +#define MC44S803_S1_S 12 +#define MC44S803_LP 0x7E000 +#define MC44S803_LP_S 13 +#define MC44S803_CLRF 0x80000 +#define MC44S803_CLRF_S 19 +#define MC44S803_CLIF 0x100000 +#define MC44S803_CLIF_S 20 +/* REG_TEST */ +/* REG_DIGTUNE */ +#define MC44S803_DA 0xF0 +#define MC44S803_DA_S 4 +#define MC44S803_XOD 0x300 +#define MC44S803_XOD_S 8 +#define MC44S803_RST 0x10000 +#define MC44S803_RST_S 16 +#define MC44S803_LO_REF 0x1FFF00 +#define MC44S803_LO_REF_S 8 +#define MC44S803_AT 0x200000 +#define MC44S803_AT_S 21 +#define MC44S803_MT 0x400000 +#define MC44S803_MT_S 22 +/* REG_LNAAGC */ +#define MC44S803_G 0x3F0 +#define MC44S803_G_S 4 +#define MC44S803_AT1 0x400 +#define MC44S803_AT1_S 10 +#define MC44S803_AT2 0x800 +#define MC44S803_AT2_S 11 +#define MC44S803_HL_GR_EN 0x8000 +#define MC44S803_HL_GR_EN_S 15 +#define MC44S803_AGC_AN_DIG 0x10000 +#define MC44S803_AGC_AN_DIG_S 16 +#define MC44S803_ATTEN_EN 0x20000 +#define MC44S803_ATTEN_EN_S 17 +#define MC44S803_AGC_READ_EN 0x40000 +#define MC44S803_AGC_READ_EN_S 18 +#define MC44S803_LNA0 0x80000 +#define MC44S803_LNA0_S 19 +#define MC44S803_AGC_SEL 0x100000 +#define MC44S803_AGC_SEL_S 20 +#define MC44S803_AT0 0x200000 +#define MC44S803_AT0_S 21 +#define MC44S803_B 0xC00000 +#define MC44S803_B_S 22 +/* REG_DATAREG */ +#define MC44S803_D 0xF0 +#define MC44S803_D_S 4 +/* REG_REGTEST */ +/* REG_VCOTEST */ +/* REG_LNAGAIN */ +#define MC44S803_IF_PWR 0x700 +#define MC44S803_IF_PWR_S 8 +#define MC44S803_RF_PWR 0x3800 +#define MC44S803_RF_PWR_S 11 +#define MC44S803_LNA_GAIN 0xFC000 +#define MC44S803_LNA_GAIN_S 14 +/* REG_ID */ +#define MC44S803_ID 0x3E00 +#define MC44S803_ID_S 9 + +/* Some macros to read/write fields */ + +/* First shift, then mask */ +#define MC44S803_REG_SM(_val, _reg) \ + (((_val) << _reg##_S) & (_reg)) + +/* First mask, then shift */ +#define MC44S803_REG_MS(_val, _reg) \ + (((_val) & (_reg)) >> _reg##_S) + +struct mc44s803_priv { + struct mc44s803_config *cfg; + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + + u32 frequency; +}; + +#endif diff --git a/drivers/media/tuners/mt2060.c b/drivers/media/tuners/mt2060.c new file mode 100644 index 000000000000..13381de58a84 --- /dev/null +++ b/drivers/media/tuners/mt2060.c @@ -0,0 +1,403 @@ +/* + * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" + * + * Copyright (c) 2006 Olivier DANET + * + * 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.= + */ + +/* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "mt2060.h" +#include "mt2060_priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2060: " args); printk("\n"); }} while (0) + +// Reads a single register +static int mt2060_readreg(struct mt2060_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "mt2060 I2C read failed\n"); + return -EREMOTEIO; + } + return 0; +} + +// Writes a single register +static int mt2060_writereg(struct mt2060_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 + }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mt2060 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +// Writes a set of consecutive registers +static int mt2060_writeregs(struct mt2060_priv *priv,u8 *buf, u8 len) +{ + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len + }; + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n",(int)len); + return -EREMOTEIO; + } + return 0; +} + +// Initialisation sequences +// LNABAND=3, NUM1=0x3C, DIV1=0x74, NUM2=0x1080, DIV2=0x49 +static u8 mt2060_config1[] = { + REG_LO1C1, + 0x3F, 0x74, 0x00, 0x08, 0x93 +}; + +// FMCG=2, GP2=0, GP1=0 +static u8 mt2060_config2[] = { + REG_MISC_CTRL, + 0x20, 0x1E, 0x30, 0xff, 0x80, 0xff, 0x00, 0x2c, 0x42 +}; + +// VGAG=3, V1CSE=1 + +#ifdef MT2060_SPURCHECK +/* The function below calculates the frequency offset between the output frequency if2 + and the closer cross modulation subcarrier between lo1 and lo2 up to the tenth harmonic */ +static int mt2060_spurcalc(u32 lo1,u32 lo2,u32 if2) +{ + int I,J; + int dia,diamin,diff; + diamin=1000000; + for (I = 1; I < 10; I++) { + J = ((2*I*lo1)/lo2+1)/2; + diff = I*(int)lo1-J*(int)lo2; + if (diff < 0) diff=-diff; + dia = (diff-(int)if2); + if (dia < 0) dia=-dia; + if (diamin > dia) diamin=dia; + } + return diamin; +} + +#define BANDWIDTH 4000 // kHz + +/* Calculates the frequency offset to add to avoid spurs. Returns 0 if no offset is needed */ +static int mt2060_spurcheck(u32 lo1,u32 lo2,u32 if2) +{ + u32 Spur,Sp1,Sp2; + int I,J; + I=0; + J=1000; + + Spur=mt2060_spurcalc(lo1,lo2,if2); + if (Spur < BANDWIDTH) { + /* Potential spurs detected */ + dprintk("Spurs before : f_lo1: %d f_lo2: %d (kHz)", + (int)lo1,(int)lo2); + I=1000; + Sp1 = mt2060_spurcalc(lo1+I,lo2+I,if2); + Sp2 = mt2060_spurcalc(lo1-I,lo2-I,if2); + + if (Sp1 < Sp2) { + J=-J; I=-I; Spur=Sp2; + } else + Spur=Sp1; + + while (Spur < BANDWIDTH) { + I += J; + Spur = mt2060_spurcalc(lo1+I,lo2+I,if2); + } + dprintk("Spurs after : f_lo1: %d f_lo2: %d (kHz)", + (int)(lo1+I),(int)(lo2+I)); + } + return I; +} +#endif + +#define IF2 36150 // IF2 frequency = 36.150 MHz +#define FREF 16000 // Quartz oscillator 16 MHz + +static int mt2060_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct mt2060_priv *priv; + int ret=0; + int i=0; + u32 freq; + u8 lnaband; + u32 f_lo1,f_lo2; + u32 div1,num1,div2,num2; + u8 b[8]; + u32 if1; + + priv = fe->tuner_priv; + + if1 = priv->if1_freq; + b[0] = REG_LO1B1; + b[1] = 0xFF; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + mt2060_writeregs(priv,b,2); + + freq = c->frequency / 1000; /* Hz -> kHz */ + + f_lo1 = freq + if1 * 1000; + f_lo1 = (f_lo1 / 250) * 250; + f_lo2 = f_lo1 - freq - IF2; + // From the Comtech datasheet, the step used is 50kHz. The tuner chip could be more precise + f_lo2 = ((f_lo2 + 25) / 50) * 50; + priv->frequency = (f_lo1 - f_lo2 - IF2) * 1000, + +#ifdef MT2060_SPURCHECK + // LO-related spurs detection and correction + num1 = mt2060_spurcheck(f_lo1,f_lo2,IF2); + f_lo1 += num1; + f_lo2 += num1; +#endif + //Frequency LO1 = 16MHz * (DIV1 + NUM1/64 ) + num1 = f_lo1 / (FREF / 64); + div1 = num1 / 64; + num1 &= 0x3f; + + // Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) + num2 = f_lo2 * 64 / (FREF / 128); + div2 = num2 / 8192; + num2 &= 0x1fff; + + if (freq <= 95000) lnaband = 0xB0; else + if (freq <= 180000) lnaband = 0xA0; else + if (freq <= 260000) lnaband = 0x90; else + if (freq <= 335000) lnaband = 0x80; else + if (freq <= 425000) lnaband = 0x70; else + if (freq <= 480000) lnaband = 0x60; else + if (freq <= 570000) lnaband = 0x50; else + if (freq <= 645000) lnaband = 0x40; else + if (freq <= 730000) lnaband = 0x30; else + if (freq <= 810000) lnaband = 0x20; else lnaband = 0x10; + + b[0] = REG_LO1C1; + b[1] = lnaband | ((num1 >>2) & 0x0F); + b[2] = div1; + b[3] = (num2 & 0x0F) | ((num1 & 3) << 4); + b[4] = num2 >> 4; + b[5] = ((num2 >>12) & 1) | (div2 << 1); + + dprintk("IF1: %dMHz",(int)if1); + dprintk("PLL freq=%dkHz f_lo1=%dkHz f_lo2=%dkHz",(int)freq,(int)f_lo1,(int)f_lo2); + dprintk("PLL div1=%d num1=%d div2=%d num2=%d",(int)div1,(int)num1,(int)div2,(int)num2); + dprintk("PLL [1..5]: %2x %2x %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3],(int)b[4],(int)b[5]); + + mt2060_writeregs(priv,b,6); + + //Waits for pll lock or timeout + i = 0; + do { + mt2060_readreg(priv,REG_LO_STATUS,b); + if ((b[0] & 0x88)==0x88) + break; + msleep(4); + i++; + } while (i<10); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + return ret; +} + +static void mt2060_calibrate(struct mt2060_priv *priv) +{ + u8 b = 0; + int i = 0; + + if (mt2060_writeregs(priv,mt2060_config1,sizeof(mt2060_config1))) + return; + if (mt2060_writeregs(priv,mt2060_config2,sizeof(mt2060_config2))) + return; + + /* initialize the clock output */ + mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30); + + do { + b |= (1 << 6); // FM1SS; + mt2060_writereg(priv, REG_LO2C1,b); + msleep(20); + + if (i == 0) { + b |= (1 << 7); // FM1CA; + mt2060_writereg(priv, REG_LO2C1,b); + b &= ~(1 << 7); // FM1CA; + msleep(20); + } + + b &= ~(1 << 6); // FM1SS + mt2060_writereg(priv, REG_LO2C1,b); + + msleep(20); + i++; + } while (i < 9); + + i = 0; + while (i++ < 10 && mt2060_readreg(priv, REG_MISC_STAT, &b) == 0 && (b & (1 << 6)) == 0) + msleep(20); + + if (i <= 10) { + mt2060_readreg(priv, REG_FM_FREQ, &priv->fmfreq); // now find out, what is fmreq used for :) + dprintk("calibration was successful: %d", (int)priv->fmfreq); + } else + dprintk("FMCAL timed out"); +} + +static int mt2060_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mt2060_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int mt2060_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + *frequency = IF2 * 1000; + return 0; +} + +static int mt2060_init(struct dvb_frontend *fe) +{ + struct mt2060_priv *priv = fe->tuner_priv; + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + ret = mt2060_writereg(priv, REG_VGAG, + (priv->cfg->clock_out << 6) | 0x33); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + return ret; +} + +static int mt2060_sleep(struct dvb_frontend *fe) +{ + struct mt2060_priv *priv = fe->tuner_priv; + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + ret = mt2060_writereg(priv, REG_VGAG, + (priv->cfg->clock_out << 6) | 0x30); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + return ret; +} + +static int mt2060_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops mt2060_tuner_ops = { + .info = { + .name = "Microtune MT2060", + .frequency_min = 48000000, + .frequency_max = 860000000, + .frequency_step = 50000, + }, + + .release = mt2060_release, + + .init = mt2060_init, + .sleep = mt2060_sleep, + + .set_params = mt2060_set_params, + .get_frequency = mt2060_get_frequency, + .get_if_frequency = mt2060_get_if_frequency, +}; + +/* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */ +struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) +{ + struct mt2060_priv *priv = NULL; + u8 id = 0; + + priv = kzalloc(sizeof(struct mt2060_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + priv->if1_freq = if1; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) { + kfree(priv); + return NULL; + } + + if (id != PART_REV) { + kfree(priv); + return NULL; + } + printk(KERN_INFO "MT2060: successfully identified (IF1 = %d)\n", if1); + memcpy(&fe->ops.tuner_ops, &mt2060_tuner_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + + mt2060_calibrate(priv); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + return fe; +} +EXPORT_SYMBOL(mt2060_attach); + +MODULE_AUTHOR("Olivier DANET"); +MODULE_DESCRIPTION("Microtune MT2060 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/mt2060.h b/drivers/media/tuners/mt2060.h new file mode 100644 index 000000000000..cb60caffb6b6 --- /dev/null +++ b/drivers/media/tuners/mt2060.h @@ -0,0 +1,43 @@ +/* + * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" + * + * Copyright (c) 2006 Olivier DANET + * + * 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 MT2060_H +#define MT2060_H + +struct dvb_frontend; +struct i2c_adapter; + +struct mt2060_config { + u8 i2c_address; + u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ +}; + +#if defined(CONFIG_MEDIA_TUNER_MT2060) || (defined(CONFIG_MEDIA_TUNER_MT2060_MODULE) && defined(MODULE)) +extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1); +#else +static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_MEDIA_TUNER_MT2060 + +#endif diff --git a/drivers/media/tuners/mt2060_priv.h b/drivers/media/tuners/mt2060_priv.h new file mode 100644 index 000000000000..2b60de6c707d --- /dev/null +++ b/drivers/media/tuners/mt2060_priv.h @@ -0,0 +1,104 @@ +/* + * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" + * + * Copyright (c) 2006 Olivier DANET + * + * 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 MT2060_PRIV_H +#define MT2060_PRIV_H + +// Uncomment the #define below to enable spurs checking. The results where quite unconvincing. +// #define MT2060_SPURCHECK + +/* This driver is based on the information available in the datasheet of the + "Comtech SDVBT-3K6M" tuner ( K1000737843.pdf ) which features the MT2060 register map : + + I2C Address : 0x60 + + Reg.No | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | ( defaults ) + -------------------------------------------------------------------------------- + 00 | [ PART ] | [ REV ] | R = 0x63 + 01 | [ LNABAND ] | [ NUM1(5:2) ] | RW = 0x3F + 02 | [ DIV1 ] | RW = 0x74 + 03 | FM1CA | FM1SS | [ NUM1(1:0) ] | [ NUM2(3:0) ] | RW = 0x00 + 04 | NUM2(11:4) ] | RW = 0x08 + 05 | [ DIV2 ] |NUM2(12)| RW = 0x93 + 06 | L1LK | [ TAD1 ] | L2LK | [ TAD2 ] | R + 07 | [ FMF ] | R + 08 | ? | FMCAL | ? | ? | ? | ? | ? | TEMP | R + 09 | 0 | 0 | [ FMGC ] | 0 | GP02 | GP01 | 0 | RW = 0x20 + 0A | ?? + 0B | 0 | 0 | 1 | 1 | 0 | 0 | [ VGAG ] | RW = 0x30 + 0C | V1CSE | 1 | 1 | 1 | 1 | 1 | 1 | 1 | RW = 0xFF + 0D | 1 | 0 | [ V1CS ] | RW = 0xB0 + 0E | ?? + 0F | ?? + 10 | ?? + 11 | [ LOTO ] | 0 | 0 | 1 | 0 | RW = 0x42 + + PART : Part code : 6 for MT2060 + REV : Revision code : 3 for current revision + LNABAND : Input frequency range : ( See code for details ) + NUM1 / DIV1 / NUM2 / DIV2 : Frequencies programming ( See code for details ) + FM1CA : Calibration Start Bit + FM1SS : Calibration Single Step bit + L1LK : LO1 Lock Detect + TAD1 : Tune Line ADC ( ? ) + L2LK : LO2 Lock Detect + TAD2 : Tune Line ADC ( ? ) + FMF : Estimated first IF Center frequency Offset ( ? ) + FM1CAL : Calibration done bit + TEMP : On chip temperature sensor + FMCG : Mixer 1 Cap Gain ( ? ) + GP01 / GP02 : Programmable digital outputs. Unconnected pins ? + V1CSE : LO1 VCO Automatic Capacitor Select Enable ( ? ) + V1CS : LO1 Capacitor Selection Value ( ? ) + LOTO : LO Timeout ( ? ) + VGAG : Tuner Output gain +*/ + +#define I2C_ADDRESS 0x60 + +#define REG_PART_REV 0 +#define REG_LO1C1 1 +#define REG_LO1C2 2 +#define REG_LO2C1 3 +#define REG_LO2C2 4 +#define REG_LO2C3 5 +#define REG_LO_STATUS 6 +#define REG_FM_FREQ 7 +#define REG_MISC_STAT 8 +#define REG_MISC_CTRL 9 +#define REG_RESERVED_A 0x0A +#define REG_VGAG 0x0B +#define REG_LO1B1 0x0C +#define REG_LO1B2 0x0D +#define REG_LOTO 0x11 + +#define PART_REV 0x63 // The current driver works only with PART=6 and REV=3 chips + +struct mt2060_priv { + struct mt2060_config *cfg; + struct i2c_adapter *i2c; + + u32 frequency; + u16 if1_freq; + u8 fmfreq; +}; + +#endif diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c new file mode 100644 index 000000000000..0ed9091ff48e --- /dev/null +++ b/drivers/media/tuners/mt2063.c @@ -0,0 +1,2307 @@ +/* + * Driver for mt2063 Micronas tuner + * + * Copyright (c) 2011 Mauro Carvalho Chehab + * + * This driver came from a driver originally written by: + * Henry Wang + * Made publicly available by Terratec, at: + * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz + * The original driver's license is GPL, as declared with MODULE_LICENSE() + * + * 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 under version 2 of the License. + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include "mt2063.h" + +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Set Verbosity level"); + +#define dprintk(level, fmt, arg...) do { \ +if (debug >= level) \ + printk(KERN_DEBUG "mt2063 %s: " fmt, __func__, ## arg); \ +} while (0) + + +/* positive error codes used internally */ + +/* Info: Unavoidable LO-related spur may be present in the output */ +#define MT2063_SPUR_PRESENT_ERR (0x00800000) + +/* Info: Mask of bits used for # of LO-related spurs that were avoided during tuning */ +#define MT2063_SPUR_CNT_MASK (0x001f0000) +#define MT2063_SPUR_SHIFT (16) + +/* Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */ +#define MT2063_UPC_RANGE (0x04000000) + +/* Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */ +#define MT2063_DNC_RANGE (0x08000000) + +/* + * Constant defining the version of the following structure + * and therefore the API for this code. + * + * When compiling the tuner driver, the preprocessor will + * check against this version number to make sure that + * it matches the version that the tuner driver knows about. + */ + +/* DECT Frequency Avoidance */ +#define MT2063_DECT_AVOID_US_FREQS 0x00000001 + +#define MT2063_DECT_AVOID_EURO_FREQS 0x00000002 + +#define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0) + +#define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0) + +enum MT2063_DECT_Avoid_Type { + MT2063_NO_DECT_AVOIDANCE = 0, /* Do not create DECT exclusion zones. */ + MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS, /* Avoid US DECT frequencies. */ + MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS, /* Avoid European DECT frequencies. */ + MT2063_AVOID_BOTH /* Avoid both regions. Not typically used. */ +}; + +#define MT2063_MAX_ZONES 48 + +struct MT2063_ExclZone_t { + u32 min_; + u32 max_; + struct MT2063_ExclZone_t *next_; +}; + +/* + * Structure of data needed for Spur Avoidance + */ +struct MT2063_AvoidSpursData_t { + u32 f_ref; + u32 f_in; + u32 f_LO1; + u32 f_if1_Center; + u32 f_if1_Request; + u32 f_if1_bw; + u32 f_LO2; + u32 f_out; + u32 f_out_bw; + u32 f_LO1_Step; + u32 f_LO2_Step; + u32 f_LO1_FracN_Avoid; + u32 f_LO2_FracN_Avoid; + u32 f_zif_bw; + u32 f_min_LO_Separation; + u32 maxH1; + u32 maxH2; + enum MT2063_DECT_Avoid_Type avoidDECT; + u32 bSpurPresent; + u32 bSpurAvoided; + u32 nSpursFound; + u32 nZones; + struct MT2063_ExclZone_t *freeZones; + struct MT2063_ExclZone_t *usedZones; + struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES]; +}; + +/* + * Parameter for function MT2063_SetPowerMask that specifies the power down + * of various sections of the MT2063. + */ +enum MT2063_Mask_Bits { + MT2063_REG_SD = 0x0040, /* Shutdown regulator */ + MT2063_SRO_SD = 0x0020, /* Shutdown SRO */ + MT2063_AFC_SD = 0x0010, /* Shutdown AFC A/D */ + MT2063_PD_SD = 0x0002, /* Enable power detector shutdown */ + MT2063_PDADC_SD = 0x0001, /* Enable power detector A/D shutdown */ + MT2063_VCO_SD = 0x8000, /* Enable VCO shutdown */ + MT2063_LTX_SD = 0x4000, /* Enable LTX shutdown */ + MT2063_LT1_SD = 0x2000, /* Enable LT1 shutdown */ + MT2063_LNA_SD = 0x1000, /* Enable LNA shutdown */ + MT2063_UPC_SD = 0x0800, /* Enable upconverter shutdown */ + MT2063_DNC_SD = 0x0400, /* Enable downconverter shutdown */ + MT2063_VGA_SD = 0x0200, /* Enable VGA shutdown */ + MT2063_AMP_SD = 0x0100, /* Enable AMP shutdown */ + MT2063_ALL_SD = 0xFF73, /* All shutdown bits for this tuner */ + MT2063_NONE_SD = 0x0000 /* No shutdown bits */ +}; + +/* + * Possible values for MT2063_DNC_OUTPUT + */ +enum MT2063_DNC_Output_Enable { + MT2063_DNC_NONE = 0, + MT2063_DNC_1, + MT2063_DNC_2, + MT2063_DNC_BOTH +}; + +/* + * Two-wire serial bus subaddresses of the tuner registers. + * Also known as the tuner's register addresses. + */ +enum MT2063_Register_Offsets { + MT2063_REG_PART_REV = 0, /* 0x00: Part/Rev Code */ + MT2063_REG_LO1CQ_1, /* 0x01: LO1C Queued Byte 1 */ + MT2063_REG_LO1CQ_2, /* 0x02: LO1C Queued Byte 2 */ + MT2063_REG_LO2CQ_1, /* 0x03: LO2C Queued Byte 1 */ + MT2063_REG_LO2CQ_2, /* 0x04: LO2C Queued Byte 2 */ + MT2063_REG_LO2CQ_3, /* 0x05: LO2C Queued Byte 3 */ + MT2063_REG_RSVD_06, /* 0x06: Reserved */ + MT2063_REG_LO_STATUS, /* 0x07: LO Status */ + MT2063_REG_FIFFC, /* 0x08: FIFF Center */ + MT2063_REG_CLEARTUNE, /* 0x09: ClearTune Filter */ + MT2063_REG_ADC_OUT, /* 0x0A: ADC_OUT */ + MT2063_REG_LO1C_1, /* 0x0B: LO1C Byte 1 */ + MT2063_REG_LO1C_2, /* 0x0C: LO1C Byte 2 */ + MT2063_REG_LO2C_1, /* 0x0D: LO2C Byte 1 */ + MT2063_REG_LO2C_2, /* 0x0E: LO2C Byte 2 */ + MT2063_REG_LO2C_3, /* 0x0F: LO2C Byte 3 */ + MT2063_REG_RSVD_10, /* 0x10: Reserved */ + MT2063_REG_PWR_1, /* 0x11: PWR Byte 1 */ + MT2063_REG_PWR_2, /* 0x12: PWR Byte 2 */ + MT2063_REG_TEMP_STATUS, /* 0x13: Temp Status */ + MT2063_REG_XO_STATUS, /* 0x14: Crystal Status */ + MT2063_REG_RF_STATUS, /* 0x15: RF Attn Status */ + MT2063_REG_FIF_STATUS, /* 0x16: FIF Attn Status */ + MT2063_REG_LNA_OV, /* 0x17: LNA Attn Override */ + MT2063_REG_RF_OV, /* 0x18: RF Attn Override */ + MT2063_REG_FIF_OV, /* 0x19: FIF Attn Override */ + MT2063_REG_LNA_TGT, /* 0x1A: Reserved */ + MT2063_REG_PD1_TGT, /* 0x1B: Pwr Det 1 Target */ + MT2063_REG_PD2_TGT, /* 0x1C: Pwr Det 2 Target */ + MT2063_REG_RSVD_1D, /* 0x1D: Reserved */ + MT2063_REG_RSVD_1E, /* 0x1E: Reserved */ + MT2063_REG_RSVD_1F, /* 0x1F: Reserved */ + MT2063_REG_RSVD_20, /* 0x20: Reserved */ + MT2063_REG_BYP_CTRL, /* 0x21: Bypass Control */ + MT2063_REG_RSVD_22, /* 0x22: Reserved */ + MT2063_REG_RSVD_23, /* 0x23: Reserved */ + MT2063_REG_RSVD_24, /* 0x24: Reserved */ + MT2063_REG_RSVD_25, /* 0x25: Reserved */ + MT2063_REG_RSVD_26, /* 0x26: Reserved */ + MT2063_REG_RSVD_27, /* 0x27: Reserved */ + MT2063_REG_FIFF_CTRL, /* 0x28: FIFF Control */ + MT2063_REG_FIFF_OFFSET, /* 0x29: FIFF Offset */ + MT2063_REG_CTUNE_CTRL, /* 0x2A: Reserved */ + MT2063_REG_CTUNE_OV, /* 0x2B: Reserved */ + MT2063_REG_CTRL_2C, /* 0x2C: Reserved */ + MT2063_REG_FIFF_CTRL2, /* 0x2D: Fiff Control */ + MT2063_REG_RSVD_2E, /* 0x2E: Reserved */ + MT2063_REG_DNC_GAIN, /* 0x2F: DNC Control */ + MT2063_REG_VGA_GAIN, /* 0x30: VGA Gain Ctrl */ + MT2063_REG_RSVD_31, /* 0x31: Reserved */ + MT2063_REG_TEMP_SEL, /* 0x32: Temperature Selection */ + MT2063_REG_RSVD_33, /* 0x33: Reserved */ + MT2063_REG_RSVD_34, /* 0x34: Reserved */ + MT2063_REG_RSVD_35, /* 0x35: Reserved */ + MT2063_REG_RSVD_36, /* 0x36: Reserved */ + MT2063_REG_RSVD_37, /* 0x37: Reserved */ + MT2063_REG_RSVD_38, /* 0x38: Reserved */ + MT2063_REG_RSVD_39, /* 0x39: Reserved */ + MT2063_REG_RSVD_3A, /* 0x3A: Reserved */ + MT2063_REG_RSVD_3B, /* 0x3B: Reserved */ + MT2063_REG_RSVD_3C, /* 0x3C: Reserved */ + MT2063_REG_END_REGS +}; + +struct mt2063_state { + struct i2c_adapter *i2c; + + bool init; + + const struct mt2063_config *config; + struct dvb_tuner_ops ops; + struct dvb_frontend *frontend; + struct tuner_state status; + + u32 frequency; + u32 srate; + u32 bandwidth; + u32 reference; + + u32 tuner_id; + struct MT2063_AvoidSpursData_t AS_Data; + u32 f_IF1_actual; + u32 rcvr_mode; + u32 ctfilt_sw; + u32 CTFiltMax[31]; + u32 num_regs; + u8 reg[MT2063_REG_END_REGS]; +}; + +/* + * mt2063_write - Write data into the I2C bus + */ +static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len) +{ + struct dvb_frontend *fe = state->frontend; + int ret; + u8 buf[60]; + struct i2c_msg msg = { + .addr = state->config->tuner_address, + .flags = 0, + .buf = buf, + .len = len + 1 + }; + + dprintk(2, "\n"); + + msg.buf[0] = reg; + memcpy(msg.buf + 1, data, len); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + ret = i2c_transfer(state->i2c, &msg, 1); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (ret < 0) + printk(KERN_ERR "%s error ret=%d\n", __func__, ret); + + return ret; +} + +/* + * mt2063_write - Write register data into the I2C bus, caching the value + */ +static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val) +{ + u32 status; + + dprintk(2, "\n"); + + if (reg >= MT2063_REG_END_REGS) + return -ERANGE; + + status = mt2063_write(state, reg, &val, 1); + if (status < 0) + return status; + + state->reg[reg] = val; + + return 0; +} + +/* + * mt2063_read - Read data from the I2C bus + */ +static u32 mt2063_read(struct mt2063_state *state, + u8 subAddress, u8 *pData, u32 cnt) +{ + u32 status = 0; /* Status to be returned */ + struct dvb_frontend *fe = state->frontend; + u32 i = 0; + + dprintk(2, "addr 0x%02x, cnt %d\n", subAddress, cnt); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + for (i = 0; i < cnt; i++) { + u8 b0[] = { subAddress + i }; + struct i2c_msg msg[] = { + { + .addr = state->config->tuner_address, + .flags = 0, + .buf = b0, + .len = 1 + }, { + .addr = state->config->tuner_address, + .flags = I2C_M_RD, + .buf = pData + i, + .len = 1 + } + }; + + status = i2c_transfer(state->i2c, msg, 2); + dprintk(2, "addr 0x%02x, ret = %d, val = 0x%02x\n", + subAddress + i, status, *(pData + i)); + if (status < 0) + break; + } + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (status < 0) + printk(KERN_ERR "Can't read from address 0x%02x,\n", + subAddress + i); + + return status; +} + +/* + * FIXME: Is this really needed? + */ +static int MT2063_Sleep(struct dvb_frontend *fe) +{ + /* + * ToDo: Add code here to implement a OS blocking + */ + msleep(100); + + return 0; +} + +/* + * Microtune spur avoidance + */ + +/* Implement ceiling, floor functions. */ +#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0)) +#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d)) + +struct MT2063_FIFZone_t { + s32 min_; + s32 max_; +}; + +static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t + *pAS_Info, + struct MT2063_ExclZone_t *pPrevNode) +{ + struct MT2063_ExclZone_t *pNode; + + dprintk(2, "\n"); + + /* Check for a node in the free list */ + if (pAS_Info->freeZones != NULL) { + /* Use one from the free list */ + pNode = pAS_Info->freeZones; + pAS_Info->freeZones = pNode->next_; + } else { + /* Grab a node from the array */ + pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones]; + } + + if (pPrevNode != NULL) { + pNode->next_ = pPrevNode->next_; + pPrevNode->next_ = pNode; + } else { /* insert at the beginning of the list */ + + pNode->next_ = pAS_Info->usedZones; + pAS_Info->usedZones = pNode; + } + + pAS_Info->nZones++; + return pNode; +} + +static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t + *pAS_Info, + struct MT2063_ExclZone_t *pPrevNode, + struct MT2063_ExclZone_t + *pNodeToRemove) +{ + struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_; + + dprintk(2, "\n"); + + /* Make previous node point to the subsequent node */ + if (pPrevNode != NULL) + pPrevNode->next_ = pNext; + + /* Add pNodeToRemove to the beginning of the freeZones */ + pNodeToRemove->next_ = pAS_Info->freeZones; + pAS_Info->freeZones = pNodeToRemove; + + /* Decrement node count */ + pAS_Info->nZones--; + + return pNext; +} + +/* + * MT_AddExclZone() + * + * Add (and merge) an exclusion zone into the list. + * If the range (f_min, f_max) is totally outside the + * 1st IF BW, ignore the entry. + * If the range (f_min, f_max) is negative, ignore the entry. + */ +static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info, + u32 f_min, u32 f_max) +{ + struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones; + struct MT2063_ExclZone_t *pPrev = NULL; + struct MT2063_ExclZone_t *pNext = NULL; + + dprintk(2, "\n"); + + /* Check to see if this overlaps the 1st IF filter */ + if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2))) + && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2))) + && (f_min < f_max)) { + /* + * 1 2 3 4 5 6 + * + * New entry: |---| |--| |--| |-| |---| |--| + * or or or or or + * Existing: |--| |--| |--| |---| |-| |--| + */ + + /* Check for our place in the list */ + while ((pNode != NULL) && (pNode->max_ < f_min)) { + pPrev = pNode; + pNode = pNode->next_; + } + + if ((pNode != NULL) && (pNode->min_ < f_max)) { + /* Combine me with pNode */ + if (f_min < pNode->min_) + pNode->min_ = f_min; + if (f_max > pNode->max_) + pNode->max_ = f_max; + } else { + pNode = InsertNode(pAS_Info, pPrev); + pNode->min_ = f_min; + pNode->max_ = f_max; + } + + /* Look for merging possibilities */ + pNext = pNode->next_; + while ((pNext != NULL) && (pNext->min_ < pNode->max_)) { + if (pNext->max_ > pNode->max_) + pNode->max_ = pNext->max_; + /* Remove pNext, return ptr to pNext->next */ + pNext = RemoveNode(pAS_Info, pNode, pNext); + } + } +} + +/* + * Reset all exclusion zones. + * Add zones to protect the PLL FracN regions near zero + */ +static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info) +{ + u32 center; + + dprintk(2, "\n"); + + pAS_Info->nZones = 0; /* this clears the used list */ + pAS_Info->usedZones = NULL; /* reset ptr */ + pAS_Info->freeZones = NULL; /* reset ptr */ + + center = + pAS_Info->f_ref * + ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 + + pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in; + while (center < + pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 + + pAS_Info->f_LO1_FracN_Avoid) { + /* Exclude LO1 FracN */ + MT2063_AddExclZone(pAS_Info, + center - pAS_Info->f_LO1_FracN_Avoid, + center - 1); + MT2063_AddExclZone(pAS_Info, center + 1, + center + pAS_Info->f_LO1_FracN_Avoid); + center += pAS_Info->f_ref; + } + + center = + pAS_Info->f_ref * + ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 - + pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out; + while (center < + pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 + + pAS_Info->f_LO2_FracN_Avoid) { + /* Exclude LO2 FracN */ + MT2063_AddExclZone(pAS_Info, + center - pAS_Info->f_LO2_FracN_Avoid, + center - 1); + MT2063_AddExclZone(pAS_Info, center + 1, + center + pAS_Info->f_LO2_FracN_Avoid); + center += pAS_Info->f_ref; + } + + if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) { + /* Exclude LO1 values that conflict with DECT channels */ + MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */ + MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */ + MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */ + MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */ + MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */ + } + + if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) { + MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */ + MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */ + MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */ + MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */ + MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */ + MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */ + MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */ + MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */ + MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */ + MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */ + } +} + +/* + * MT_ChooseFirstIF - Choose the best available 1st IF + * If f_Desired is not excluded, choose that first. + * Otherwise, return the value closest to f_Center that is + * not excluded + */ +static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info) +{ + /* + * Update "f_Desired" to be the nearest "combinational-multiple" of + * "f_LO1_Step". + * The resulting number, F_LO1 must be a multiple of f_LO1_Step. + * And F_LO1 is the arithmetic sum of f_in + f_Center. + * Neither f_in, nor f_Center must be a multiple of f_LO1_Step. + * However, the sum must be. + */ + const u32 f_Desired = + pAS_Info->f_LO1_Step * + ((pAS_Info->f_if1_Request + pAS_Info->f_in + + pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) - + pAS_Info->f_in; + const u32 f_Step = + (pAS_Info->f_LO1_Step > + pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info-> + f_LO2_Step; + u32 f_Center; + s32 i; + s32 j = 0; + u32 bDesiredExcluded = 0; + u32 bZeroExcluded = 0; + s32 tmpMin, tmpMax; + s32 bestDiff; + struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones; + struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES]; + + dprintk(2, "\n"); + + if (pAS_Info->nZones == 0) + return f_Desired; + + /* + * f_Center needs to be an integer multiple of f_Step away + * from f_Desired + */ + if (pAS_Info->f_if1_Center > f_Desired) + f_Center = + f_Desired + + f_Step * + ((pAS_Info->f_if1_Center - f_Desired + + f_Step / 2) / f_Step); + else + f_Center = + f_Desired - + f_Step * + ((f_Desired - pAS_Info->f_if1_Center + + f_Step / 2) / f_Step); + + /* + * Take MT_ExclZones, center around f_Center and change the + * resolution to f_Step + */ + while (pNode != NULL) { + /* floor function */ + tmpMin = + floor((s32) (pNode->min_ - f_Center), (s32) f_Step); + + /* ceil function */ + tmpMax = + ceil((s32) (pNode->max_ - f_Center), (s32) f_Step); + + if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired)) + bDesiredExcluded = 1; + + if ((tmpMin < 0) && (tmpMax > 0)) + bZeroExcluded = 1; + + /* See if this zone overlaps the previous */ + if ((j > 0) && (tmpMin < zones[j - 1].max_)) + zones[j - 1].max_ = tmpMax; + else { + /* Add new zone */ + zones[j].min_ = tmpMin; + zones[j].max_ = tmpMax; + j++; + } + pNode = pNode->next_; + } + + /* + * If the desired is okay, return with it + */ + if (bDesiredExcluded == 0) + return f_Desired; + + /* + * If the desired is excluded and the center is okay, return with it + */ + if (bZeroExcluded == 0) + return f_Center; + + /* Find the value closest to 0 (f_Center) */ + bestDiff = zones[0].min_; + for (i = 0; i < j; i++) { + if (abs(zones[i].min_) < abs(bestDiff)) + bestDiff = zones[i].min_; + if (abs(zones[i].max_) < abs(bestDiff)) + bestDiff = zones[i].max_; + } + + if (bestDiff < 0) + return f_Center - ((u32) (-bestDiff) * f_Step); + + return f_Center + (bestDiff * f_Step); +} + +/** + * gcd() - Uses Euclid's algorithm + * + * @u, @v: Unsigned values whose GCD is desired. + * + * Returns THE greatest common divisor of u and v, if either value is 0, + * the other value is returned as the result. + */ +static u32 MT2063_gcd(u32 u, u32 v) +{ + u32 r; + + while (v != 0) { + r = u % v; + u = v; + v = r; + } + + return u; +} + +/** + * IsSpurInBand() - Checks to see if a spur will be present within the IF's + * bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW) + * + * ma mb mc md + * <--+-+-+-------------------+-------------------+-+-+--> + * | ^ 0 ^ | + * ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^ + * a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2 + * + * Note that some equations are doubled to prevent round-off + * problems when calculating fIFBW/2 + * + * @pAS_Info: Avoid Spurs information block + * @fm: If spur, amount f_IF1 has to move negative + * @fp: If spur, amount f_IF1 has to move positive + * + * Returns 1 if an LO spur would be present, otherwise 0. + */ +static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info, + u32 *fm, u32 * fp) +{ + /* + ** Calculate LO frequency settings. + */ + u32 n, n0; + const u32 f_LO1 = pAS_Info->f_LO1; + const u32 f_LO2 = pAS_Info->f_LO2; + const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2; + const u32 c = d - pAS_Info->f_out_bw; + const u32 f = pAS_Info->f_zif_bw / 2; + const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1; + s32 f_nsLO1, f_nsLO2; + s32 f_Spur; + u32 ma, mb, mc, md, me, mf; + u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs; + + dprintk(2, "\n"); + + *fm = 0; + + /* + ** For each edge (d, c & f), calculate a scale, based on the gcd + ** of f_LO1, f_LO2 and the edge value. Use the larger of this + ** gcd-based scale factor or f_Scale. + */ + lo_gcd = MT2063_gcd(f_LO1, f_LO2); + gd_Scale = max((u32) MT2063_gcd(lo_gcd, d), f_Scale); + hgds = gd_Scale / 2; + gc_Scale = max((u32) MT2063_gcd(lo_gcd, c), f_Scale); + hgcs = gc_Scale / 2; + gf_Scale = max((u32) MT2063_gcd(lo_gcd, f), f_Scale); + hgfs = gf_Scale / 2; + + n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2); + + /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */ + for (n = n0; n <= pAS_Info->maxH1; ++n) { + md = (n * ((f_LO1 + hgds) / gd_Scale) - + ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale); + + /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */ + if (md >= pAS_Info->maxH1) + break; + + ma = (n * ((f_LO1 + hgds) / gd_Scale) + + ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale); + + /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */ + if (md == ma) + continue; + + mc = (n * ((f_LO1 + hgcs) / gc_Scale) - + ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale); + if (mc != md) { + f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale)); + f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale)); + f_Spur = + (gc_Scale * (f_nsLO1 - f_nsLO2)) + + n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale); + + *fp = ((f_Spur - (s32) c) / (mc - n)) + 1; + *fm = (((s32) d - f_Spur) / (mc - n)) + 1; + return 1; + } + + /* Location of Zero-IF-spur to be checked */ + me = (n * ((f_LO1 + hgfs) / gf_Scale) + + ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale); + mf = (n * ((f_LO1 + hgfs) / gf_Scale) - + ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale); + if (me != mf) { + f_nsLO1 = n * (f_LO1 / gf_Scale); + f_nsLO2 = me * (f_LO2 / gf_Scale); + f_Spur = + (gf_Scale * (f_nsLO1 - f_nsLO2)) + + n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale); + + *fp = ((f_Spur + (s32) f) / (me - n)) + 1; + *fm = (((s32) f - f_Spur) / (me - n)) + 1; + return 1; + } + + mb = (n * ((f_LO1 + hgcs) / gc_Scale) + + ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale); + if (ma != mb) { + f_nsLO1 = n * (f_LO1 / gc_Scale); + f_nsLO2 = ma * (f_LO2 / gc_Scale); + f_Spur = + (gc_Scale * (f_nsLO1 - f_nsLO2)) + + n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale); + + *fp = (((s32) d + f_Spur) / (ma - n)) + 1; + *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1; + return 1; + } + } + + /* No spurs found */ + return 0; +} + +/* + * MT_AvoidSpurs() - Main entry point to avoid spurs. + * Checks for existing spurs in present LO1, LO2 freqs + * and if present, chooses spur-free LO1, LO2 combination + * that tunes the same input/output frequencies. + */ +static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info) +{ + u32 status = 0; + u32 fm, fp; /* restricted range on LO's */ + pAS_Info->bSpurAvoided = 0; + pAS_Info->nSpursFound = 0; + + dprintk(2, "\n"); + + if (pAS_Info->maxH1 == 0) + return 0; + + /* + * Avoid LO Generated Spurs + * + * Make sure that have no LO-related spurs within the IF output + * bandwidth. + * + * If there is an LO spur in this band, start at the current IF1 frequency + * and work out until we find a spur-free frequency or run up against the + * 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they + * will be unchanged if a spur-free setting is not found. + */ + pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp); + if (pAS_Info->bSpurPresent) { + u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */ + u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */ + u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */ + u32 delta_IF1; + u32 new_IF1; + + /* + ** Spur was found, attempt to find a spur-free 1st IF + */ + do { + pAS_Info->nSpursFound++; + + /* Raise f_IF1_upper, if needed */ + MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp); + + /* Choose next IF1 that is closest to f_IF1_CENTER */ + new_IF1 = MT2063_ChooseFirstIF(pAS_Info); + + if (new_IF1 > zfIF1) { + pAS_Info->f_LO1 += (new_IF1 - zfIF1); + pAS_Info->f_LO2 += (new_IF1 - zfIF1); + } else { + pAS_Info->f_LO1 -= (zfIF1 - new_IF1); + pAS_Info->f_LO2 -= (zfIF1 - new_IF1); + } + zfIF1 = new_IF1; + + if (zfIF1 > pAS_Info->f_if1_Center) + delta_IF1 = zfIF1 - pAS_Info->f_if1_Center; + else + delta_IF1 = pAS_Info->f_if1_Center - zfIF1; + + pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp); + /* + * Continue while the new 1st IF is still within the 1st IF bandwidth + * and there is a spur in the band (again) + */ + } while ((2 * delta_IF1 + pAS_Info->f_out_bw <= pAS_Info->f_if1_bw) && pAS_Info->bSpurPresent); + + /* + * Use the LO-spur free values found. If the search went all + * the way to the 1st IF band edge and always found spurs, just + * leave the original choice. It's as "good" as any other. + */ + if (pAS_Info->bSpurPresent == 1) { + status |= MT2063_SPUR_PRESENT_ERR; + pAS_Info->f_LO1 = zfLO1; + pAS_Info->f_LO2 = zfLO2; + } else + pAS_Info->bSpurAvoided = 1; + } + + status |= + ((pAS_Info-> + nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK); + + return status; +} + +/* + * Constants used by the tuning algorithm + */ +#define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */ +#define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */ +#define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */ +#define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */ +#define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */ +#define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */ +#define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */ +#define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */ +#define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */ +#define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */ +#define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */ +#define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */ +#define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */ +#define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */ +#define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */ +#define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */ +#define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */ +#define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */ + +/* + * Define the supported Part/Rev codes for the MT2063 + */ +#define MT2063_B0 (0x9B) +#define MT2063_B1 (0x9C) +#define MT2063_B2 (0x9D) +#define MT2063_B3 (0x9E) + +/** + * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked + * + * @state: struct mt2063_state pointer + * + * This function returns 0, if no lock, 1 if locked and a value < 1 if error + */ +static unsigned int mt2063_lockStatus(struct mt2063_state *state) +{ + const u32 nMaxWait = 100; /* wait a maximum of 100 msec */ + const u32 nPollRate = 2; /* poll status bits every 2 ms */ + const u32 nMaxLoops = nMaxWait / nPollRate; + const u8 LO1LK = 0x80; + u8 LO2LK = 0x08; + u32 status; + u32 nDelays = 0; + + dprintk(2, "\n"); + + /* LO2 Lock bit was in a different place for B0 version */ + if (state->tuner_id == MT2063_B0) + LO2LK = 0x40; + + do { + status = mt2063_read(state, MT2063_REG_LO_STATUS, + &state->reg[MT2063_REG_LO_STATUS], 1); + + if (status < 0) + return status; + + if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) == + (LO1LK | LO2LK)) { + return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO; + } + msleep(nPollRate); /* Wait between retries */ + } while (++nDelays < nMaxLoops); + + /* + * Got no lock or partial lock + */ + return 0; +} + +/* + * Constants for setting receiver modes. + * (6 modes defined at this time, enumerated by mt2063_delivery_sys) + * (DNC1GC & DNC2GC are the values, which are used, when the specific + * DNC Output is selected, the other is always off) + * + * enum mt2063_delivery_sys + * -------------+---------------------------------------------- + * Mode 0 : | MT2063_CABLE_QAM + * Mode 1 : | MT2063_CABLE_ANALOG + * Mode 2 : | MT2063_OFFAIR_COFDM + * Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS + * Mode 4 : | MT2063_OFFAIR_ANALOG + * Mode 5 : | MT2063_OFFAIR_8VSB + * --------------+---------------------------------------------- + * + * |<---------- Mode -------------->| + * Reg Field | 0 | 1 | 2 | 3 | 4 | 5 | + * ------------+-----+-----+-----+-----+-----+-----+ + * RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF + * LNARin | 0 | 0 | 3 | 3 | 3 | 3 + * FIFFQen | 1 | 1 | 1 | 1 | 1 | 1 + * FIFFq | 0 | 0 | 0 | 0 | 0 | 0 + * DNC1gc | 0 | 0 | 0 | 0 | 0 | 0 + * DNC2gc | 0 | 0 | 0 | 0 | 0 | 0 + * GCU Auto | 1 | 1 | 1 | 1 | 1 | 1 + * LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31 + * LNA Target | 44 | 43 | 43 | 43 | 43 | 43 + * ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0 + * RF max Atn | 31 | 31 | 31 | 31 | 31 | 31 + * PD1 Target | 36 | 36 | 38 | 38 | 36 | 38 + * ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0 + * FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5 + * PD2 Target | 40 | 33 | 42 | 42 | 33 | 42 + */ + +enum mt2063_delivery_sys { + MT2063_CABLE_QAM = 0, + MT2063_CABLE_ANALOG, + MT2063_OFFAIR_COFDM, + MT2063_OFFAIR_COFDM_SAWLESS, + MT2063_OFFAIR_ANALOG, + MT2063_OFFAIR_8VSB, + MT2063_NUM_RCVR_MODES +}; + +static const char *mt2063_mode_name[] = { + [MT2063_CABLE_QAM] = "digital cable", + [MT2063_CABLE_ANALOG] = "analog cable", + [MT2063_OFFAIR_COFDM] = "digital offair", + [MT2063_OFFAIR_COFDM_SAWLESS] = "digital offair without SAW", + [MT2063_OFFAIR_ANALOG] = "analog offair", + [MT2063_OFFAIR_8VSB] = "analog offair 8vsb", +}; + +static const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 }; +static const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 }; +static const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 }; +static const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 }; +static const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 }; +static const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 }; +static const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 }; +static const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 }; + +/* + * mt2063_set_dnc_output_enable() + */ +static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state, + enum MT2063_DNC_Output_Enable *pValue) +{ + dprintk(2, "\n"); + + if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */ + if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */ + *pValue = MT2063_DNC_NONE; + else + *pValue = MT2063_DNC_2; + } else { /* DNC1 is on */ + if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */ + *pValue = MT2063_DNC_1; + else + *pValue = MT2063_DNC_BOTH; + } + return 0; +} + +/* + * mt2063_set_dnc_output_enable() + */ +static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state, + enum MT2063_DNC_Output_Enable nValue) +{ + u32 status = 0; /* Status to be returned */ + u8 val = 0; + + dprintk(2, "\n"); + + /* selects, which DNC output is used */ + switch (nValue) { + case MT2063_DNC_NONE: + val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */ + if (state->reg[MT2063_REG_DNC_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_DNC_GAIN, + val); + + val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */ + if (state->reg[MT2063_REG_VGA_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_VGA_GAIN, + val); + + val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */ + if (state->reg[MT2063_REG_RSVD_20] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_RSVD_20, + val); + + break; + case MT2063_DNC_1: + val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */ + if (state->reg[MT2063_REG_DNC_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_DNC_GAIN, + val); + + val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */ + if (state->reg[MT2063_REG_VGA_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_VGA_GAIN, + val); + + val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */ + if (state->reg[MT2063_REG_RSVD_20] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_RSVD_20, + val); + + break; + case MT2063_DNC_2: + val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */ + if (state->reg[MT2063_REG_DNC_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_DNC_GAIN, + val); + + val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */ + if (state->reg[MT2063_REG_VGA_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_VGA_GAIN, + val); + + val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */ + if (state->reg[MT2063_REG_RSVD_20] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_RSVD_20, + val); + + break; + case MT2063_DNC_BOTH: + val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */ + if (state->reg[MT2063_REG_DNC_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_DNC_GAIN, + val); + + val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */ + if (state->reg[MT2063_REG_VGA_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_VGA_GAIN, + val); + + val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */ + if (state->reg[MT2063_REG_RSVD_20] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_RSVD_20, + val); + + break; + default: + break; + } + + return status; +} + +/* + * MT2063_SetReceiverMode() - Set the MT2063 receiver mode, according with + * the selected enum mt2063_delivery_sys type. + * + * (DNC1GC & DNC2GC are the values, which are used, when the specific + * DNC Output is selected, the other is always off) + * + * @state: ptr to mt2063_state structure + * @Mode: desired reciever delivery system + * + * Note: Register cache must be valid for it to work + */ + +static u32 MT2063_SetReceiverMode(struct mt2063_state *state, + enum mt2063_delivery_sys Mode) +{ + u32 status = 0; /* Status to be returned */ + u8 val; + u32 longval; + + dprintk(2, "\n"); + + if (Mode >= MT2063_NUM_RCVR_MODES) + status = -ERANGE; + + /* RFAGCen */ + if (status >= 0) { + val = + (state-> + reg[MT2063_REG_PD1_TGT] & (u8) ~0x40) | (RFAGCEN[Mode] + ? 0x40 : + 0x00); + if (state->reg[MT2063_REG_PD1_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); + } + + /* LNARin */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_CTRL_2C] & (u8) ~0x03) | + (LNARIN[Mode] & 0x03); + if (state->reg[MT2063_REG_CTRL_2C] != val) + status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val); + } + + /* FIFFQEN and FIFFQ */ + if (status >= 0) { + val = + (state-> + reg[MT2063_REG_FIFF_CTRL2] & (u8) ~0xF0) | + (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4); + if (state->reg[MT2063_REG_FIFF_CTRL2] != val) { + status |= + mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val); + /* trigger FIFF calibration, needed after changing FIFFQ */ + val = + (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01); + status |= + mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); + val = + (state-> + reg[MT2063_REG_FIFF_CTRL] & (u8) ~0x01); + status |= + mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); + } + } + + /* DNC1GC & DNC2GC */ + status |= mt2063_get_dnc_output_enable(state, &longval); + status |= mt2063_set_dnc_output_enable(state, longval); + + /* acLNAmax */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_LNA_OV] & (u8) ~0x1F) | + (ACLNAMAX[Mode] & 0x1F); + if (state->reg[MT2063_REG_LNA_OV] != val) + status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val); + } + + /* LNATGT */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x3F) | + (LNATGT[Mode] & 0x3F); + if (state->reg[MT2063_REG_LNA_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); + } + + /* ACRF */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_RF_OV] & (u8) ~0x1F) | + (ACRFMAX[Mode] & 0x1F); + if (state->reg[MT2063_REG_RF_OV] != val) + status |= mt2063_setreg(state, MT2063_REG_RF_OV, val); + } + + /* PD1TGT */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x3F) | + (PD1TGT[Mode] & 0x3F); + if (state->reg[MT2063_REG_PD1_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); + } + + /* FIFATN */ + if (status >= 0) { + u8 val = ACFIFMAX[Mode]; + if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5) + val = 5; + val = (state->reg[MT2063_REG_FIF_OV] & (u8) ~0x1F) | + (val & 0x1F); + if (state->reg[MT2063_REG_FIF_OV] != val) + status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val); + } + + /* PD2TGT */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_PD2_TGT] & (u8) ~0x3F) | + (PD2TGT[Mode] & 0x3F); + if (state->reg[MT2063_REG_PD2_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val); + } + + /* Ignore ATN Overload */ + if (status >= 0) { + val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x80) | + (RFOVDIS[Mode] ? 0x80 : 0x00); + if (state->reg[MT2063_REG_LNA_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); + } + + /* Ignore FIF Overload */ + if (status >= 0) { + val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x80) | + (FIFOVDIS[Mode] ? 0x80 : 0x00); + if (state->reg[MT2063_REG_PD1_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); + } + + if (status >= 0) { + state->rcvr_mode = Mode; + dprintk(1, "mt2063 mode changed to %s\n", + mt2063_mode_name[state->rcvr_mode]); + } + + return status; +} + +/* + * MT2063_ClearPowerMaskBits () - Clears the power-down mask bits for various + * sections of the MT2063 + * + * @Bits: Mask bits to be cleared. + * + * See definition of MT2063_Mask_Bits type for description + * of each of the power bits. + */ +static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, + enum MT2063_Mask_Bits Bits) +{ + u32 status = 0; + + dprintk(2, "\n"); + Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */ + if ((Bits & 0xFF00) != 0) { + state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8); + status |= + mt2063_write(state, + MT2063_REG_PWR_2, + &state->reg[MT2063_REG_PWR_2], 1); + } + if ((Bits & 0xFF) != 0) { + state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF); + status |= + mt2063_write(state, + MT2063_REG_PWR_1, + &state->reg[MT2063_REG_PWR_1], 1); + } + + return status; +} + +/* + * MT2063_SoftwareShutdown() - Enables or disables software shutdown function. + * When Shutdown is 1, any section whose power + * mask is set will be shutdown. + */ +static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown) +{ + u32 status; + + dprintk(2, "\n"); + if (Shutdown == 1) + state->reg[MT2063_REG_PWR_1] |= 0x04; + else + state->reg[MT2063_REG_PWR_1] &= ~0x04; + + status = mt2063_write(state, + MT2063_REG_PWR_1, + &state->reg[MT2063_REG_PWR_1], 1); + + if (Shutdown != 1) { + state->reg[MT2063_REG_BYP_CTRL] = + (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40; + status |= + mt2063_write(state, + MT2063_REG_BYP_CTRL, + &state->reg[MT2063_REG_BYP_CTRL], + 1); + state->reg[MT2063_REG_BYP_CTRL] = + (state->reg[MT2063_REG_BYP_CTRL] & 0x9F); + status |= + mt2063_write(state, + MT2063_REG_BYP_CTRL, + &state->reg[MT2063_REG_BYP_CTRL], + 1); + } + + return status; +} + +static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref) +{ + return f_ref * (f_LO / f_ref) + + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step); +} + +/** + * fLO_FractionalTerm() - Calculates the portion contributed by FracN / denom. + * This function preserves maximum precision without + * risk of overflow. It accurately calculates + * f_ref * num / denom to within 1 HZ with fixed math. + * + * @num : Fractional portion of the multiplier + * @denom: denominator portion of the ratio + * @f_Ref: SRO frequency. + * + * This calculation handles f_ref as two separate 14-bit fields. + * Therefore, a maximum value of 2^28-1 may safely be used for f_ref. + * This is the genesis of the magic number "14" and the magic mask value of + * 0x03FFF. + * + * This routine successfully handles denom values up to and including 2^18. + * Returns: f_ref * num / denom + */ +static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom) +{ + u32 t1 = (f_ref >> 14) * num; + u32 term1 = t1 / denom; + u32 loss = t1 % denom; + u32 term2 = + (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom; + return (term1 << 14) + term2; +} + +/* + * CalcLO1Mult()- Calculates Integer divider value and the numerator + * value for a FracN PLL. + * + * This function assumes that the f_LO and f_Ref are + * evenly divisible by f_LO_Step. + * + * @Div: OUTPUT: Whole number portion of the multiplier + * @FracN: OUTPUT: Fractional portion of the multiplier + * @f_LO: desired LO frequency. + * @f_LO_Step: Minimum step size for the LO (in Hz). + * @f_Ref: SRO frequency. + * @f_Avoid: Range of PLL frequencies to avoid near integer multiples + * of f_Ref (in Hz). + * + * Returns: Recalculated LO frequency. + */ +static u32 MT2063_CalcLO1Mult(u32 *Div, + u32 *FracN, + u32 f_LO, + u32 f_LO_Step, u32 f_Ref) +{ + /* Calculate the whole number portion of the divider */ + *Div = f_LO / f_Ref; + + /* Calculate the numerator value (round to nearest f_LO_Step) */ + *FracN = + (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) + + (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step); + + return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64); +} + +/** + * CalcLO2Mult() - Calculates Integer divider value and the numerator + * value for a FracN PLL. + * + * This function assumes that the f_LO and f_Ref are + * evenly divisible by f_LO_Step. + * + * @Div: OUTPUT: Whole number portion of the multiplier + * @FracN: OUTPUT: Fractional portion of the multiplier + * @f_LO: desired LO frequency. + * @f_LO_Step: Minimum step size for the LO (in Hz). + * @f_Ref: SRO frequency. + * @f_Avoid: Range of PLL frequencies to avoid near + * integer multiples of f_Ref (in Hz). + * + * Returns: Recalculated LO frequency. + */ +static u32 MT2063_CalcLO2Mult(u32 *Div, + u32 *FracN, + u32 f_LO, + u32 f_LO_Step, u32 f_Ref) +{ + /* Calculate the whole number portion of the divider */ + *Div = f_LO / f_Ref; + + /* Calculate the numerator value (round to nearest f_LO_Step) */ + *FracN = + (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) + + (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step); + + return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, + 8191); +} + +/* + * FindClearTuneFilter() - Calculate the corrrect ClearTune filter to be + * used for a given input frequency. + * + * @state: ptr to tuner data structure + * @f_in: RF input center frequency (in Hz). + * + * Returns: ClearTune filter number (0-31) + */ +static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in) +{ + u32 RFBand; + u32 idx; /* index loop */ + + /* + ** Find RF Band setting + */ + RFBand = 31; /* def when f_in > all */ + for (idx = 0; idx < 31; ++idx) { + if (state->CTFiltMax[idx] >= f_in) { + RFBand = idx; + break; + } + } + return RFBand; +} + +/* + * MT2063_Tune() - Change the tuner's tuned frequency to RFin. + */ +static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in) +{ /* RF input center frequency */ + + u32 status = 0; + u32 LO1; /* 1st LO register value */ + u32 Num1; /* Numerator for LO1 reg. value */ + u32 f_IF1; /* 1st IF requested */ + u32 LO2; /* 2nd LO register value */ + u32 Num2; /* Numerator for LO2 reg. value */ + u32 ofLO1, ofLO2; /* last time's LO frequencies */ + u8 fiffc = 0x80; /* FIFF center freq from tuner */ + u32 fiffof; /* Offset from FIFF center freq */ + const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */ + u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */ + u8 val; + u32 RFBand; + + dprintk(2, "\n"); + /* Check the input and output frequency ranges */ + if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ)) + return -EINVAL; + + if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ) + || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ)) + return -EINVAL; + + /* + * Save original LO1 and LO2 register values + */ + ofLO1 = state->AS_Data.f_LO1; + ofLO2 = state->AS_Data.f_LO2; + + /* + * Find and set RF Band setting + */ + if (state->ctfilt_sw == 1) { + val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08); + if (state->reg[MT2063_REG_CTUNE_CTRL] != val) { + status |= + mt2063_setreg(state, MT2063_REG_CTUNE_CTRL, val); + } + val = state->reg[MT2063_REG_CTUNE_OV]; + RFBand = FindClearTuneFilter(state, f_in); + state->reg[MT2063_REG_CTUNE_OV] = + (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F) + | RFBand); + if (state->reg[MT2063_REG_CTUNE_OV] != val) { + status |= + mt2063_setreg(state, MT2063_REG_CTUNE_OV, val); + } + } + + /* + * Read the FIFF Center Frequency from the tuner + */ + if (status >= 0) { + status |= + mt2063_read(state, + MT2063_REG_FIFFC, + &state->reg[MT2063_REG_FIFFC], 1); + fiffc = state->reg[MT2063_REG_FIFFC]; + } + /* + * Assign in the requested values + */ + state->AS_Data.f_in = f_in; + /* Request a 1st IF such that LO1 is on a step size */ + state->AS_Data.f_if1_Request = + MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in, + state->AS_Data.f_LO1_Step, + state->AS_Data.f_ref) - f_in; + + /* + * Calculate frequency settings. f_IF1_FREQ + f_in is the + * desired LO1 frequency + */ + MT2063_ResetExclZones(&state->AS_Data); + + f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data); + + state->AS_Data.f_LO1 = + MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step, + state->AS_Data.f_ref); + + state->AS_Data.f_LO2 = + MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in, + state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); + + /* + * Check for any LO spurs in the output bandwidth and adjust + * the LO settings to avoid them if needed + */ + status |= MT2063_AvoidSpurs(&state->AS_Data); + /* + * MT_AvoidSpurs spurs may have changed the LO1 & LO2 values. + * Recalculate the LO frequencies and the values to be placed + * in the tuning registers. + */ + state->AS_Data.f_LO1 = + MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1, + state->AS_Data.f_LO1_Step, state->AS_Data.f_ref); + state->AS_Data.f_LO2 = + MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in, + state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); + state->AS_Data.f_LO2 = + MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2, + state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); + + /* + * Check the upconverter and downconverter frequency ranges + */ + if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ) + || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ)) + status |= MT2063_UPC_RANGE; + if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ) + || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ)) + status |= MT2063_DNC_RANGE; + /* LO2 Lock bit was in a different place for B0 version */ + if (state->tuner_id == MT2063_B0) + LO2LK = 0x40; + + /* + * If we have the same LO frequencies and we're already locked, + * then skip re-programming the LO registers. + */ + if ((ofLO1 != state->AS_Data.f_LO1) + || (ofLO2 != state->AS_Data.f_LO2) + || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) != + (LO1LK | LO2LK))) { + /* + * Calculate the FIFFOF register value + * + * IF1_Actual + * FIFFOF = ------------ - 8 * FIFFC - 4992 + * f_ref/64 + */ + fiffof = + (state->AS_Data.f_LO1 - + f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc - + 4992; + if (fiffof > 0xFF) + fiffof = 0xFF; + + /* + * Place all of the calculated values into the local tuner + * register fields. + */ + if (status >= 0) { + state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */ + state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */ + state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */ + |(Num2 >> 12)); /* NUM2q (hi) */ + state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */ + state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */ + + /* + * Now write out the computed register values + * IMPORTANT: There is a required order for writing + * (0x05 must follow all the others). + */ + status |= mt2063_write(state, MT2063_REG_LO1CQ_1, &state->reg[MT2063_REG_LO1CQ_1], 5); /* 0x01 - 0x05 */ + if (state->tuner_id == MT2063_B0) { + /* Re-write the one-shot bits to trigger the tune operation */ + status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */ + } + /* Write out the FIFF offset only if it's changing */ + if (state->reg[MT2063_REG_FIFF_OFFSET] != + (u8) fiffof) { + state->reg[MT2063_REG_FIFF_OFFSET] = + (u8) fiffof; + status |= + mt2063_write(state, + MT2063_REG_FIFF_OFFSET, + &state-> + reg[MT2063_REG_FIFF_OFFSET], + 1); + } + } + + /* + * Check for LO's locking + */ + + if (status < 0) + return status; + + status = mt2063_lockStatus(state); + if (status < 0) + return status; + if (!status) + return -EINVAL; /* Couldn't lock */ + + /* + * If we locked OK, assign calculated data to mt2063_state structure + */ + state->f_IF1_actual = state->AS_Data.f_LO1 - f_in; + } + + return status; +} + +static const u8 MT2063B0_defaults[] = { + /* Reg, Value */ + 0x19, 0x05, + 0x1B, 0x1D, + 0x1C, 0x1F, + 0x1D, 0x0F, + 0x1E, 0x3F, + 0x1F, 0x0F, + 0x20, 0x3F, + 0x22, 0x21, + 0x23, 0x3F, + 0x24, 0x20, + 0x25, 0x3F, + 0x27, 0xEE, + 0x2C, 0x27, /* bit at 0x20 is cleared below */ + 0x30, 0x03, + 0x2C, 0x07, /* bit at 0x20 is cleared here */ + 0x2D, 0x87, + 0x2E, 0xAA, + 0x28, 0xE1, /* Set the FIFCrst bit here */ + 0x28, 0xE0, /* Clear the FIFCrst bit here */ + 0x00 +}; + +/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ +static const u8 MT2063B1_defaults[] = { + /* Reg, Value */ + 0x05, 0xF0, + 0x11, 0x10, /* New Enable AFCsd */ + 0x19, 0x05, + 0x1A, 0x6C, + 0x1B, 0x24, + 0x1C, 0x28, + 0x1D, 0x8F, + 0x1E, 0x14, + 0x1F, 0x8F, + 0x20, 0x57, + 0x22, 0x21, /* New - ver 1.03 */ + 0x23, 0x3C, /* New - ver 1.10 */ + 0x24, 0x20, /* New - ver 1.03 */ + 0x2C, 0x24, /* bit at 0x20 is cleared below */ + 0x2D, 0x87, /* FIFFQ=0 */ + 0x2F, 0xF3, + 0x30, 0x0C, /* New - ver 1.11 */ + 0x31, 0x1B, /* New - ver 1.11 */ + 0x2C, 0x04, /* bit at 0x20 is cleared here */ + 0x28, 0xE1, /* Set the FIFCrst bit here */ + 0x28, 0xE0, /* Clear the FIFCrst bit here */ + 0x00 +}; + +/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ +static const u8 MT2063B3_defaults[] = { + /* Reg, Value */ + 0x05, 0xF0, + 0x19, 0x3D, + 0x2C, 0x24, /* bit at 0x20 is cleared below */ + 0x2C, 0x04, /* bit at 0x20 is cleared here */ + 0x28, 0xE1, /* Set the FIFCrst bit here */ + 0x28, 0xE0, /* Clear the FIFCrst bit here */ + 0x00 +}; + +static int mt2063_init(struct dvb_frontend *fe) +{ + u32 status; + struct mt2063_state *state = fe->tuner_priv; + u8 all_resets = 0xF0; /* reset/load bits */ + const u8 *def = NULL; + char *step; + u32 FCRUN; + s32 maxReads; + u32 fcu_osc; + u32 i; + + dprintk(2, "\n"); + + state->rcvr_mode = MT2063_CABLE_QAM; + + /* Read the Part/Rev code from the tuner */ + status = mt2063_read(state, MT2063_REG_PART_REV, + &state->reg[MT2063_REG_PART_REV], 1); + if (status < 0) { + printk(KERN_ERR "Can't read mt2063 part ID\n"); + return status; + } + + /* Check the part/rev code */ + switch (state->reg[MT2063_REG_PART_REV]) { + case MT2063_B0: + step = "B0"; + break; + case MT2063_B1: + step = "B1"; + break; + case MT2063_B2: + step = "B2"; + break; + case MT2063_B3: + step = "B3"; + break; + default: + printk(KERN_ERR "mt2063: Unknown mt2063 device ID (0x%02x)\n", + state->reg[MT2063_REG_PART_REV]); + return -ENODEV; /* Wrong tuner Part/Rev code */ + } + + /* Check the 2nd byte of the Part/Rev code from the tuner */ + status = mt2063_read(state, MT2063_REG_RSVD_3B, + &state->reg[MT2063_REG_RSVD_3B], 1); + + /* b7 != 0 ==> NOT MT2063 */ + if (status < 0 || ((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) { + printk(KERN_ERR "mt2063: Unknown part ID (0x%02x%02x)\n", + state->reg[MT2063_REG_PART_REV], + state->reg[MT2063_REG_RSVD_3B]); + return -ENODEV; /* Wrong tuner Part/Rev code */ + } + + printk(KERN_INFO "mt2063: detected a mt2063 %s\n", step); + + /* Reset the tuner */ + status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1); + if (status < 0) + return status; + + /* change all of the default values that vary from the HW reset values */ + /* def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */ + switch (state->reg[MT2063_REG_PART_REV]) { + case MT2063_B3: + def = MT2063B3_defaults; + break; + + case MT2063_B1: + def = MT2063B1_defaults; + break; + + case MT2063_B0: + def = MT2063B0_defaults; + break; + + default: + return -ENODEV; + break; + } + + while (status >= 0 && *def) { + u8 reg = *def++; + u8 val = *def++; + status = mt2063_write(state, reg, &val, 1); + } + if (status < 0) + return status; + + /* Wait for FIFF location to complete. */ + FCRUN = 1; + maxReads = 10; + while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) { + msleep(2); + status = mt2063_read(state, + MT2063_REG_XO_STATUS, + &state-> + reg[MT2063_REG_XO_STATUS], 1); + FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6; + } + + if (FCRUN != 0 || status < 0) + return -ENODEV; + + status = mt2063_read(state, + MT2063_REG_FIFFC, + &state->reg[MT2063_REG_FIFFC], 1); + if (status < 0) + return status; + + /* Read back all the registers from the tuner */ + status = mt2063_read(state, + MT2063_REG_PART_REV, + state->reg, MT2063_REG_END_REGS); + if (status < 0) + return status; + + /* Initialize the tuner state. */ + state->tuner_id = state->reg[MT2063_REG_PART_REV]; + state->AS_Data.f_ref = MT2063_REF_FREQ; + state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) * + ((u32) state->reg[MT2063_REG_FIFFC] + 640); + state->AS_Data.f_if1_bw = MT2063_IF1_BW; + state->AS_Data.f_out = 43750000UL; + state->AS_Data.f_out_bw = 6750000UL; + state->AS_Data.f_zif_bw = MT2063_ZIF_BW; + state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64; + state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE; + state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1; + state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2; + state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP; + state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center; + state->AS_Data.f_LO1 = 2181000000UL; + state->AS_Data.f_LO2 = 1486249786UL; + state->f_IF1_actual = state->AS_Data.f_if1_Center; + state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual; + state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID; + state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID; + state->num_regs = MT2063_REG_END_REGS; + state->AS_Data.avoidDECT = MT2063_AVOID_BOTH; + state->ctfilt_sw = 0; + + state->CTFiltMax[0] = 69230000; + state->CTFiltMax[1] = 105770000; + state->CTFiltMax[2] = 140350000; + state->CTFiltMax[3] = 177110000; + state->CTFiltMax[4] = 212860000; + state->CTFiltMax[5] = 241130000; + state->CTFiltMax[6] = 274370000; + state->CTFiltMax[7] = 309820000; + state->CTFiltMax[8] = 342450000; + state->CTFiltMax[9] = 378870000; + state->CTFiltMax[10] = 416210000; + state->CTFiltMax[11] = 456500000; + state->CTFiltMax[12] = 495790000; + state->CTFiltMax[13] = 534530000; + state->CTFiltMax[14] = 572610000; + state->CTFiltMax[15] = 598970000; + state->CTFiltMax[16] = 635910000; + state->CTFiltMax[17] = 672130000; + state->CTFiltMax[18] = 714840000; + state->CTFiltMax[19] = 739660000; + state->CTFiltMax[20] = 770410000; + state->CTFiltMax[21] = 814660000; + state->CTFiltMax[22] = 846950000; + state->CTFiltMax[23] = 867820000; + state->CTFiltMax[24] = 915980000; + state->CTFiltMax[25] = 947450000; + state->CTFiltMax[26] = 983110000; + state->CTFiltMax[27] = 1021630000; + state->CTFiltMax[28] = 1061870000; + state->CTFiltMax[29] = 1098330000; + state->CTFiltMax[30] = 1138990000; + + /* + ** Fetch the FCU osc value and use it and the fRef value to + ** scale all of the Band Max values + */ + + state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A; + status = mt2063_write(state, MT2063_REG_CTUNE_CTRL, + &state->reg[MT2063_REG_CTUNE_CTRL], 1); + if (status < 0) + return status; + + /* Read the ClearTune filter calibration value */ + status = mt2063_read(state, MT2063_REG_FIFFC, + &state->reg[MT2063_REG_FIFFC], 1); + if (status < 0) + return status; + + fcu_osc = state->reg[MT2063_REG_FIFFC]; + + state->reg[MT2063_REG_CTUNE_CTRL] = 0x00; + status = mt2063_write(state, MT2063_REG_CTUNE_CTRL, + &state->reg[MT2063_REG_CTUNE_CTRL], 1); + if (status < 0) + return status; + + /* Adjust each of the values in the ClearTune filter cross-over table */ + for (i = 0; i < 31; i++) + state->CTFiltMax[i] = (state->CTFiltMax[i] / 768) * (fcu_osc + 640); + + status = MT2063_SoftwareShutdown(state, 1); + if (status < 0) + return status; + status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD); + if (status < 0) + return status; + + state->init = true; + + return 0; +} + +static int mt2063_get_status(struct dvb_frontend *fe, u32 *tuner_status) +{ + struct mt2063_state *state = fe->tuner_priv; + int status; + + dprintk(2, "\n"); + + if (!state->init) + return -ENODEV; + + *tuner_status = 0; + status = mt2063_lockStatus(state); + if (status < 0) + return status; + if (status) + *tuner_status = TUNER_STATUS_LOCKED; + + dprintk(1, "Tuner status: %d", *tuner_status); + + return 0; +} + +static int mt2063_release(struct dvb_frontend *fe) +{ + struct mt2063_state *state = fe->tuner_priv; + + dprintk(2, "\n"); + + fe->tuner_priv = NULL; + kfree(state); + + return 0; +} + +static int mt2063_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct mt2063_state *state = fe->tuner_priv; + s32 pict_car; + s32 pict2chanb_vsb; + s32 ch_bw; + s32 if_mid; + s32 rcvr_mode; + int status; + + dprintk(2, "\n"); + + if (!state->init) { + status = mt2063_init(fe); + if (status < 0) + return status; + } + + switch (params->mode) { + case V4L2_TUNER_RADIO: + pict_car = 38900000; + ch_bw = 8000000; + pict2chanb_vsb = -(ch_bw / 2); + rcvr_mode = MT2063_OFFAIR_ANALOG; + break; + case V4L2_TUNER_ANALOG_TV: + rcvr_mode = MT2063_CABLE_ANALOG; + if (params->std & ~V4L2_STD_MN) { + pict_car = 38900000; + ch_bw = 6000000; + pict2chanb_vsb = -1250000; + } else if (params->std & V4L2_STD_PAL_G) { + pict_car = 38900000; + ch_bw = 7000000; + pict2chanb_vsb = -1250000; + } else { /* PAL/SECAM standards */ + pict_car = 38900000; + ch_bw = 8000000; + pict2chanb_vsb = -1250000; + } + break; + default: + return -EINVAL; + } + if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2)); + + state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */ + state->AS_Data.f_out = if_mid; + state->AS_Data.f_out_bw = ch_bw + 750000; + status = MT2063_SetReceiverMode(state, rcvr_mode); + if (status < 0) + return status; + + dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n", + params->frequency, ch_bw, pict2chanb_vsb); + + status = MT2063_Tune(state, (params->frequency + (pict2chanb_vsb + (ch_bw / 2)))); + if (status < 0) + return status; + + state->frequency = params->frequency; + return 0; +} + +/* + * As defined on EN 300 429, the DVB-C roll-off factor is 0.15. + * So, the amount of the needed bandwith is given by: + * Bw = Symbol_rate * (1 + 0.15) + * As such, the maximum symbol rate supported by 6 MHz is given by: + * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds + */ +#define MAX_SYMBOL_RATE_6MHz 5217391 + +static int mt2063_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct mt2063_state *state = fe->tuner_priv; + int status; + s32 pict_car; + s32 pict2chanb_vsb; + s32 ch_bw; + s32 if_mid; + s32 rcvr_mode; + + if (!state->init) { + status = mt2063_init(fe); + if (status < 0) + return status; + } + + dprintk(2, "\n"); + + if (c->bandwidth_hz == 0) + return -EINVAL; + if (c->bandwidth_hz <= 6000000) + ch_bw = 6000000; + else if (c->bandwidth_hz <= 7000000) + ch_bw = 7000000; + else + ch_bw = 8000000; + + switch (c->delivery_system) { + case SYS_DVBT: + rcvr_mode = MT2063_OFFAIR_COFDM; + pict_car = 36125000; + pict2chanb_vsb = -(ch_bw / 2); + break; + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + rcvr_mode = MT2063_CABLE_QAM; + pict_car = 36125000; + pict2chanb_vsb = -(ch_bw / 2); + break; + default: + return -EINVAL; + } + if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2)); + + state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */ + state->AS_Data.f_out = if_mid; + state->AS_Data.f_out_bw = ch_bw + 750000; + status = MT2063_SetReceiverMode(state, rcvr_mode); + if (status < 0) + return status; + + dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n", + c->frequency, ch_bw, pict2chanb_vsb); + + status = MT2063_Tune(state, (c->frequency + (pict2chanb_vsb + (ch_bw / 2)))); + + if (status < 0) + return status; + + state->frequency = c->frequency; + return 0; +} + +static int mt2063_get_if_frequency(struct dvb_frontend *fe, u32 *freq) +{ + struct mt2063_state *state = fe->tuner_priv; + + dprintk(2, "\n"); + + if (!state->init) + return -ENODEV; + + *freq = state->AS_Data.f_out; + + dprintk(1, "IF frequency: %d\n", *freq); + + return 0; +} + +static int mt2063_get_bandwidth(struct dvb_frontend *fe, u32 *bw) +{ + struct mt2063_state *state = fe->tuner_priv; + + dprintk(2, "\n"); + + if (!state->init) + return -ENODEV; + + *bw = state->AS_Data.f_out_bw - 750000; + + dprintk(1, "bandwidth: %d\n", *bw); + + return 0; +} + +static struct dvb_tuner_ops mt2063_ops = { + .info = { + .name = "MT2063 Silicon Tuner", + .frequency_min = 45000000, + .frequency_max = 865000000, + .frequency_step = 0, + }, + + .init = mt2063_init, + .sleep = MT2063_Sleep, + .get_status = mt2063_get_status, + .set_analog_params = mt2063_set_analog_params, + .set_params = mt2063_set_params, + .get_if_frequency = mt2063_get_if_frequency, + .get_bandwidth = mt2063_get_bandwidth, + .release = mt2063_release, +}; + +struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, + struct mt2063_config *config, + struct i2c_adapter *i2c) +{ + struct mt2063_state *state = NULL; + + dprintk(2, "\n"); + + state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL); + if (state == NULL) + goto error; + + state->config = config; + state->i2c = i2c; + state->frontend = fe; + state->reference = config->refclock / 1000; /* kHz */ + fe->tuner_priv = state; + fe->ops.tuner_ops = mt2063_ops; + + printk(KERN_INFO "%s: Attaching MT2063\n", __func__); + return fe; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL_GPL(mt2063_attach); + +/* + * Ancillary routines visible outside mt2063 + * FIXME: Remove them in favor of using standard tuner callbacks + */ +unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) +{ + struct mt2063_state *state = fe->tuner_priv; + int err = 0; + + dprintk(2, "\n"); + + err = MT2063_SoftwareShutdown(state, 1); + if (err < 0) + printk(KERN_ERR "%s: Couldn't shutdown\n", __func__); + + return err; +} +EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown); + +unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) +{ + struct mt2063_state *state = fe->tuner_priv; + int err = 0; + + dprintk(2, "\n"); + + err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD); + if (err < 0) + printk(KERN_ERR "%s: Invalid parameter\n", __func__); + + return err; +} +EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits); + +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_DESCRIPTION("MT2063 Silicon tuner"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/mt2063.h b/drivers/media/tuners/mt2063.h new file mode 100644 index 000000000000..3f5cfd93713f --- /dev/null +++ b/drivers/media/tuners/mt2063.h @@ -0,0 +1,32 @@ +#ifndef __MT2063_H__ +#define __MT2063_H__ + +#include "dvb_frontend.h" + +struct mt2063_config { + u8 tuner_address; + u32 refclock; +}; + +#if defined(CONFIG_MEDIA_TUNER_MT2063) || (defined(CONFIG_MEDIA_TUNER_MT2063_MODULE) && defined(MODULE)) +struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, + struct mt2063_config *config, + struct i2c_adapter *i2c); + +#else + +static inline struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, + struct mt2063_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); + return NULL; +} + +/* FIXME: Should use the standard DVB attachment interfaces */ +unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe); +unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe); + +#endif /* CONFIG_DVB_MT2063 */ + +#endif /* __MT2063_H__ */ diff --git a/drivers/media/tuners/mt20xx.c b/drivers/media/tuners/mt20xx.c new file mode 100644 index 000000000000..0e74e97e0d1a --- /dev/null +++ b/drivers/media/tuners/mt20xx.c @@ -0,0 +1,670 @@ +/* + * i2c tv tuner chip device driver + * controls microtune tuners, mt2032 + mt2050 at the moment. + * + * This "mt20xx" module was split apart from the original "tuner" module. + */ +#include +#include +#include +#include +#include "tuner-i2c.h" +#include "mt20xx.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +/* ---------------------------------------------------------------------- */ + +static unsigned int optimize_vco = 1; +module_param(optimize_vco, int, 0644); + +static unsigned int tv_antenna = 1; +module_param(tv_antenna, int, 0644); + +static unsigned int radio_antenna; +module_param(radio_antenna, int, 0644); + +/* ---------------------------------------------------------------------- */ + +#define MT2032 0x04 +#define MT2030 0x06 +#define MT2040 0x07 +#define MT2050 0x42 + +static char *microtune_part[] = { + [ MT2030 ] = "MT2030", + [ MT2032 ] = "MT2032", + [ MT2040 ] = "MT2040", + [ MT2050 ] = "MT2050", +}; + +struct microtune_priv { + struct tuner_i2c_props i2c_props; + + unsigned int xogc; + //unsigned int radio_if2; + + u32 frequency; +}; + +static int microtune_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; +} + +static int microtune_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct microtune_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +// IsSpurInBand()? +static int mt2032_spurcheck(struct dvb_frontend *fe, + int f1, int f2, int spectrum_from,int spectrum_to) +{ + struct microtune_priv *priv = fe->tuner_priv; + int n1=1,n2,f; + + f1=f1/1000; //scale to kHz to avoid 32bit overflows + f2=f2/1000; + spectrum_from/=1000; + spectrum_to/=1000; + + tuner_dbg("spurcheck f1=%d f2=%d from=%d to=%d\n", + f1,f2,spectrum_from,spectrum_to); + + do { + n2=-n1; + f=n1*(f1-f2); + do { + n2--; + f=f-f2; + tuner_dbg("spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f); + + if( (f>spectrum_from) && (f(f2-spectrum_to)) || (n2>-5)); + n1++; + } while (n1<5); + + return 1; +} + +static int mt2032_compute_freq(struct dvb_frontend *fe, + unsigned int rfin, + unsigned int if1, unsigned int if2, + unsigned int spectrum_from, + unsigned int spectrum_to, + unsigned char *buf, + int *ret_sel, + unsigned int xogc) //all in Hz +{ + struct microtune_priv *priv = fe->tuner_priv; + unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, + desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq; + + fref= 5250 *1000; //5.25MHz + desired_lo1=rfin+if1; + + lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000); + lo1n=lo1/8; + lo1a=lo1-(lo1n*8); + + s=rfin/1000/1000+1090; + + if(optimize_vco) { + if(s>1890) sel=0; + else if(s>1720) sel=1; + else if(s>1530) sel=2; + else if(s>1370) sel=3; + else sel=4; // >1090 + } + else { + if(s>1790) sel=0; // <1958 + else if(s>1617) sel=1; + else if(s>1449) sel=2; + else if(s>1291) sel=3; + else sel=4; // >1090 + } + *ret_sel=sel; + + lo1freq=(lo1a+8*lo1n)*fref; + + tuner_dbg("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n", + rfin,lo1,lo1n,lo1a,sel,lo1freq); + + desired_lo2=lo1freq-rfin-if2; + lo2=(desired_lo2)/fref; + lo2n=lo2/8; + lo2a=lo2-(lo2n*8); + lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith + lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000; + + tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n", + rfin,lo2,lo2n,lo2a,lo2num,lo2freq); + + if (lo1a > 7 || lo1n < 17 || lo1n > 48 || lo2a > 7 || lo2n < 17 || + lo2n > 30) { + tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n", + lo1a, lo1n, lo2a,lo2n); + return(-1); + } + + mt2032_spurcheck(fe, lo1freq, desired_lo2, spectrum_from, spectrum_to); + // should recalculate lo1 (one step up/down) + + // set up MT2032 register map for transfer over i2c + buf[0]=lo1n-1; + buf[1]=lo1a | (sel<<4); + buf[2]=0x86; // LOGC + buf[3]=0x0f; //reserved + buf[4]=0x1f; + buf[5]=(lo2n-1) | (lo2a<<5); + if(rfin >400*1000*1000) + buf[6]=0xe4; + else + buf[6]=0xf4; // set PKEN per rev 1.2 + buf[7]=8+xogc; + buf[8]=0xc3; //reserved + buf[9]=0x4e; //reserved + buf[10]=0xec; //reserved + buf[11]=(lo2num&0xff); + buf[12]=(lo2num>>8) |0x80; // Lo2RST + + return 0; +} + +static int mt2032_check_lo_lock(struct dvb_frontend *fe) +{ + struct microtune_priv *priv = fe->tuner_priv; + int try,lock=0; + unsigned char buf[2]; + + for(try=0;try<10;try++) { + buf[0]=0x0e; + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); + tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]); + lock=buf[0] &0x06; + + if (lock==6) + break; + + tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]); + udelay(1000); + } + return lock; +} + +static int mt2032_optimize_vco(struct dvb_frontend *fe,int sel,int lock) +{ + struct microtune_priv *priv = fe->tuner_priv; + unsigned char buf[2]; + int tad1; + + buf[0]=0x0f; + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); + tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]); + tad1=buf[0]&0x07; + + if(tad1 ==0) return lock; + if(tad1 ==1) return lock; + + if(tad1==2) { + if(sel==0) + return lock; + else sel--; + } + else { + if(sel<4) + sel++; + else + return lock; + } + + tuner_dbg("mt2032 optimize_vco: sel=%d\n",sel); + + buf[0]=0x0f; + buf[1]=sel; + tuner_i2c_xfer_send(&priv->i2c_props,buf,2); + lock=mt2032_check_lo_lock(fe); + return lock; +} + + +static void mt2032_set_if_freq(struct dvb_frontend *fe, unsigned int rfin, + unsigned int if1, unsigned int if2, + unsigned int from, unsigned int to) +{ + unsigned char buf[21]; + int lint_try,ret,sel,lock=0; + struct microtune_priv *priv = fe->tuner_priv; + + tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n", + rfin,if1,if2,from,to); + + buf[0]=0; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); + + buf[0]=0; + ret=mt2032_compute_freq(fe,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); + if (ret<0) + return; + + // send only the relevant registers per Rev. 1.2 + buf[0]=0; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,4); + buf[5]=5; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,4); + buf[11]=11; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+11,3); + if(ret!=3) + tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret); + + // wait for PLLs to lock (per manual), retry LINT if not. + for(lint_try=0; lint_try<2; lint_try++) { + lock=mt2032_check_lo_lock(fe); + + if(optimize_vco) + lock=mt2032_optimize_vco(fe,sel,lock); + if(lock==6) break; + + tuner_dbg("mt2032: re-init PLLs by LINT\n"); + buf[0]=7; + buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs + tuner_i2c_xfer_send(&priv->i2c_props,buf,2); + mdelay(10); + buf[1]=8+priv->xogc; + tuner_i2c_xfer_send(&priv->i2c_props,buf,2); + } + + if (lock!=6) + tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n"); + + buf[0]=2; + buf[1]=0x20; // LOGC for optimal phase noise + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); + if (ret!=2) + tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); +} + + +static int mt2032_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + int if2,from,to; + + // signal bandwidth and picture carrier + if (params->std & V4L2_STD_525_60) { + // NTSC + from = 40750*1000; + to = 46750*1000; + if2 = 45750*1000; + } else { + // PAL + from = 32900*1000; + to = 39900*1000; + if2 = 38900*1000; + } + + mt2032_set_if_freq(fe, params->frequency*62500, + 1090*1000*1000, if2, from, to); + + return 0; +} + +static int mt2032_set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct microtune_priv *priv = fe->tuner_priv; + int if2; + + if (params->std & V4L2_STD_525_60) { + tuner_dbg("pinnacle ntsc\n"); + if2 = 41300 * 1000; + } else { + tuner_dbg("pinnacle pal\n"); + if2 = 33300 * 1000; + } + + // per Manual for FM tuning: first if center freq. 1085 MHz + mt2032_set_if_freq(fe, params->frequency * 125 / 2, + 1085*1000*1000,if2,if2,if2); + + return 0; +} + +static int mt2032_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct microtune_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + switch (params->mode) { + case V4L2_TUNER_RADIO: + ret = mt2032_set_radio_freq(fe, params); + priv->frequency = params->frequency * 125 / 2; + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + ret = mt2032_set_tv_freq(fe, params); + priv->frequency = params->frequency * 62500; + break; + } + + return ret; +} + +static struct dvb_tuner_ops mt2032_tuner_ops = { + .set_analog_params = mt2032_set_params, + .release = microtune_release, + .get_frequency = microtune_get_frequency, +}; + +// Initialization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 +static int mt2032_init(struct dvb_frontend *fe) +{ + struct microtune_priv *priv = fe->tuner_priv; + unsigned char buf[21]; + int ret,xogc,xok=0; + + // Initialize Registers per spec. + buf[1]=2; // Index to register 2 + buf[2]=0xff; + buf[3]=0x0f; + buf[4]=0x1f; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+1,4); + + buf[5]=6; // Index register 6 + buf[6]=0xe4; + buf[7]=0x8f; + buf[8]=0xc3; + buf[9]=0x4e; + buf[10]=0xec; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,6); + + buf[12]=13; // Index register 13 + buf[13]=0x32; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+12,2); + + // Adjust XOGC (register 7), wait for XOK + xogc=7; + do { + tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); + mdelay(10); + buf[0]=0x0e; + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); + xok=buf[0]&0x01; + tuner_dbg("mt2032: xok = 0x%02x\n",xok); + if (xok == 1) break; + + xogc--; + tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); + if (xogc == 3) { + xogc=4; // min. 4 per spec + break; + } + buf[0]=0x07; + buf[1]=0x88 + xogc; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); + if (ret!=2) + tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); + } while (xok != 1 ); + priv->xogc=xogc; + + memcpy(&fe->ops.tuner_ops, &mt2032_tuner_ops, sizeof(struct dvb_tuner_ops)); + + return(1); +} + +static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna) +{ + struct microtune_priv *priv = fe->tuner_priv; + unsigned char buf[2]; + + buf[0] = 6; + buf[1] = antenna ? 0x11 : 0x10; + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); + tuner_dbg("mt2050: enabled antenna connector %d\n", antenna); +} + +static void mt2050_set_if_freq(struct dvb_frontend *fe,unsigned int freq, unsigned int if2) +{ + struct microtune_priv *priv = fe->tuner_priv; + unsigned int if1=1218*1000*1000; + unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; + int ret; + unsigned char buf[6]; + + tuner_dbg("mt2050_set_if_freq freq=%d if1=%d if2=%d\n", + freq,if1,if2); + + f_lo1=freq+if1; + f_lo1=(f_lo1/1000000)*1000000; + + f_lo2=f_lo1-freq-if2; + f_lo2=(f_lo2/50000)*50000; + + lo1=f_lo1/4000000; + lo2=f_lo2/4000000; + + f_lo1_modulo= f_lo1-(lo1*4000000); + f_lo2_modulo= f_lo2-(lo2*4000000); + + num1=4*f_lo1_modulo/4000000; + num2=4096*(f_lo2_modulo/1000)/4000; + + // todo spurchecks + + div1a=(lo1/12)-1; + div1b=lo1-(div1a+1)*12; + + div2a=(lo2/8)-1; + div2b=lo2-(div2a+1)*8; + + if (debug > 1) { + tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2); + tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n", + num1,num2,div1a,div1b,div2a,div2b); + } + + buf[0]=1; + buf[1]= 4*div1b + num1; + if(freq<275*1000*1000) buf[1] = buf[1]|0x80; + + buf[2]=div1a; + buf[3]=32*div2b + num2/256; + buf[4]=num2-(num2/256)*256; + buf[5]=div2a; + if(num2!=0) buf[5]=buf[5]|0x40; + + if (debug > 1) { + int i; + tuner_dbg("bufs is: "); + for(i=0;i<6;i++) + printk("%x ",buf[i]); + printk("\n"); + } + + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,6); + if (ret!=6) + tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret); +} + +static int mt2050_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + unsigned int if2; + + if (params->std & V4L2_STD_525_60) { + // NTSC + if2 = 45750*1000; + } else { + // PAL + if2 = 38900*1000; + } + if (V4L2_TUNER_DIGITAL_TV == params->mode) { + // DVB (pinnacle 300i) + if2 = 36150*1000; + } + mt2050_set_if_freq(fe, params->frequency*62500, if2); + mt2050_set_antenna(fe, tv_antenna); + + return 0; +} + +static int mt2050_set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct microtune_priv *priv = fe->tuner_priv; + int if2; + + if (params->std & V4L2_STD_525_60) { + tuner_dbg("pinnacle ntsc\n"); + if2 = 41300 * 1000; + } else { + tuner_dbg("pinnacle pal\n"); + if2 = 33300 * 1000; + } + + mt2050_set_if_freq(fe, params->frequency * 125 / 2, if2); + mt2050_set_antenna(fe, radio_antenna); + + return 0; +} + +static int mt2050_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct microtune_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + switch (params->mode) { + case V4L2_TUNER_RADIO: + ret = mt2050_set_radio_freq(fe, params); + priv->frequency = params->frequency * 125 / 2; + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + ret = mt2050_set_tv_freq(fe, params); + priv->frequency = params->frequency * 62500; + break; + } + + return ret; +} + +static struct dvb_tuner_ops mt2050_tuner_ops = { + .set_analog_params = mt2050_set_params, + .release = microtune_release, + .get_frequency = microtune_get_frequency, +}; + +static int mt2050_init(struct dvb_frontend *fe) +{ + struct microtune_priv *priv = fe->tuner_priv; + unsigned char buf[2]; + + buf[0] = 6; + buf[1] = 0x10; + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); /* power */ + + buf[0] = 0x0f; + buf[1] = 0x0f; + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); /* m1lo */ + + buf[0] = 0x0d; + tuner_i2c_xfer_send(&priv->i2c_props, buf, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, buf, 1); + + tuner_dbg("mt2050: sro is %x\n", buf[0]); + + memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops)); + + return 0; +} + +struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + struct microtune_priv *priv = NULL; + char *name; + unsigned char buf[21]; + int company_code; + + priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + fe->tuner_priv = priv; + + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + priv->i2c_props.name = "mt20xx"; + + //priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ + + memset(buf,0,sizeof(buf)); + + name = "unknown"; + + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); + if (debug) { + int i; + tuner_dbg("MT20xx hexdump:"); + for(i=0;i<21;i++) { + printk(" %02x",buf[i]); + if(((i+1)%8)==0) printk(" "); + } + printk("\n"); + } + company_code = buf[0x11] << 8 | buf[0x12]; + tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n", + company_code,buf[0x13],buf[0x14]); + + + if (buf[0x13] < ARRAY_SIZE(microtune_part) && + NULL != microtune_part[buf[0x13]]) + name = microtune_part[buf[0x13]]; + switch (buf[0x13]) { + case MT2032: + mt2032_init(fe); + break; + case MT2050: + mt2050_init(fe); + break; + default: + tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n", + name); + return NULL; + } + + strlcpy(fe->ops.tuner_ops.info.name, name, + sizeof(fe->ops.tuner_ops.info.name)); + tuner_info("microtune %s found, OK\n",name); + return fe; +} + +EXPORT_SYMBOL_GPL(microtune_attach); + +MODULE_DESCRIPTION("Microtune tuner driver"); +MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/tuners/mt20xx.h b/drivers/media/tuners/mt20xx.h new file mode 100644 index 000000000000..259553a24903 --- /dev/null +++ b/drivers/media/tuners/mt20xx.h @@ -0,0 +1,37 @@ +/* + 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 __MT20XX_H__ +#define __MT20XX_H__ + +#include +#include "dvb_frontend.h" + +#if defined(CONFIG_MEDIA_TUNER_MT20XX) || (defined(CONFIG_MEDIA_TUNER_MT20XX_MODULE) && defined(MODULE)) +extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr); +#else +static inline struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __MT20XX_H__ */ diff --git a/drivers/media/tuners/mt2131.c b/drivers/media/tuners/mt2131.c new file mode 100644 index 000000000000..f83b0c1ea6c8 --- /dev/null +++ b/drivers/media/tuners/mt2131.c @@ -0,0 +1,301 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth + * + * 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 +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "mt2131.h" +#include "mt2131_priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_INFO "%s: " fmt, "mt2131", ## arg) + +static u8 mt2131_config1[] = { + 0x01, + 0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88, + 0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32, + 0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80, + 0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00 +}; + +static u8 mt2131_config2[] = { + 0x10, + 0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04 +}; + +static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, .flags = 0, + .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, + .buf = val, .len = 1 }, + }; + + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "mt2131 I2C read failed\n"); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, + .buf = buf, .len = 2 }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mt2131 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) +{ + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, + .flags = 0, .buf = buf, .len = len }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n", + (int)len); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct mt2131_priv *priv; + int ret=0, i; + u32 freq; + u8 if_band_center; + u32 f_lo1, f_lo2; + u32 div1, num1, div2, num2; + u8 b[8]; + u8 lockval = 0; + + priv = fe->tuner_priv; + + freq = c->frequency / 1000; /* Hz -> kHz */ + dprintk(1, "%s() freq=%d\n", __func__, freq); + + f_lo1 = freq + MT2131_IF1 * 1000; + f_lo1 = (f_lo1 / 250) * 250; + f_lo2 = f_lo1 - freq - MT2131_IF2; + + priv->frequency = (f_lo1 - f_lo2 - MT2131_IF2) * 1000; + + /* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */ + num1 = f_lo1 * 64 / (MT2131_FREF / 128); + div1 = num1 / 8192; + num1 &= 0x1fff; + + /* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */ + num2 = f_lo2 * 64 / (MT2131_FREF / 128); + div2 = num2 / 8192; + num2 &= 0x1fff; + + if (freq <= 82500) if_band_center = 0x00; else + if (freq <= 137500) if_band_center = 0x01; else + if (freq <= 192500) if_band_center = 0x02; else + if (freq <= 247500) if_band_center = 0x03; else + if (freq <= 302500) if_band_center = 0x04; else + if (freq <= 357500) if_band_center = 0x05; else + if (freq <= 412500) if_band_center = 0x06; else + if (freq <= 467500) if_band_center = 0x07; else + if (freq <= 522500) if_band_center = 0x08; else + if (freq <= 577500) if_band_center = 0x09; else + if (freq <= 632500) if_band_center = 0x0A; else + if (freq <= 687500) if_band_center = 0x0B; else + if (freq <= 742500) if_band_center = 0x0C; else + if (freq <= 797500) if_band_center = 0x0D; else + if (freq <= 852500) if_band_center = 0x0E; else + if (freq <= 907500) if_band_center = 0x0F; else + if (freq <= 962500) if_band_center = 0x10; else + if (freq <= 1017500) if_band_center = 0x11; else + if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13; + + b[0] = 1; + b[1] = (num1 >> 5) & 0xFF; + b[2] = (num1 & 0x1F); + b[3] = div1; + b[4] = (num2 >> 5) & 0xFF; + b[5] = num2 & 0x1F; + b[6] = div2; + + dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2); + dprintk(1, "PLL freq=%dkHz band=%d\n", (int)freq, (int)if_band_center); + dprintk(1, "PLL f_lo1=%dkHz f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2); + dprintk(1, "PLL div1=%d num1=%d div2=%d num2=%d\n", + (int)div1, (int)num1, (int)div2, (int)num2); + dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n", + (int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5], + (int)b[6]); + + ret = mt2131_writeregs(priv,b,7); + if (ret < 0) + return ret; + + mt2131_writereg(priv, 0x0b, if_band_center); + + /* Wait for lock */ + i = 0; + do { + mt2131_readreg(priv, 0x08, &lockval); + if ((lockval & 0x88) == 0x88) + break; + msleep(4); + i++; + } while (i < 10); + + return ret; +} + +static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mt2131_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + *frequency = priv->frequency; + return 0; +} + +static int mt2131_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct mt2131_priv *priv = fe->tuner_priv; + u8 lock_status = 0; + u8 afc_status = 0; + + *status = 0; + + mt2131_readreg(priv, 0x08, &lock_status); + if ((lock_status & 0x88) == 0x88) + *status = TUNER_STATUS_LOCKED; + + mt2131_readreg(priv, 0x09, &afc_status); + dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n", + __func__, lock_status, afc_status); + + return 0; +} + +static int mt2131_init(struct dvb_frontend *fe) +{ + struct mt2131_priv *priv = fe->tuner_priv; + int ret; + dprintk(1, "%s()\n", __func__); + + if ((ret = mt2131_writeregs(priv, mt2131_config1, + sizeof(mt2131_config1))) < 0) + return ret; + + mt2131_writereg(priv, 0x0b, 0x09); + mt2131_writereg(priv, 0x15, 0x47); + mt2131_writereg(priv, 0x07, 0xf2); + mt2131_writereg(priv, 0x0b, 0x01); + + if ((ret = mt2131_writeregs(priv, mt2131_config2, + sizeof(mt2131_config2))) < 0) + return ret; + + return ret; +} + +static int mt2131_release(struct dvb_frontend *fe) +{ + dprintk(1, "%s()\n", __func__); + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops mt2131_tuner_ops = { + .info = { + .name = "Microtune MT2131", + .frequency_min = 48000000, + .frequency_max = 860000000, + .frequency_step = 50000, + }, + + .release = mt2131_release, + .init = mt2131_init, + + .set_params = mt2131_set_params, + .get_frequency = mt2131_get_frequency, + .get_status = mt2131_get_status +}; + +struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, u16 if1) +{ + struct mt2131_priv *priv = NULL; + u8 id = 0; + + dprintk(1, "%s()\n", __func__); + + priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + + if (mt2131_readreg(priv, 0, &id) != 0) { + kfree(priv); + return NULL; + } + if ( (id != 0x3E) && (id != 0x3F) ) { + printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n", + cfg->i2c_address); + kfree(priv); + return NULL; + } + + printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n", + cfg->i2c_address); + memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + return fe; +} +EXPORT_SYMBOL(mt2131_attach); + +MODULE_AUTHOR("Steven Toth"); +MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver"); +MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/tuners/mt2131.h b/drivers/media/tuners/mt2131.h new file mode 100644 index 000000000000..6632de640df0 --- /dev/null +++ b/drivers/media/tuners/mt2131.h @@ -0,0 +1,54 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth + * + * 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 __MT2131_H__ +#define __MT2131_H__ + +struct dvb_frontend; +struct i2c_adapter; + +struct mt2131_config { + u8 i2c_address; + u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ +}; + +#if defined(CONFIG_MEDIA_TUNER_MT2131) || (defined(CONFIG_MEDIA_TUNER_MT2131_MODULE) && defined(MODULE)) +extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, + u16 if1); +#else +static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, + u16 if1) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_MEDIA_TUNER_MT2131 */ + +#endif /* __MT2131_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/tuners/mt2131_priv.h b/drivers/media/tuners/mt2131_priv.h new file mode 100644 index 000000000000..62aeedf5c550 --- /dev/null +++ b/drivers/media/tuners/mt2131_priv.h @@ -0,0 +1,48 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth + * + * 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 __MT2131_PRIV_H__ +#define __MT2131_PRIV_H__ + +/* Regs */ +#define MT2131_PWR 0x07 +#define MT2131_UPC_1 0x0b +#define MT2131_AGC_RL 0x10 +#define MT2131_MISC_2 0x15 + +/* frequency values in KHz */ +#define MT2131_IF1 1220 +#define MT2131_IF2 44000 +#define MT2131_FREF 16000 + +struct mt2131_priv { + struct mt2131_config *cfg; + struct i2c_adapter *i2c; + + u32 frequency; +}; + +#endif /* __MT2131_PRIV_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/tuners/mt2266.c b/drivers/media/tuners/mt2266.c new file mode 100644 index 000000000000..bca4d75e42d4 --- /dev/null +++ b/drivers/media/tuners/mt2266.c @@ -0,0 +1,353 @@ +/* + * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" + * + * Copyright (c) 2007 Olivier DANET + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "mt2266.h" + +#define I2C_ADDRESS 0x60 + +#define REG_PART_REV 0 +#define REG_TUNE 1 +#define REG_BAND 6 +#define REG_BANDWIDTH 8 +#define REG_LOCK 0x12 + +#define PART_REV 0x85 + +struct mt2266_priv { + struct mt2266_config *cfg; + struct i2c_adapter *i2c; + + u32 frequency; + u32 bandwidth; + u8 band; +}; + +#define MT2266_VHF 1 +#define MT2266_UHF 0 + +/* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0) + +// Reads a single register +static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "MT2266 I2C read failed\n"); + return -EREMOTEIO; + } + return 0; +} + +// Writes a single register +static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 + }; + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "MT2266 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +// Writes a set of consecutive registers +static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len) +{ + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len + }; + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len); + return -EREMOTEIO; + } + return 0; +} + +// Initialisation sequences +static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28, + 0x00, 0x52, 0x99, 0x3f }; + +static u8 mt2266_init2[] = { + 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4, + 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, + 0xff, 0x00, 0x77, 0x0f, 0x2d +}; + +static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22 }; + +static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32 }; + +static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7 }; + +static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64, + 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 }; + +static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5, + 0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f }; + +#define FREF 30000 // Quartz oscillator 30 MHz + +static int mt2266_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct mt2266_priv *priv; + int ret=0; + u32 freq; + u32 tune; + u8 lnaband; + u8 b[10]; + int i; + u8 band; + + priv = fe->tuner_priv; + + freq = priv->frequency / 1000; /* Hz -> kHz */ + if (freq < 470000 && freq > 230000) + return -EINVAL; /* Gap between VHF and UHF bands */ + + priv->frequency = c->frequency; + tune = 2 * freq * (8192/16) / (FREF/16); + band = (freq < 300000) ? MT2266_VHF : MT2266_UHF; + if (band == MT2266_VHF) + tune *= 2; + + switch (c->bandwidth_hz) { + case 6000000: + mt2266_writeregs(priv, mt2266_init_6mhz, + sizeof(mt2266_init_6mhz)); + break; + case 8000000: + mt2266_writeregs(priv, mt2266_init_8mhz, + sizeof(mt2266_init_8mhz)); + break; + case 7000000: + default: + mt2266_writeregs(priv, mt2266_init_7mhz, + sizeof(mt2266_init_7mhz)); + break; + } + priv->bandwidth = c->bandwidth_hz; + + if (band == MT2266_VHF && priv->band == MT2266_UHF) { + dprintk("Switch from UHF to VHF"); + mt2266_writereg(priv, 0x05, 0x04); + mt2266_writereg(priv, 0x19, 0x61); + mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf)); + } else if (band == MT2266_UHF && priv->band == MT2266_VHF) { + dprintk("Switch from VHF to UHF"); + mt2266_writereg(priv, 0x05, 0x52); + mt2266_writereg(priv, 0x19, 0x61); + mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf)); + } + msleep(10); + + if (freq <= 495000) + lnaband = 0xEE; + else if (freq <= 525000) + lnaband = 0xDD; + else if (freq <= 550000) + lnaband = 0xCC; + else if (freq <= 580000) + lnaband = 0xBB; + else if (freq <= 605000) + lnaband = 0xAA; + else if (freq <= 630000) + lnaband = 0x99; + else if (freq <= 655000) + lnaband = 0x88; + else if (freq <= 685000) + lnaband = 0x77; + else if (freq <= 710000) + lnaband = 0x66; + else if (freq <= 735000) + lnaband = 0x55; + else if (freq <= 765000) + lnaband = 0x44; + else if (freq <= 802000) + lnaband = 0x33; + else if (freq <= 840000) + lnaband = 0x22; + else + lnaband = 0x11; + + b[0] = REG_TUNE; + b[1] = (tune >> 8) & 0x1F; + b[2] = tune & 0xFF; + b[3] = tune >> 13; + mt2266_writeregs(priv,b,4); + + dprintk("set_parms: tune=%d band=%d %s", + (int) tune, (int) lnaband, + (band == MT2266_UHF) ? "UHF" : "VHF"); + dprintk("set_parms: [1..3]: %2x %2x %2x", + (int) b[1], (int) b[2], (int)b[3]); + + if (band == MT2266_UHF) { + b[0] = 0x05; + b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62; + b[2] = lnaband; + mt2266_writeregs(priv, b, 3); + } + + /* Wait for pll lock or timeout */ + i = 0; + do { + mt2266_readreg(priv,REG_LOCK,b); + if (b[0] & 0x40) + break; + msleep(10); + i++; + } while (i<10); + dprintk("Lock when i=%i",(int)i); + + if (band == MT2266_UHF && priv->band == MT2266_VHF) + mt2266_writereg(priv, 0x05, 0x62); + + priv->band = band; + + return ret; +} + +static void mt2266_calibrate(struct mt2266_priv *priv) +{ + mt2266_writereg(priv, 0x11, 0x03); + mt2266_writereg(priv, 0x11, 0x01); + mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1)); + mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2)); + mt2266_writereg(priv, 0x33, 0x5e); + mt2266_writereg(priv, 0x10, 0x10); + mt2266_writereg(priv, 0x10, 0x00); + mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz)); + msleep(25); + mt2266_writereg(priv, 0x17, 0x6d); + mt2266_writereg(priv, 0x1c, 0x00); + msleep(75); + mt2266_writereg(priv, 0x17, 0x6d); + mt2266_writereg(priv, 0x1c, 0xff); +} + +static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mt2266_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mt2266_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static int mt2266_init(struct dvb_frontend *fe) +{ + int ret; + struct mt2266_priv *priv = fe->tuner_priv; + ret = mt2266_writereg(priv, 0x17, 0x6d); + if (ret < 0) + return ret; + ret = mt2266_writereg(priv, 0x1c, 0xff); + if (ret < 0) + return ret; + return 0; +} + +static int mt2266_sleep(struct dvb_frontend *fe) +{ + struct mt2266_priv *priv = fe->tuner_priv; + mt2266_writereg(priv, 0x17, 0x6d); + mt2266_writereg(priv, 0x1c, 0x00); + return 0; +} + +static int mt2266_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops mt2266_tuner_ops = { + .info = { + .name = "Microtune MT2266", + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_step = 50000, + }, + .release = mt2266_release, + .init = mt2266_init, + .sleep = mt2266_sleep, + .set_params = mt2266_set_params, + .get_frequency = mt2266_get_frequency, + .get_bandwidth = mt2266_get_bandwidth +}; + +struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) +{ + struct mt2266_priv *priv = NULL; + u8 id = 0; + + priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + priv->band = MT2266_UHF; + + if (mt2266_readreg(priv, 0, &id)) { + kfree(priv); + return NULL; + } + if (id != PART_REV) { + kfree(priv); + return NULL; + } + printk(KERN_INFO "MT2266: successfully identified\n"); + memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + mt2266_calibrate(priv); + return fe; +} +EXPORT_SYMBOL(mt2266_attach); + +MODULE_AUTHOR("Olivier DANET"); +MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/mt2266.h b/drivers/media/tuners/mt2266.h new file mode 100644 index 000000000000..4d083882d044 --- /dev/null +++ b/drivers/media/tuners/mt2266.h @@ -0,0 +1,37 @@ +/* + * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" + * + * Copyright (c) 2007 Olivier DANET + * + * 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. + */ + +#ifndef MT2266_H +#define MT2266_H + +struct dvb_frontend; +struct i2c_adapter; + +struct mt2266_config { + u8 i2c_address; +}; + +#if defined(CONFIG_MEDIA_TUNER_MT2266) || (defined(CONFIG_MEDIA_TUNER_MT2266_MODULE) && defined(MODULE)) +extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg); +#else +static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_MEDIA_TUNER_MT2266 + +#endif diff --git a/drivers/media/tuners/mxl5005s.c b/drivers/media/tuners/mxl5005s.c new file mode 100644 index 000000000000..6133315fb0e3 --- /dev/null +++ b/drivers/media/tuners/mxl5005s.c @@ -0,0 +1,4109 @@ +/* + MaxLinear MXL5005S VSB/QAM/DVBT tuner driver + + Copyright (C) 2008 MaxLinear + Copyright (C) 2006 Steven Toth + Functions: + mxl5005s_reset() + mxl5005s_writereg() + mxl5005s_writeregs() + mxl5005s_init() + mxl5005s_reconfigure() + mxl5005s_AssignTunerMode() + mxl5005s_set_params() + mxl5005s_get_frequency() + mxl5005s_get_bandwidth() + mxl5005s_release() + mxl5005s_attach() + + Copyright (C) 2008 Realtek + Copyright (C) 2008 Jan Hoogenraad + Functions: + mxl5005s_SetRfFreqHz() + + 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. + +*/ + +/* + History of this driver (Steven Toth): + I was given a public release of a linux driver that included + support for the MaxLinear MXL5005S silicon tuner. Analysis of + the tuner driver showed clearly three things. + + 1. The tuner driver didn't support the LinuxTV tuner API + so the code Realtek added had to be removed. + + 2. A significant amount of the driver is reference driver code + from MaxLinear, I felt it was important to identify and + preserve this. + + 3. New code has to be added to interface correctly with the + LinuxTV API, as a regular kernel module. + + Other than the reference driver enum's, I've clearly marked + sections of the code and retained the copyright of the + respective owners. +*/ +#include +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "mxl5005s.h" + +static int debug; + +#define dprintk(level, arg...) do { \ + if (level <= debug) \ + printk(arg); \ + } while (0) + +#define TUNER_REGS_NUM 104 +#define INITCTRL_NUM 40 + +#ifdef _MXL_PRODUCTION +#define CHCTRL_NUM 39 +#else +#define CHCTRL_NUM 36 +#endif + +#define MXLCTRL_NUM 189 +#define MASTER_CONTROL_ADDR 9 + +/* Enumeration of Master Control Register State */ +enum master_control_state { + MC_LOAD_START = 1, + MC_POWER_DOWN, + MC_SYNTH_RESET, + MC_SEQ_OFF +}; + +/* Enumeration of MXL5005 Tuner Modulation Type */ +enum { + MXL_DEFAULT_MODULATION = 0, + MXL_DVBT, + MXL_ATSC, + MXL_QAM, + MXL_ANALOG_CABLE, + MXL_ANALOG_OTA +}; + +/* MXL5005 Tuner Register Struct */ +struct TunerReg { + u16 Reg_Num; /* Tuner Register Address */ + u16 Reg_Val; /* Current sw programmed value waiting to be written */ +}; + +enum { + /* Initialization Control Names */ + DN_IQTN_AMP_CUT = 1, /* 1 */ + BB_MODE, /* 2 */ + BB_BUF, /* 3 */ + BB_BUF_OA, /* 4 */ + BB_ALPF_BANDSELECT, /* 5 */ + BB_IQSWAP, /* 6 */ + BB_DLPF_BANDSEL, /* 7 */ + RFSYN_CHP_GAIN, /* 8 */ + RFSYN_EN_CHP_HIGAIN, /* 9 */ + AGC_IF, /* 10 */ + AGC_RF, /* 11 */ + IF_DIVVAL, /* 12 */ + IF_VCO_BIAS, /* 13 */ + CHCAL_INT_MOD_IF, /* 14 */ + CHCAL_FRAC_MOD_IF, /* 15 */ + DRV_RES_SEL, /* 16 */ + I_DRIVER, /* 17 */ + EN_AAF, /* 18 */ + EN_3P, /* 19 */ + EN_AUX_3P, /* 20 */ + SEL_AAF_BAND, /* 21 */ + SEQ_ENCLK16_CLK_OUT, /* 22 */ + SEQ_SEL4_16B, /* 23 */ + XTAL_CAPSELECT, /* 24 */ + IF_SEL_DBL, /* 25 */ + RFSYN_R_DIV, /* 26 */ + SEQ_EXTSYNTHCALIF, /* 27 */ + SEQ_EXTDCCAL, /* 28 */ + AGC_EN_RSSI, /* 29 */ + RFA_ENCLKRFAGC, /* 30 */ + RFA_RSSI_REFH, /* 31 */ + RFA_RSSI_REF, /* 32 */ + RFA_RSSI_REFL, /* 33 */ + RFA_FLR, /* 34 */ + RFA_CEIL, /* 35 */ + SEQ_EXTIQFSMPULSE, /* 36 */ + OVERRIDE_1, /* 37 */ + BB_INITSTATE_DLPF_TUNE, /* 38 */ + TG_R_DIV, /* 39 */ + EN_CHP_LIN_B, /* 40 */ + + /* Channel Change Control Names */ + DN_POLY = 51, /* 51 */ + DN_RFGAIN, /* 52 */ + DN_CAP_RFLPF, /* 53 */ + DN_EN_VHFUHFBAR, /* 54 */ + DN_GAIN_ADJUST, /* 55 */ + DN_IQTNBUF_AMP, /* 56 */ + DN_IQTNGNBFBIAS_BST, /* 57 */ + RFSYN_EN_OUTMUX, /* 58 */ + RFSYN_SEL_VCO_OUT, /* 59 */ + RFSYN_SEL_VCO_HI, /* 60 */ + RFSYN_SEL_DIVM, /* 61 */ + RFSYN_RF_DIV_BIAS, /* 62 */ + DN_SEL_FREQ, /* 63 */ + RFSYN_VCO_BIAS, /* 64 */ + CHCAL_INT_MOD_RF, /* 65 */ + CHCAL_FRAC_MOD_RF, /* 66 */ + RFSYN_LPF_R, /* 67 */ + CHCAL_EN_INT_RF, /* 68 */ + TG_LO_DIVVAL, /* 69 */ + TG_LO_SELVAL, /* 70 */ + TG_DIV_VAL, /* 71 */ + TG_VCO_BIAS, /* 72 */ + SEQ_EXTPOWERUP, /* 73 */ + OVERRIDE_2, /* 74 */ + OVERRIDE_3, /* 75 */ + OVERRIDE_4, /* 76 */ + SEQ_FSM_PULSE, /* 77 */ + GPIO_4B, /* 78 */ + GPIO_3B, /* 79 */ + GPIO_4, /* 80 */ + GPIO_3, /* 81 */ + GPIO_1B, /* 82 */ + DAC_A_ENABLE, /* 83 */ + DAC_B_ENABLE, /* 84 */ + DAC_DIN_A, /* 85 */ + DAC_DIN_B, /* 86 */ +#ifdef _MXL_PRODUCTION + RFSYN_EN_DIV, /* 87 */ + RFSYN_DIVM, /* 88 */ + DN_BYPASS_AGC_I2C /* 89 */ +#endif +}; + +/* + * The following context is source code provided by MaxLinear. + * MaxLinear source code - Common_MXL.h (?) + */ + +/* Constants */ +#define MXL5005S_REG_WRITING_TABLE_LEN_MAX 104 +#define MXL5005S_LATCH_BYTE 0xfe + +/* Register address, MSB, and LSB */ +#define MXL5005S_BB_IQSWAP_ADDR 59 +#define MXL5005S_BB_IQSWAP_MSB 0 +#define MXL5005S_BB_IQSWAP_LSB 0 + +#define MXL5005S_BB_DLPF_BANDSEL_ADDR 53 +#define MXL5005S_BB_DLPF_BANDSEL_MSB 4 +#define MXL5005S_BB_DLPF_BANDSEL_LSB 3 + +/* Standard modes */ +enum { + MXL5005S_STANDARD_DVBT, + MXL5005S_STANDARD_ATSC, +}; +#define MXL5005S_STANDARD_MODE_NUM 2 + +/* Bandwidth modes */ +enum { + MXL5005S_BANDWIDTH_6MHZ = 6000000, + MXL5005S_BANDWIDTH_7MHZ = 7000000, + MXL5005S_BANDWIDTH_8MHZ = 8000000, +}; +#define MXL5005S_BANDWIDTH_MODE_NUM 3 + +/* MXL5005 Tuner Control Struct */ +struct TunerControl { + u16 Ctrl_Num; /* Control Number */ + u16 size; /* Number of bits to represent Value */ + u16 addr[25]; /* Array of Tuner Register Address for each bit pos */ + u16 bit[25]; /* Array of bit pos in Reg Addr for each bit pos */ + u16 val[25]; /* Binary representation of Value */ +}; + +/* MXL5005 Tuner Struct */ +struct mxl5005s_state { + u8 Mode; /* 0: Analog Mode ; 1: Digital Mode */ + u8 IF_Mode; /* for Analog Mode, 0: zero IF; 1: low IF */ + u32 Chan_Bandwidth; /* filter channel bandwidth (6, 7, 8) */ + u32 IF_OUT; /* Desired IF Out Frequency */ + u16 IF_OUT_LOAD; /* IF Out Load Resistor (200/300 Ohms) */ + u32 RF_IN; /* RF Input Frequency */ + u32 Fxtal; /* XTAL Frequency */ + u8 AGC_Mode; /* AGC Mode 0: Dual AGC; 1: Single AGC */ + u16 TOP; /* Value: take over point */ + u8 CLOCK_OUT; /* 0: turn off clk out; 1: turn on clock out */ + u8 DIV_OUT; /* 4MHz or 16MHz */ + u8 CAPSELECT; /* 0: disable On-Chip pulling cap; 1: enable */ + u8 EN_RSSI; /* 0: disable RSSI; 1: enable RSSI */ + + /* Modulation Type; */ + /* 0 - Default; 1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */ + u8 Mod_Type; + + /* Tracking Filter Type */ + /* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */ + u8 TF_Type; + + /* Calculated Settings */ + u32 RF_LO; /* Synth RF LO Frequency */ + u32 IF_LO; /* Synth IF LO Frequency */ + u32 TG_LO; /* Synth TG_LO Frequency */ + + /* Pointers to ControlName Arrays */ + u16 Init_Ctrl_Num; /* Number of INIT Control Names */ + struct TunerControl + Init_Ctrl[INITCTRL_NUM]; /* INIT Control Names Array Pointer */ + + u16 CH_Ctrl_Num; /* Number of CH Control Names */ + struct TunerControl + CH_Ctrl[CHCTRL_NUM]; /* CH Control Name Array Pointer */ + + u16 MXL_Ctrl_Num; /* Number of MXL Control Names */ + struct TunerControl + MXL_Ctrl[MXLCTRL_NUM]; /* MXL Control Name Array Pointer */ + + /* Pointer to Tuner Register Array */ + u16 TunerRegs_Num; /* Number of Tuner Registers */ + struct TunerReg + TunerRegs[TUNER_REGS_NUM]; /* Tuner Register Array Pointer */ + + /* Linux driver framework specific */ + struct mxl5005s_config *config; + struct dvb_frontend *frontend; + struct i2c_adapter *i2c; + + /* Cache values */ + u32 current_mode; + +}; + +static u16 MXL_GetMasterControl(u8 *MasterReg, int state); +static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value); +static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value); +static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit, + u8 bitVal); +static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, + u8 *RegVal, int *count); +static u32 MXL_Ceiling(u32 value, u32 resolution); +static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal); +static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, + u32 value, u16 controlGroup); +static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val); +static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum, + u8 *RegVal, int *count); +static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq); +static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe); +static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe); +static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum, + u8 *RegVal, int *count); +static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable, + u8 *datatable, u8 len); +static u16 MXL_IFSynthInit(struct dvb_frontend *fe); +static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type, + u32 bandwidth); +static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type, + u32 bandwidth); + +/* ---------------------------------------------------------------- + * Begin: Custom code salvaged from the Realtek driver. + * Copyright (C) 2008 Realtek + * Copyright (C) 2008 Jan Hoogenraad + * This code is placed under the terms of the GNU General Public License + * + * Released by Realtek under GPLv2. + * Thanks to Realtek for a lot of support we received ! + * + * Revision: 080314 - original version + */ + +static int mxl5005s_SetRfFreqHz(struct dvb_frontend *fe, unsigned long RfFreqHz) +{ + struct mxl5005s_state *state = fe->tuner_priv; + unsigned char AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; + unsigned char ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; + int TableLen; + + u32 IfDivval = 0; + unsigned char MasterControlByte; + + dprintk(1, "%s() freq=%ld\n", __func__, RfFreqHz); + + /* Set MxL5005S tuner RF frequency according to example code. */ + + /* Tuner RF frequency setting stage 0 */ + MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET); + AddrTable[0] = MASTER_CONTROL_ADDR; + ByteTable[0] |= state->config->AgcMasterByte; + + mxl5005s_writeregs(fe, AddrTable, ByteTable, 1); + + /* Tuner RF frequency setting stage 1 */ + MXL_TuneRF(fe, RfFreqHz); + + MXL_ControlRead(fe, IF_DIVVAL, &IfDivval); + + MXL_ControlWrite(fe, SEQ_FSM_PULSE, 0); + MXL_ControlWrite(fe, SEQ_EXTPOWERUP, 1); + MXL_ControlWrite(fe, IF_DIVVAL, 8); + MXL_GetCHRegister(fe, AddrTable, ByteTable, &TableLen); + + MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START); + AddrTable[TableLen] = MASTER_CONTROL_ADDR ; + ByteTable[TableLen] = MasterControlByte | + state->config->AgcMasterByte; + TableLen += 1; + + mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); + + /* Wait 30 ms. */ + msleep(150); + + /* Tuner RF frequency setting stage 2 */ + MXL_ControlWrite(fe, SEQ_FSM_PULSE, 1); + MXL_ControlWrite(fe, IF_DIVVAL, IfDivval); + MXL_GetCHRegister_ZeroIF(fe, AddrTable, ByteTable, &TableLen); + + MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START); + AddrTable[TableLen] = MASTER_CONTROL_ADDR ; + ByteTable[TableLen] = MasterControlByte | + state->config->AgcMasterByte ; + TableLen += 1; + + mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); + + msleep(100); + + return 0; +} +/* End: Custom code taken from the Realtek driver */ + +/* ---------------------------------------------------------------- + * Begin: Reference driver code found in the Realtek driver. + * Copyright (C) 2008 MaxLinear + */ +static u16 MXL5005_RegisterInit(struct dvb_frontend *fe) +{ + struct mxl5005s_state *state = fe->tuner_priv; + state->TunerRegs_Num = TUNER_REGS_NUM ; + + state->TunerRegs[0].Reg_Num = 9 ; + state->TunerRegs[0].Reg_Val = 0x40 ; + + state->TunerRegs[1].Reg_Num = 11 ; + state->TunerRegs[1].Reg_Val = 0x19 ; + + state->TunerRegs[2].Reg_Num = 12 ; + state->TunerRegs[2].Reg_Val = 0x60 ; + + state->TunerRegs[3].Reg_Num = 13 ; + state->TunerRegs[3].Reg_Val = 0x00 ; + + state->TunerRegs[4].Reg_Num = 14 ; + state->TunerRegs[4].Reg_Val = 0x00 ; + + state->TunerRegs[5].Reg_Num = 15 ; + state->TunerRegs[5].Reg_Val = 0xC0 ; + + state->TunerRegs[6].Reg_Num = 16 ; + state->TunerRegs[6].Reg_Val = 0x00 ; + + state->TunerRegs[7].Reg_Num = 17 ; + state->TunerRegs[7].Reg_Val = 0x00 ; + + state->TunerRegs[8].Reg_Num = 18 ; + state->TunerRegs[8].Reg_Val = 0x00 ; + + state->TunerRegs[9].Reg_Num = 19 ; + state->TunerRegs[9].Reg_Val = 0x34 ; + + state->TunerRegs[10].Reg_Num = 21 ; + state->TunerRegs[10].Reg_Val = 0x00 ; + + state->TunerRegs[11].Reg_Num = 22 ; + state->TunerRegs[11].Reg_Val = 0x6B ; + + state->TunerRegs[12].Reg_Num = 23 ; + state->TunerRegs[12].Reg_Val = 0x35 ; + + state->TunerRegs[13].Reg_Num = 24 ; + state->TunerRegs[13].Reg_Val = 0x70 ; + + state->TunerRegs[14].Reg_Num = 25 ; + state->TunerRegs[14].Reg_Val = 0x3E ; + + state->TunerRegs[15].Reg_Num = 26 ; + state->TunerRegs[15].Reg_Val = 0x82 ; + + state->TunerRegs[16].Reg_Num = 31 ; + state->TunerRegs[16].Reg_Val = 0x00 ; + + state->TunerRegs[17].Reg_Num = 32 ; + state->TunerRegs[17].Reg_Val = 0x40 ; + + state->TunerRegs[18].Reg_Num = 33 ; + state->TunerRegs[18].Reg_Val = 0x53 ; + + state->TunerRegs[19].Reg_Num = 34 ; + state->TunerRegs[19].Reg_Val = 0x81 ; + + state->TunerRegs[20].Reg_Num = 35 ; + state->TunerRegs[20].Reg_Val = 0xC9 ; + + state->TunerRegs[21].Reg_Num = 36 ; + state->TunerRegs[21].Reg_Val = 0x01 ; + + state->TunerRegs[22].Reg_Num = 37 ; + state->TunerRegs[22].Reg_Val = 0x00 ; + + state->TunerRegs[23].Reg_Num = 41 ; + state->TunerRegs[23].Reg_Val = 0x00 ; + + state->TunerRegs[24].Reg_Num = 42 ; + state->TunerRegs[24].Reg_Val = 0xF8 ; + + state->TunerRegs[25].Reg_Num = 43 ; + state->TunerRegs[25].Reg_Val = 0x43 ; + + state->TunerRegs[26].Reg_Num = 44 ; + state->TunerRegs[26].Reg_Val = 0x20 ; + + state->TunerRegs[27].Reg_Num = 45 ; + state->TunerRegs[27].Reg_Val = 0x80 ; + + state->TunerRegs[28].Reg_Num = 46 ; + state->TunerRegs[28].Reg_Val = 0x88 ; + + state->TunerRegs[29].Reg_Num = 47 ; + state->TunerRegs[29].Reg_Val = 0x86 ; + + state->TunerRegs[30].Reg_Num = 48 ; + state->TunerRegs[30].Reg_Val = 0x00 ; + + state->TunerRegs[31].Reg_Num = 49 ; + state->TunerRegs[31].Reg_Val = 0x00 ; + + state->TunerRegs[32].Reg_Num = 53 ; + state->TunerRegs[32].Reg_Val = 0x94 ; + + state->TunerRegs[33].Reg_Num = 54 ; + state->TunerRegs[33].Reg_Val = 0xFA ; + + state->TunerRegs[34].Reg_Num = 55 ; + state->TunerRegs[34].Reg_Val = 0x92 ; + + state->TunerRegs[35].Reg_Num = 56 ; + state->TunerRegs[35].Reg_Val = 0x80 ; + + state->TunerRegs[36].Reg_Num = 57 ; + state->TunerRegs[36].Reg_Val = 0x41 ; + + state->TunerRegs[37].Reg_Num = 58 ; + state->TunerRegs[37].Reg_Val = 0xDB ; + + state->TunerRegs[38].Reg_Num = 59 ; + state->TunerRegs[38].Reg_Val = 0x00 ; + + state->TunerRegs[39].Reg_Num = 60 ; + state->TunerRegs[39].Reg_Val = 0x00 ; + + state->TunerRegs[40].Reg_Num = 61 ; + state->TunerRegs[40].Reg_Val = 0x00 ; + + state->TunerRegs[41].Reg_Num = 62 ; + state->TunerRegs[41].Reg_Val = 0x00 ; + + state->TunerRegs[42].Reg_Num = 65 ; + state->TunerRegs[42].Reg_Val = 0xF8 ; + + state->TunerRegs[43].Reg_Num = 66 ; + state->TunerRegs[43].Reg_Val = 0xE4 ; + + state->TunerRegs[44].Reg_Num = 67 ; + state->TunerRegs[44].Reg_Val = 0x90 ; + + state->TunerRegs[45].Reg_Num = 68 ; + state->TunerRegs[45].Reg_Val = 0xC0 ; + + state->TunerRegs[46].Reg_Num = 69 ; + state->TunerRegs[46].Reg_Val = 0x01 ; + + state->TunerRegs[47].Reg_Num = 70 ; + state->TunerRegs[47].Reg_Val = 0x50 ; + + state->TunerRegs[48].Reg_Num = 71 ; + state->TunerRegs[48].Reg_Val = 0x06 ; + + state->TunerRegs[49].Reg_Num = 72 ; + state->TunerRegs[49].Reg_Val = 0x00 ; + + state->TunerRegs[50].Reg_Num = 73 ; + state->TunerRegs[50].Reg_Val = 0x20 ; + + state->TunerRegs[51].Reg_Num = 76 ; + state->TunerRegs[51].Reg_Val = 0xBB ; + + state->TunerRegs[52].Reg_Num = 77 ; + state->TunerRegs[52].Reg_Val = 0x13 ; + + state->TunerRegs[53].Reg_Num = 81 ; + state->TunerRegs[53].Reg_Val = 0x04 ; + + state->TunerRegs[54].Reg_Num = 82 ; + state->TunerRegs[54].Reg_Val = 0x75 ; + + state->TunerRegs[55].Reg_Num = 83 ; + state->TunerRegs[55].Reg_Val = 0x00 ; + + state->TunerRegs[56].Reg_Num = 84 ; + state->TunerRegs[56].Reg_Val = 0x00 ; + + state->TunerRegs[57].Reg_Num = 85 ; + state->TunerRegs[57].Reg_Val = 0x00 ; + + state->TunerRegs[58].Reg_Num = 91 ; + state->TunerRegs[58].Reg_Val = 0x70 ; + + state->TunerRegs[59].Reg_Num = 92 ; + state->TunerRegs[59].Reg_Val = 0x00 ; + + state->TunerRegs[60].Reg_Num = 93 ; + state->TunerRegs[60].Reg_Val = 0x00 ; + + state->TunerRegs[61].Reg_Num = 94 ; + state->TunerRegs[61].Reg_Val = 0x00 ; + + state->TunerRegs[62].Reg_Num = 95 ; + state->TunerRegs[62].Reg_Val = 0x0C ; + + state->TunerRegs[63].Reg_Num = 96 ; + state->TunerRegs[63].Reg_Val = 0x00 ; + + state->TunerRegs[64].Reg_Num = 97 ; + state->TunerRegs[64].Reg_Val = 0x00 ; + + state->TunerRegs[65].Reg_Num = 98 ; + state->TunerRegs[65].Reg_Val = 0xE2 ; + + state->TunerRegs[66].Reg_Num = 99 ; + state->TunerRegs[66].Reg_Val = 0x00 ; + + state->TunerRegs[67].Reg_Num = 100 ; + state->TunerRegs[67].Reg_Val = 0x00 ; + + state->TunerRegs[68].Reg_Num = 101 ; + state->TunerRegs[68].Reg_Val = 0x12 ; + + state->TunerRegs[69].Reg_Num = 102 ; + state->TunerRegs[69].Reg_Val = 0x80 ; + + state->TunerRegs[70].Reg_Num = 103 ; + state->TunerRegs[70].Reg_Val = 0x32 ; + + state->TunerRegs[71].Reg_Num = 104 ; + state->TunerRegs[71].Reg_Val = 0xB4 ; + + state->TunerRegs[72].Reg_Num = 105 ; + state->TunerRegs[72].Reg_Val = 0x60 ; + + state->TunerRegs[73].Reg_Num = 106 ; + state->TunerRegs[73].Reg_Val = 0x83 ; + + state->TunerRegs[74].Reg_Num = 107 ; + state->TunerRegs[74].Reg_Val = 0x84 ; + + state->TunerRegs[75].Reg_Num = 108 ; + state->TunerRegs[75].Reg_Val = 0x9C ; + + state->TunerRegs[76].Reg_Num = 109 ; + state->TunerRegs[76].Reg_Val = 0x02 ; + + state->TunerRegs[77].Reg_Num = 110 ; + state->TunerRegs[77].Reg_Val = 0x81 ; + + state->TunerRegs[78].Reg_Num = 111 ; + state->TunerRegs[78].Reg_Val = 0xC0 ; + + state->TunerRegs[79].Reg_Num = 112 ; + state->TunerRegs[79].Reg_Val = 0x10 ; + + state->TunerRegs[80].Reg_Num = 131 ; + state->TunerRegs[80].Reg_Val = 0x8A ; + + state->TunerRegs[81].Reg_Num = 132 ; + state->TunerRegs[81].Reg_Val = 0x10 ; + + state->TunerRegs[82].Reg_Num = 133 ; + state->TunerRegs[82].Reg_Val = 0x24 ; + + state->TunerRegs[83].Reg_Num = 134 ; + state->TunerRegs[83].Reg_Val = 0x00 ; + + state->TunerRegs[84].Reg_Num = 135 ; + state->TunerRegs[84].Reg_Val = 0x00 ; + + state->TunerRegs[85].Reg_Num = 136 ; + state->TunerRegs[85].Reg_Val = 0x7E ; + + state->TunerRegs[86].Reg_Num = 137 ; + state->TunerRegs[86].Reg_Val = 0x40 ; + + state->TunerRegs[87].Reg_Num = 138 ; + state->TunerRegs[87].Reg_Val = 0x38 ; + + state->TunerRegs[88].Reg_Num = 146 ; + state->TunerRegs[88].Reg_Val = 0xF6 ; + + state->TunerRegs[89].Reg_Num = 147 ; + state->TunerRegs[89].Reg_Val = 0x1A ; + + state->TunerRegs[90].Reg_Num = 148 ; + state->TunerRegs[90].Reg_Val = 0x62 ; + + state->TunerRegs[91].Reg_Num = 149 ; + state->TunerRegs[91].Reg_Val = 0x33 ; + + state->TunerRegs[92].Reg_Num = 150 ; + state->TunerRegs[92].Reg_Val = 0x80 ; + + state->TunerRegs[93].Reg_Num = 156 ; + state->TunerRegs[93].Reg_Val = 0x56 ; + + state->TunerRegs[94].Reg_Num = 157 ; + state->TunerRegs[94].Reg_Val = 0x17 ; + + state->TunerRegs[95].Reg_Num = 158 ; + state->TunerRegs[95].Reg_Val = 0xA9 ; + + state->TunerRegs[96].Reg_Num = 159 ; + state->TunerRegs[96].Reg_Val = 0x00 ; + + state->TunerRegs[97].Reg_Num = 160 ; + state->TunerRegs[97].Reg_Val = 0x00 ; + + state->TunerRegs[98].Reg_Num = 161 ; + state->TunerRegs[98].Reg_Val = 0x00 ; + + state->TunerRegs[99].Reg_Num = 162 ; + state->TunerRegs[99].Reg_Val = 0x40 ; + + state->TunerRegs[100].Reg_Num = 166 ; + state->TunerRegs[100].Reg_Val = 0xAE ; + + state->TunerRegs[101].Reg_Num = 167 ; + state->TunerRegs[101].Reg_Val = 0x1B ; + + state->TunerRegs[102].Reg_Num = 168 ; + state->TunerRegs[102].Reg_Val = 0xF2 ; + + state->TunerRegs[103].Reg_Num = 195 ; + state->TunerRegs[103].Reg_Val = 0x00 ; + + return 0 ; +} + +static u16 MXL5005_ControlInit(struct dvb_frontend *fe) +{ + struct mxl5005s_state *state = fe->tuner_priv; + state->Init_Ctrl_Num = INITCTRL_NUM; + + state->Init_Ctrl[0].Ctrl_Num = DN_IQTN_AMP_CUT ; + state->Init_Ctrl[0].size = 1 ; + state->Init_Ctrl[0].addr[0] = 73; + state->Init_Ctrl[0].bit[0] = 7; + state->Init_Ctrl[0].val[0] = 0; + + state->Init_Ctrl[1].Ctrl_Num = BB_MODE ; + state->Init_Ctrl[1].size = 1 ; + state->Init_Ctrl[1].addr[0] = 53; + state->Init_Ctrl[1].bit[0] = 2; + state->Init_Ctrl[1].val[0] = 1; + + state->Init_Ctrl[2].Ctrl_Num = BB_BUF ; + state->Init_Ctrl[2].size = 2 ; + state->Init_Ctrl[2].addr[0] = 53; + state->Init_Ctrl[2].bit[0] = 1; + state->Init_Ctrl[2].val[0] = 0; + state->Init_Ctrl[2].addr[1] = 57; + state->Init_Ctrl[2].bit[1] = 0; + state->Init_Ctrl[2].val[1] = 1; + + state->Init_Ctrl[3].Ctrl_Num = BB_BUF_OA ; + state->Init_Ctrl[3].size = 1 ; + state->Init_Ctrl[3].addr[0] = 53; + state->Init_Ctrl[3].bit[0] = 0; + state->Init_Ctrl[3].val[0] = 0; + + state->Init_Ctrl[4].Ctrl_Num = BB_ALPF_BANDSELECT ; + state->Init_Ctrl[4].size = 3 ; + state->Init_Ctrl[4].addr[0] = 53; + state->Init_Ctrl[4].bit[0] = 5; + state->Init_Ctrl[4].val[0] = 0; + state->Init_Ctrl[4].addr[1] = 53; + state->Init_Ctrl[4].bit[1] = 6; + state->Init_Ctrl[4].val[1] = 0; + state->Init_Ctrl[4].addr[2] = 53; + state->Init_Ctrl[4].bit[2] = 7; + state->Init_Ctrl[4].val[2] = 1; + + state->Init_Ctrl[5].Ctrl_Num = BB_IQSWAP ; + state->Init_Ctrl[5].size = 1 ; + state->Init_Ctrl[5].addr[0] = 59; + state->Init_Ctrl[5].bit[0] = 0; + state->Init_Ctrl[5].val[0] = 0; + + state->Init_Ctrl[6].Ctrl_Num = BB_DLPF_BANDSEL ; + state->Init_Ctrl[6].size = 2 ; + state->Init_Ctrl[6].addr[0] = 53; + state->Init_Ctrl[6].bit[0] = 3; + state->Init_Ctrl[6].val[0] = 0; + state->Init_Ctrl[6].addr[1] = 53; + state->Init_Ctrl[6].bit[1] = 4; + state->Init_Ctrl[6].val[1] = 1; + + state->Init_Ctrl[7].Ctrl_Num = RFSYN_CHP_GAIN ; + state->Init_Ctrl[7].size = 4 ; + state->Init_Ctrl[7].addr[0] = 22; + state->Init_Ctrl[7].bit[0] = 4; + state->Init_Ctrl[7].val[0] = 0; + state->Init_Ctrl[7].addr[1] = 22; + state->Init_Ctrl[7].bit[1] = 5; + state->Init_Ctrl[7].val[1] = 1; + state->Init_Ctrl[7].addr[2] = 22; + state->Init_Ctrl[7].bit[2] = 6; + state->Init_Ctrl[7].val[2] = 1; + state->Init_Ctrl[7].addr[3] = 22; + state->Init_Ctrl[7].bit[3] = 7; + state->Init_Ctrl[7].val[3] = 0; + + state->Init_Ctrl[8].Ctrl_Num = RFSYN_EN_CHP_HIGAIN ; + state->Init_Ctrl[8].size = 1 ; + state->Init_Ctrl[8].addr[0] = 22; + state->Init_Ctrl[8].bit[0] = 2; + state->Init_Ctrl[8].val[0] = 0; + + state->Init_Ctrl[9].Ctrl_Num = AGC_IF ; + state->Init_Ctrl[9].size = 4 ; + state->Init_Ctrl[9].addr[0] = 76; + state->Init_Ctrl[9].bit[0] = 0; + state->Init_Ctrl[9].val[0] = 1; + state->Init_Ctrl[9].addr[1] = 76; + state->Init_Ctrl[9].bit[1] = 1; + state->Init_Ctrl[9].val[1] = 1; + state->Init_Ctrl[9].addr[2] = 76; + state->Init_Ctrl[9].bit[2] = 2; + state->Init_Ctrl[9].val[2] = 0; + state->Init_Ctrl[9].addr[3] = 76; + state->Init_Ctrl[9].bit[3] = 3; + state->Init_Ctrl[9].val[3] = 1; + + state->Init_Ctrl[10].Ctrl_Num = AGC_RF ; + state->Init_Ctrl[10].size = 4 ; + state->Init_Ctrl[10].addr[0] = 76; + state->Init_Ctrl[10].bit[0] = 4; + state->Init_Ctrl[10].val[0] = 1; + state->Init_Ctrl[10].addr[1] = 76; + state->Init_Ctrl[10].bit[1] = 5; + state->Init_Ctrl[10].val[1] = 1; + state->Init_Ctrl[10].addr[2] = 76; + state->Init_Ctrl[10].bit[2] = 6; + state->Init_Ctrl[10].val[2] = 0; + state->Init_Ctrl[10].addr[3] = 76; + state->Init_Ctrl[10].bit[3] = 7; + state->Init_Ctrl[10].val[3] = 1; + + state->Init_Ctrl[11].Ctrl_Num = IF_DIVVAL ; + state->Init_Ctrl[11].size = 5 ; + state->Init_Ctrl[11].addr[0] = 43; + state->Init_Ctrl[11].bit[0] = 3; + state->Init_Ctrl[11].val[0] = 0; + state->Init_Ctrl[11].addr[1] = 43; + state->Init_Ctrl[11].bit[1] = 4; + state->Init_Ctrl[11].val[1] = 0; + state->Init_Ctrl[11].addr[2] = 43; + state->Init_Ctrl[11].bit[2] = 5; + state->Init_Ctrl[11].val[2] = 0; + state->Init_Ctrl[11].addr[3] = 43; + state->Init_Ctrl[11].bit[3] = 6; + state->Init_Ctrl[11].val[3] = 1; + state->Init_Ctrl[11].addr[4] = 43; + state->Init_Ctrl[11].bit[4] = 7; + state->Init_Ctrl[11].val[4] = 0; + + state->Init_Ctrl[12].Ctrl_Num = IF_VCO_BIAS ; + state->Init_Ctrl[12].size = 6 ; + state->Init_Ctrl[12].addr[0] = 44; + state->Init_Ctrl[12].bit[0] = 2; + state->Init_Ctrl[12].val[0] = 0; + state->Init_Ctrl[12].addr[1] = 44; + state->Init_Ctrl[12].bit[1] = 3; + state->Init_Ctrl[12].val[1] = 0; + state->Init_Ctrl[12].addr[2] = 44; + state->Init_Ctrl[12].bit[2] = 4; + state->Init_Ctrl[12].val[2] = 0; + state->Init_Ctrl[12].addr[3] = 44; + state->Init_Ctrl[12].bit[3] = 5; + state->Init_Ctrl[12].val[3] = 1; + state->Init_Ctrl[12].addr[4] = 44; + state->Init_Ctrl[12].bit[4] = 6; + state->Init_Ctrl[12].val[4] = 0; + state->Init_Ctrl[12].addr[5] = 44; + state->Init_Ctrl[12].bit[5] = 7; + state->Init_Ctrl[12].val[5] = 0; + + state->Init_Ctrl[13].Ctrl_Num = CHCAL_INT_MOD_IF ; + state->Init_Ctrl[13].size = 7 ; + state->Init_Ctrl[13].addr[0] = 11; + state->Init_Ctrl[13].bit[0] = 0; + state->Init_Ctrl[13].val[0] = 1; + state->Init_Ctrl[13].addr[1] = 11; + state->Init_Ctrl[13].bit[1] = 1; + state->Init_Ctrl[13].val[1] = 0; + state->Init_Ctrl[13].addr[2] = 11; + state->Init_Ctrl[13].bit[2] = 2; + state->Init_Ctrl[13].val[2] = 0; + state->Init_Ctrl[13].addr[3] = 11; + state->Init_Ctrl[13].bit[3] = 3; + state->Init_Ctrl[13].val[3] = 1; + state->Init_Ctrl[13].addr[4] = 11; + state->Init_Ctrl[13].bit[4] = 4; + state->Init_Ctrl[13].val[4] = 1; + state->Init_Ctrl[13].addr[5] = 11; + state->Init_Ctrl[13].bit[5] = 5; + state->Init_Ctrl[13].val[5] = 0; + state->Init_Ctrl[13].addr[6] = 11; + state->Init_Ctrl[13].bit[6] = 6; + state->Init_Ctrl[13].val[6] = 0; + + state->Init_Ctrl[14].Ctrl_Num = CHCAL_FRAC_MOD_IF ; + state->Init_Ctrl[14].size = 16 ; + state->Init_Ctrl[14].addr[0] = 13; + state->Init_Ctrl[14].bit[0] = 0; + state->Init_Ctrl[14].val[0] = 0; + state->Init_Ctrl[14].addr[1] = 13; + state->Init_Ctrl[14].bit[1] = 1; + state->Init_Ctrl[14].val[1] = 0; + state->Init_Ctrl[14].addr[2] = 13; + state->Init_Ctrl[14].bit[2] = 2; + state->Init_Ctrl[14].val[2] = 0; + state->Init_Ctrl[14].addr[3] = 13; + state->Init_Ctrl[14].bit[3] = 3; + state->Init_Ctrl[14].val[3] = 0; + state->Init_Ctrl[14].addr[4] = 13; + state->Init_Ctrl[14].bit[4] = 4; + state->Init_Ctrl[14].val[4] = 0; + state->Init_Ctrl[14].addr[5] = 13; + state->Init_Ctrl[14].bit[5] = 5; + state->Init_Ctrl[14].val[5] = 0; + state->Init_Ctrl[14].addr[6] = 13; + state->Init_Ctrl[14].bit[6] = 6; + state->Init_Ctrl[14].val[6] = 0; + state->Init_Ctrl[14].addr[7] = 13; + state->Init_Ctrl[14].bit[7] = 7; + state->Init_Ctrl[14].val[7] = 0; + state->Init_Ctrl[14].addr[8] = 12; + state->Init_Ctrl[14].bit[8] = 0; + state->Init_Ctrl[14].val[8] = 0; + state->Init_Ctrl[14].addr[9] = 12; + state->Init_Ctrl[14].bit[9] = 1; + state->Init_Ctrl[14].val[9] = 0; + state->Init_Ctrl[14].addr[10] = 12; + state->Init_Ctrl[14].bit[10] = 2; + state->Init_Ctrl[14].val[10] = 0; + state->Init_Ctrl[14].addr[11] = 12; + state->Init_Ctrl[14].bit[11] = 3; + state->Init_Ctrl[14].val[11] = 0; + state->Init_Ctrl[14].addr[12] = 12; + state->Init_Ctrl[14].bit[12] = 4; + state->Init_Ctrl[14].val[12] = 0; + state->Init_Ctrl[14].addr[13] = 12; + state->Init_Ctrl[14].bit[13] = 5; + state->Init_Ctrl[14].val[13] = 1; + state->Init_Ctrl[14].addr[14] = 12; + state->Init_Ctrl[14].bit[14] = 6; + state->Init_Ctrl[14].val[14] = 1; + state->Init_Ctrl[14].addr[15] = 12; + state->Init_Ctrl[14].bit[15] = 7; + state->Init_Ctrl[14].val[15] = 0; + + state->Init_Ctrl[15].Ctrl_Num = DRV_RES_SEL ; + state->Init_Ctrl[15].size = 3 ; + state->Init_Ctrl[15].addr[0] = 147; + state->Init_Ctrl[15].bit[0] = 2; + state->Init_Ctrl[15].val[0] = 0; + state->Init_Ctrl[15].addr[1] = 147; + state->Init_Ctrl[15].bit[1] = 3; + state->Init_Ctrl[15].val[1] = 1; + state->Init_Ctrl[15].addr[2] = 147; + state->Init_Ctrl[15].bit[2] = 4; + state->Init_Ctrl[15].val[2] = 1; + + state->Init_Ctrl[16].Ctrl_Num = I_DRIVER ; + state->Init_Ctrl[16].size = 2 ; + state->Init_Ctrl[16].addr[0] = 147; + state->Init_Ctrl[16].bit[0] = 0; + state->Init_Ctrl[16].val[0] = 0; + state->Init_Ctrl[16].addr[1] = 147; + state->Init_Ctrl[16].bit[1] = 1; + state->Init_Ctrl[16].val[1] = 1; + + state->Init_Ctrl[17].Ctrl_Num = EN_AAF ; + state->Init_Ctrl[17].size = 1 ; + state->Init_Ctrl[17].addr[0] = 147; + state->Init_Ctrl[17].bit[0] = 7; + state->Init_Ctrl[17].val[0] = 0; + + state->Init_Ctrl[18].Ctrl_Num = EN_3P ; + state->Init_Ctrl[18].size = 1 ; + state->Init_Ctrl[18].addr[0] = 147; + state->Init_Ctrl[18].bit[0] = 6; + state->Init_Ctrl[18].val[0] = 0; + + state->Init_Ctrl[19].Ctrl_Num = EN_AUX_3P ; + state->Init_Ctrl[19].size = 1 ; + state->Init_Ctrl[19].addr[0] = 156; + state->Init_Ctrl[19].bit[0] = 0; + state->Init_Ctrl[19].val[0] = 0; + + state->Init_Ctrl[20].Ctrl_Num = SEL_AAF_BAND ; + state->Init_Ctrl[20].size = 1 ; + state->Init_Ctrl[20].addr[0] = 147; + state->Init_Ctrl[20].bit[0] = 5; + state->Init_Ctrl[20].val[0] = 0; + + state->Init_Ctrl[21].Ctrl_Num = SEQ_ENCLK16_CLK_OUT ; + state->Init_Ctrl[21].size = 1 ; + state->Init_Ctrl[21].addr[0] = 137; + state->Init_Ctrl[21].bit[0] = 4; + state->Init_Ctrl[21].val[0] = 0; + + state->Init_Ctrl[22].Ctrl_Num = SEQ_SEL4_16B ; + state->Init_Ctrl[22].size = 1 ; + state->Init_Ctrl[22].addr[0] = 137; + state->Init_Ctrl[22].bit[0] = 7; + state->Init_Ctrl[22].val[0] = 0; + + state->Init_Ctrl[23].Ctrl_Num = XTAL_CAPSELECT ; + state->Init_Ctrl[23].size = 1 ; + state->Init_Ctrl[23].addr[0] = 91; + state->Init_Ctrl[23].bit[0] = 5; + state->Init_Ctrl[23].val[0] = 1; + + state->Init_Ctrl[24].Ctrl_Num = IF_SEL_DBL ; + state->Init_Ctrl[24].size = 1 ; + state->Init_Ctrl[24].addr[0] = 43; + state->Init_Ctrl[24].bit[0] = 0; + state->Init_Ctrl[24].val[0] = 1; + + state->Init_Ctrl[25].Ctrl_Num = RFSYN_R_DIV ; + state->Init_Ctrl[25].size = 2 ; + state->Init_Ctrl[25].addr[0] = 22; + state->Init_Ctrl[25].bit[0] = 0; + state->Init_Ctrl[25].val[0] = 1; + state->Init_Ctrl[25].addr[1] = 22; + state->Init_Ctrl[25].bit[1] = 1; + state->Init_Ctrl[25].val[1] = 1; + + state->Init_Ctrl[26].Ctrl_Num = SEQ_EXTSYNTHCALIF ; + state->Init_Ctrl[26].size = 1 ; + state->Init_Ctrl[26].addr[0] = 134; + state->Init_Ctrl[26].bit[0] = 2; + state->Init_Ctrl[26].val[0] = 0; + + state->Init_Ctrl[27].Ctrl_Num = SEQ_EXTDCCAL ; + state->Init_Ctrl[27].size = 1 ; + state->Init_Ctrl[27].addr[0] = 137; + state->Init_Ctrl[27].bit[0] = 3; + state->Init_Ctrl[27].val[0] = 0; + + state->Init_Ctrl[28].Ctrl_Num = AGC_EN_RSSI ; + state->Init_Ctrl[28].size = 1 ; + state->Init_Ctrl[28].addr[0] = 77; + state->Init_Ctrl[28].bit[0] = 7; + state->Init_Ctrl[28].val[0] = 0; + + state->Init_Ctrl[29].Ctrl_Num = RFA_ENCLKRFAGC ; + state->Init_Ctrl[29].size = 1 ; + state->Init_Ctrl[29].addr[0] = 166; + state->Init_Ctrl[29].bit[0] = 7; + state->Init_Ctrl[29].val[0] = 1; + + state->Init_Ctrl[30].Ctrl_Num = RFA_RSSI_REFH ; + state->Init_Ctrl[30].size = 3 ; + state->Init_Ctrl[30].addr[0] = 166; + state->Init_Ctrl[30].bit[0] = 0; + state->Init_Ctrl[30].val[0] = 0; + state->Init_Ctrl[30].addr[1] = 166; + state->Init_Ctrl[30].bit[1] = 1; + state->Init_Ctrl[30].val[1] = 1; + state->Init_Ctrl[30].addr[2] = 166; + state->Init_Ctrl[30].bit[2] = 2; + state->Init_Ctrl[30].val[2] = 1; + + state->Init_Ctrl[31].Ctrl_Num = RFA_RSSI_REF ; + state->Init_Ctrl[31].size = 3 ; + state->Init_Ctrl[31].addr[0] = 166; + state->Init_Ctrl[31].bit[0] = 3; + state->Init_Ctrl[31].val[0] = 1; + state->Init_Ctrl[31].addr[1] = 166; + state->Init_Ctrl[31].bit[1] = 4; + state->Init_Ctrl[31].val[1] = 0; + state->Init_Ctrl[31].addr[2] = 166; + state->Init_Ctrl[31].bit[2] = 5; + state->Init_Ctrl[31].val[2] = 1; + + state->Init_Ctrl[32].Ctrl_Num = RFA_RSSI_REFL ; + state->Init_Ctrl[32].size = 3 ; + state->Init_Ctrl[32].addr[0] = 167; + state->Init_Ctrl[32].bit[0] = 0; + state->Init_Ctrl[32].val[0] = 1; + state->Init_Ctrl[32].addr[1] = 167; + state->Init_Ctrl[32].bit[1] = 1; + state->Init_Ctrl[32].val[1] = 1; + state->Init_Ctrl[32].addr[2] = 167; + state->Init_Ctrl[32].bit[2] = 2; + state->Init_Ctrl[32].val[2] = 0; + + state->Init_Ctrl[33].Ctrl_Num = RFA_FLR ; + state->Init_Ctrl[33].size = 4 ; + state->Init_Ctrl[33].addr[0] = 168; + state->Init_Ctrl[33].bit[0] = 0; + state->Init_Ctrl[33].val[0] = 0; + state->Init_Ctrl[33].addr[1] = 168; + state->Init_Ctrl[33].bit[1] = 1; + state->Init_Ctrl[33].val[1] = 1; + state->Init_Ctrl[33].addr[2] = 168; + state->Init_Ctrl[33].bit[2] = 2; + state->Init_Ctrl[33].val[2] = 0; + state->Init_Ctrl[33].addr[3] = 168; + state->Init_Ctrl[33].bit[3] = 3; + state->Init_Ctrl[33].val[3] = 0; + + state->Init_Ctrl[34].Ctrl_Num = RFA_CEIL ; + state->Init_Ctrl[34].size = 4 ; + state->Init_Ctrl[34].addr[0] = 168; + state->Init_Ctrl[34].bit[0] = 4; + state->Init_Ctrl[34].val[0] = 1; + state->Init_Ctrl[34].addr[1] = 168; + state->Init_Ctrl[34].bit[1] = 5; + state->Init_Ctrl[34].val[1] = 1; + state->Init_Ctrl[34].addr[2] = 168; + state->Init_Ctrl[34].bit[2] = 6; + state->Init_Ctrl[34].val[2] = 1; + state->Init_Ctrl[34].addr[3] = 168; + state->Init_Ctrl[34].bit[3] = 7; + state->Init_Ctrl[34].val[3] = 1; + + state->Init_Ctrl[35].Ctrl_Num = SEQ_EXTIQFSMPULSE ; + state->Init_Ctrl[35].size = 1 ; + state->Init_Ctrl[35].addr[0] = 135; + state->Init_Ctrl[35].bit[0] = 0; + state->Init_Ctrl[35].val[0] = 0; + + state->Init_Ctrl[36].Ctrl_Num = OVERRIDE_1 ; + state->Init_Ctrl[36].size = 1 ; + state->Init_Ctrl[36].addr[0] = 56; + state->Init_Ctrl[36].bit[0] = 3; + state->Init_Ctrl[36].val[0] = 0; + + state->Init_Ctrl[37].Ctrl_Num = BB_INITSTATE_DLPF_TUNE ; + state->Init_Ctrl[37].size = 7 ; + state->Init_Ctrl[37].addr[0] = 59; + state->Init_Ctrl[37].bit[0] = 1; + state->Init_Ctrl[37].val[0] = 0; + state->Init_Ctrl[37].addr[1] = 59; + state->Init_Ctrl[37].bit[1] = 2; + state->Init_Ctrl[37].val[1] = 0; + state->Init_Ctrl[37].addr[2] = 59; + state->Init_Ctrl[37].bit[2] = 3; + state->Init_Ctrl[37].val[2] = 0; + state->Init_Ctrl[37].addr[3] = 59; + state->Init_Ctrl[37].bit[3] = 4; + state->Init_Ctrl[37].val[3] = 0; + state->Init_Ctrl[37].addr[4] = 59; + state->Init_Ctrl[37].bit[4] = 5; + state->Init_Ctrl[37].val[4] = 0; + state->Init_Ctrl[37].addr[5] = 59; + state->Init_Ctrl[37].bit[5] = 6; + state->Init_Ctrl[37].val[5] = 0; + state->Init_Ctrl[37].addr[6] = 59; + state->Init_Ctrl[37].bit[6] = 7; + state->Init_Ctrl[37].val[6] = 0; + + state->Init_Ctrl[38].Ctrl_Num = TG_R_DIV ; + state->Init_Ctrl[38].size = 6 ; + state->Init_Ctrl[38].addr[0] = 32; + state->Init_Ctrl[38].bit[0] = 2; + state->Init_Ctrl[38].val[0] = 0; + state->Init_Ctrl[38].addr[1] = 32; + state->Init_Ctrl[38].bit[1] = 3; + state->Init_Ctrl[38].val[1] = 0; + state->Init_Ctrl[38].addr[2] = 32; + state->Init_Ctrl[38].bit[2] = 4; + state->Init_Ctrl[38].val[2] = 0; + state->Init_Ctrl[38].addr[3] = 32; + state->Init_Ctrl[38].bit[3] = 5; + state->Init_Ctrl[38].val[3] = 0; + state->Init_Ctrl[38].addr[4] = 32; + state->Init_Ctrl[38].bit[4] = 6; + state->Init_Ctrl[38].val[4] = 1; + state->Init_Ctrl[38].addr[5] = 32; + state->Init_Ctrl[38].bit[5] = 7; + state->Init_Ctrl[38].val[5] = 0; + + state->Init_Ctrl[39].Ctrl_Num = EN_CHP_LIN_B ; + state->Init_Ctrl[39].size = 1 ; + state->Init_Ctrl[39].addr[0] = 25; + state->Init_Ctrl[39].bit[0] = 3; + state->Init_Ctrl[39].val[0] = 1; + + + state->CH_Ctrl_Num = CHCTRL_NUM ; + + state->CH_Ctrl[0].Ctrl_Num = DN_POLY ; + state->CH_Ctrl[0].size = 2 ; + state->CH_Ctrl[0].addr[0] = 68; + state->CH_Ctrl[0].bit[0] = 6; + state->CH_Ctrl[0].val[0] = 1; + state->CH_Ctrl[0].addr[1] = 68; + state->CH_Ctrl[0].bit[1] = 7; + state->CH_Ctrl[0].val[1] = 1; + + state->CH_Ctrl[1].Ctrl_Num = DN_RFGAIN ; + state->CH_Ctrl[1].size = 2 ; + state->CH_Ctrl[1].addr[0] = 70; + state->CH_Ctrl[1].bit[0] = 6; + state->CH_Ctrl[1].val[0] = 1; + state->CH_Ctrl[1].addr[1] = 70; + state->CH_Ctrl[1].bit[1] = 7; + state->CH_Ctrl[1].val[1] = 0; + + state->CH_Ctrl[2].Ctrl_Num = DN_CAP_RFLPF ; + state->CH_Ctrl[2].size = 9 ; + state->CH_Ctrl[2].addr[0] = 69; + state->CH_Ctrl[2].bit[0] = 5; + state->CH_Ctrl[2].val[0] = 0; + state->CH_Ctrl[2].addr[1] = 69; + state->CH_Ctrl[2].bit[1] = 6; + state->CH_Ctrl[2].val[1] = 0; + state->CH_Ctrl[2].addr[2] = 69; + state->CH_Ctrl[2].bit[2] = 7; + state->CH_Ctrl[2].val[2] = 0; + state->CH_Ctrl[2].addr[3] = 68; + state->CH_Ctrl[2].bit[3] = 0; + state->CH_Ctrl[2].val[3] = 0; + state->CH_Ctrl[2].addr[4] = 68; + state->CH_Ctrl[2].bit[4] = 1; + state->CH_Ctrl[2].val[4] = 0; + state->CH_Ctrl[2].addr[5] = 68; + state->CH_Ctrl[2].bit[5] = 2; + state->CH_Ctrl[2].val[5] = 0; + state->CH_Ctrl[2].addr[6] = 68; + state->CH_Ctrl[2].bit[6] = 3; + state->CH_Ctrl[2].val[6] = 0; + state->CH_Ctrl[2].addr[7] = 68; + state->CH_Ctrl[2].bit[7] = 4; + state->CH_Ctrl[2].val[7] = 0; + state->CH_Ctrl[2].addr[8] = 68; + state->CH_Ctrl[2].bit[8] = 5; + state->CH_Ctrl[2].val[8] = 0; + + state->CH_Ctrl[3].Ctrl_Num = DN_EN_VHFUHFBAR ; + state->CH_Ctrl[3].size = 1 ; + state->CH_Ctrl[3].addr[0] = 70; + state->CH_Ctrl[3].bit[0] = 5; + state->CH_Ctrl[3].val[0] = 0; + + state->CH_Ctrl[4].Ctrl_Num = DN_GAIN_ADJUST ; + state->CH_Ctrl[4].size = 3 ; + state->CH_Ctrl[4].addr[0] = 73; + state->CH_Ctrl[4].bit[0] = 4; + state->CH_Ctrl[4].val[0] = 0; + state->CH_Ctrl[4].addr[1] = 73; + state->CH_Ctrl[4].bit[1] = 5; + state->CH_Ctrl[4].val[1] = 1; + state->CH_Ctrl[4].addr[2] = 73; + state->CH_Ctrl[4].bit[2] = 6; + state->CH_Ctrl[4].val[2] = 0; + + state->CH_Ctrl[5].Ctrl_Num = DN_IQTNBUF_AMP ; + state->CH_Ctrl[5].size = 4 ; + state->CH_Ctrl[5].addr[0] = 70; + state->CH_Ctrl[5].bit[0] = 0; + state->CH_Ctrl[5].val[0] = 0; + state->CH_Ctrl[5].addr[1] = 70; + state->CH_Ctrl[5].bit[1] = 1; + state->CH_Ctrl[5].val[1] = 0; + state->CH_Ctrl[5].addr[2] = 70; + state->CH_Ctrl[5].bit[2] = 2; + state->CH_Ctrl[5].val[2] = 0; + state->CH_Ctrl[5].addr[3] = 70; + state->CH_Ctrl[5].bit[3] = 3; + state->CH_Ctrl[5].val[3] = 0; + + state->CH_Ctrl[6].Ctrl_Num = DN_IQTNGNBFBIAS_BST ; + state->CH_Ctrl[6].size = 1 ; + state->CH_Ctrl[6].addr[0] = 70; + state->CH_Ctrl[6].bit[0] = 4; + state->CH_Ctrl[6].val[0] = 1; + + state->CH_Ctrl[7].Ctrl_Num = RFSYN_EN_OUTMUX ; + state->CH_Ctrl[7].size = 1 ; + state->CH_Ctrl[7].addr[0] = 111; + state->CH_Ctrl[7].bit[0] = 4; + state->CH_Ctrl[7].val[0] = 0; + + state->CH_Ctrl[8].Ctrl_Num = RFSYN_SEL_VCO_OUT ; + state->CH_Ctrl[8].size = 1 ; + state->CH_Ctrl[8].addr[0] = 111; + state->CH_Ctrl[8].bit[0] = 7; + state->CH_Ctrl[8].val[0] = 1; + + state->CH_Ctrl[9].Ctrl_Num = RFSYN_SEL_VCO_HI ; + state->CH_Ctrl[9].size = 1 ; + state->CH_Ctrl[9].addr[0] = 111; + state->CH_Ctrl[9].bit[0] = 6; + state->CH_Ctrl[9].val[0] = 1; + + state->CH_Ctrl[10].Ctrl_Num = RFSYN_SEL_DIVM ; + state->CH_Ctrl[10].size = 1 ; + state->CH_Ctrl[10].addr[0] = 111; + state->CH_Ctrl[10].bit[0] = 5; + state->CH_Ctrl[10].val[0] = 0; + + state->CH_Ctrl[11].Ctrl_Num = RFSYN_RF_DIV_BIAS ; + state->CH_Ctrl[11].size = 2 ; + state->CH_Ctrl[11].addr[0] = 110; + state->CH_Ctrl[11].bit[0] = 0; + state->CH_Ctrl[11].val[0] = 1; + state->CH_Ctrl[11].addr[1] = 110; + state->CH_Ctrl[11].bit[1] = 1; + state->CH_Ctrl[11].val[1] = 0; + + state->CH_Ctrl[12].Ctrl_Num = DN_SEL_FREQ ; + state->CH_Ctrl[12].size = 3 ; + state->CH_Ctrl[12].addr[0] = 69; + state->CH_Ctrl[12].bit[0] = 2; + state->CH_Ctrl[12].val[0] = 0; + state->CH_Ctrl[12].addr[1] = 69; + state->CH_Ctrl[12].bit[1] = 3; + state->CH_Ctrl[12].val[1] = 0; + state->CH_Ctrl[12].addr[2] = 69; + state->CH_Ctrl[12].bit[2] = 4; + state->CH_Ctrl[12].val[2] = 0; + + state->CH_Ctrl[13].Ctrl_Num = RFSYN_VCO_BIAS ; + state->CH_Ctrl[13].size = 6 ; + state->CH_Ctrl[13].addr[0] = 110; + state->CH_Ctrl[13].bit[0] = 2; + state->CH_Ctrl[13].val[0] = 0; + state->CH_Ctrl[13].addr[1] = 110; + state->CH_Ctrl[13].bit[1] = 3; + state->CH_Ctrl[13].val[1] = 0; + state->CH_Ctrl[13].addr[2] = 110; + state->CH_Ctrl[13].bit[2] = 4; + state->CH_Ctrl[13].val[2] = 0; + state->CH_Ctrl[13].addr[3] = 110; + state->CH_Ctrl[13].bit[3] = 5; + state->CH_Ctrl[13].val[3] = 0; + state->CH_Ctrl[13].addr[4] = 110; + state->CH_Ctrl[13].bit[4] = 6; + state->CH_Ctrl[13].val[4] = 0; + state->CH_Ctrl[13].addr[5] = 110; + state->CH_Ctrl[13].bit[5] = 7; + state->CH_Ctrl[13].val[5] = 1; + + state->CH_Ctrl[14].Ctrl_Num = CHCAL_INT_MOD_RF ; + state->CH_Ctrl[14].size = 7 ; + state->CH_Ctrl[14].addr[0] = 14; + state->CH_Ctrl[14].bit[0] = 0; + state->CH_Ctrl[14].val[0] = 0; + state->CH_Ctrl[14].addr[1] = 14; + state->CH_Ctrl[14].bit[1] = 1; + state->CH_Ctrl[14].val[1] = 0; + state->CH_Ctrl[14].addr[2] = 14; + state->CH_Ctrl[14].bit[2] = 2; + state->CH_Ctrl[14].val[2] = 0; + state->CH_Ctrl[14].addr[3] = 14; + state->CH_Ctrl[14].bit[3] = 3; + state->CH_Ctrl[14].val[3] = 0; + state->CH_Ctrl[14].addr[4] = 14; + state->CH_Ctrl[14].bit[4] = 4; + state->CH_Ctrl[14].val[4] = 0; + state->CH_Ctrl[14].addr[5] = 14; + state->CH_Ctrl[14].bit[5] = 5; + state->CH_Ctrl[14].val[5] = 0; + state->CH_Ctrl[14].addr[6] = 14; + state->CH_Ctrl[14].bit[6] = 6; + state->CH_Ctrl[14].val[6] = 0; + + state->CH_Ctrl[15].Ctrl_Num = CHCAL_FRAC_MOD_RF ; + state->CH_Ctrl[15].size = 18 ; + state->CH_Ctrl[15].addr[0] = 17; + state->CH_Ctrl[15].bit[0] = 6; + state->CH_Ctrl[15].val[0] = 0; + state->CH_Ctrl[15].addr[1] = 17; + state->CH_Ctrl[15].bit[1] = 7; + state->CH_Ctrl[15].val[1] = 0; + state->CH_Ctrl[15].addr[2] = 16; + state->CH_Ctrl[15].bit[2] = 0; + state->CH_Ctrl[15].val[2] = 0; + state->CH_Ctrl[15].addr[3] = 16; + state->CH_Ctrl[15].bit[3] = 1; + state->CH_Ctrl[15].val[3] = 0; + state->CH_Ctrl[15].addr[4] = 16; + state->CH_Ctrl[15].bit[4] = 2; + state->CH_Ctrl[15].val[4] = 0; + state->CH_Ctrl[15].addr[5] = 16; + state->CH_Ctrl[15].bit[5] = 3; + state->CH_Ctrl[15].val[5] = 0; + state->CH_Ctrl[15].addr[6] = 16; + state->CH_Ctrl[15].bit[6] = 4; + state->CH_Ctrl[15].val[6] = 0; + state->CH_Ctrl[15].addr[7] = 16; + state->CH_Ctrl[15].bit[7] = 5; + state->CH_Ctrl[15].val[7] = 0; + state->CH_Ctrl[15].addr[8] = 16; + state->CH_Ctrl[15].bit[8] = 6; + state->CH_Ctrl[15].val[8] = 0; + state->CH_Ctrl[15].addr[9] = 16; + state->CH_Ctrl[15].bit[9] = 7; + state->CH_Ctrl[15].val[9] = 0; + state->CH_Ctrl[15].addr[10] = 15; + state->CH_Ctrl[15].bit[10] = 0; + state->CH_Ctrl[15].val[10] = 0; + state->CH_Ctrl[15].addr[11] = 15; + state->CH_Ctrl[15].bit[11] = 1; + state->CH_Ctrl[15].val[11] = 0; + state->CH_Ctrl[15].addr[12] = 15; + state->CH_Ctrl[15].bit[12] = 2; + state->CH_Ctrl[15].val[12] = 0; + state->CH_Ctrl[15].addr[13] = 15; + state->CH_Ctrl[15].bit[13] = 3; + state->CH_Ctrl[15].val[13] = 0; + state->CH_Ctrl[15].addr[14] = 15; + state->CH_Ctrl[15].bit[14] = 4; + state->CH_Ctrl[15].val[14] = 0; + state->CH_Ctrl[15].addr[15] = 15; + state->CH_Ctrl[15].bit[15] = 5; + state->CH_Ctrl[15].val[15] = 0; + state->CH_Ctrl[15].addr[16] = 15; + state->CH_Ctrl[15].bit[16] = 6; + state->CH_Ctrl[15].val[16] = 1; + state->CH_Ctrl[15].addr[17] = 15; + state->CH_Ctrl[15].bit[17] = 7; + state->CH_Ctrl[15].val[17] = 1; + + state->CH_Ctrl[16].Ctrl_Num = RFSYN_LPF_R ; + state->CH_Ctrl[16].size = 5 ; + state->CH_Ctrl[16].addr[0] = 112; + state->CH_Ctrl[16].bit[0] = 0; + state->CH_Ctrl[16].val[0] = 0; + state->CH_Ctrl[16].addr[1] = 112; + state->CH_Ctrl[16].bit[1] = 1; + state->CH_Ctrl[16].val[1] = 0; + state->CH_Ctrl[16].addr[2] = 112; + state->CH_Ctrl[16].bit[2] = 2; + state->CH_Ctrl[16].val[2] = 0; + state->CH_Ctrl[16].addr[3] = 112; + state->CH_Ctrl[16].bit[3] = 3; + state->CH_Ctrl[16].val[3] = 0; + state->CH_Ctrl[16].addr[4] = 112; + state->CH_Ctrl[16].bit[4] = 4; + state->CH_Ctrl[16].val[4] = 1; + + state->CH_Ctrl[17].Ctrl_Num = CHCAL_EN_INT_RF ; + state->CH_Ctrl[17].size = 1 ; + state->CH_Ctrl[17].addr[0] = 14; + state->CH_Ctrl[17].bit[0] = 7; + state->CH_Ctrl[17].val[0] = 0; + + state->CH_Ctrl[18].Ctrl_Num = TG_LO_DIVVAL ; + state->CH_Ctrl[18].size = 4 ; + state->CH_Ctrl[18].addr[0] = 107; + state->CH_Ctrl[18].bit[0] = 3; + state->CH_Ctrl[18].val[0] = 0; + state->CH_Ctrl[18].addr[1] = 107; + state->CH_Ctrl[18].bit[1] = 4; + state->CH_Ctrl[18].val[1] = 0; + state->CH_Ctrl[18].addr[2] = 107; + state->CH_Ctrl[18].bit[2] = 5; + state->CH_Ctrl[18].val[2] = 0; + state->CH_Ctrl[18].addr[3] = 107; + state->CH_Ctrl[18].bit[3] = 6; + state->CH_Ctrl[18].val[3] = 0; + + state->CH_Ctrl[19].Ctrl_Num = TG_LO_SELVAL ; + state->CH_Ctrl[19].size = 3 ; + state->CH_Ctrl[19].addr[0] = 107; + state->CH_Ctrl[19].bit[0] = 7; + state->CH_Ctrl[19].val[0] = 1; + state->CH_Ctrl[19].addr[1] = 106; + state->CH_Ctrl[19].bit[1] = 0; + state->CH_Ctrl[19].val[1] = 1; + state->CH_Ctrl[19].addr[2] = 106; + state->CH_Ctrl[19].bit[2] = 1; + state->CH_Ctrl[19].val[2] = 1; + + state->CH_Ctrl[20].Ctrl_Num = TG_DIV_VAL ; + state->CH_Ctrl[20].size = 11 ; + state->CH_Ctrl[20].addr[0] = 109; + state->CH_Ctrl[20].bit[0] = 2; + state->CH_Ctrl[20].val[0] = 0; + state->CH_Ctrl[20].addr[1] = 109; + state->CH_Ctrl[20].bit[1] = 3; + state->CH_Ctrl[20].val[1] = 0; + state->CH_Ctrl[20].addr[2] = 109; + state->CH_Ctrl[20].bit[2] = 4; + state->CH_Ctrl[20].val[2] = 0; + state->CH_Ctrl[20].addr[3] = 109; + state->CH_Ctrl[20].bit[3] = 5; + state->CH_Ctrl[20].val[3] = 0; + state->CH_Ctrl[20].addr[4] = 109; + state->CH_Ctrl[20].bit[4] = 6; + state->CH_Ctrl[20].val[4] = 0; + state->CH_Ctrl[20].addr[5] = 109; + state->CH_Ctrl[20].bit[5] = 7; + state->CH_Ctrl[20].val[5] = 0; + state->CH_Ctrl[20].addr[6] = 108; + state->CH_Ctrl[20].bit[6] = 0; + state->CH_Ctrl[20].val[6] = 0; + state->CH_Ctrl[20].addr[7] = 108; + state->CH_Ctrl[20].bit[7] = 1; + state->CH_Ctrl[20].val[7] = 0; + state->CH_Ctrl[20].addr[8] = 108; + state->CH_Ctrl[20].bit[8] = 2; + state->CH_Ctrl[20].val[8] = 1; + state->CH_Ctrl[20].addr[9] = 108; + state->CH_Ctrl[20].bit[9] = 3; + state->CH_Ctrl[20].val[9] = 1; + state->CH_Ctrl[20].addr[10] = 108; + state->CH_Ctrl[20].bit[10] = 4; + state->CH_Ctrl[20].val[10] = 1; + + state->CH_Ctrl[21].Ctrl_Num = TG_VCO_BIAS ; + state->CH_Ctrl[21].size = 6 ; + state->CH_Ctrl[21].addr[0] = 106; + state->CH_Ctrl[21].bit[0] = 2; + state->CH_Ctrl[21].val[0] = 0; + state->CH_Ctrl[21].addr[1] = 106; + state->CH_Ctrl[21].bit[1] = 3; + state->CH_Ctrl[21].val[1] = 0; + state->CH_Ctrl[21].addr[2] = 106; + state->CH_Ctrl[21].bit[2] = 4; + state->CH_Ctrl[21].val[2] = 0; + state->CH_Ctrl[21].addr[3] = 106; + state->CH_Ctrl[21].bit[3] = 5; + state->CH_Ctrl[21].val[3] = 0; + state->CH_Ctrl[21].addr[4] = 106; + state->CH_Ctrl[21].bit[4] = 6; + state->CH_Ctrl[21].val[4] = 0; + state->CH_Ctrl[21].addr[5] = 106; + state->CH_Ctrl[21].bit[5] = 7; + state->CH_Ctrl[21].val[5] = 1; + + state->CH_Ctrl[22].Ctrl_Num = SEQ_EXTPOWERUP ; + state->CH_Ctrl[22].size = 1 ; + state->CH_Ctrl[22].addr[0] = 138; + state->CH_Ctrl[22].bit[0] = 4; + state->CH_Ctrl[22].val[0] = 1; + + state->CH_Ctrl[23].Ctrl_Num = OVERRIDE_2 ; + state->CH_Ctrl[23].size = 1 ; + state->CH_Ctrl[23].addr[0] = 17; + state->CH_Ctrl[23].bit[0] = 5; + state->CH_Ctrl[23].val[0] = 0; + + state->CH_Ctrl[24].Ctrl_Num = OVERRIDE_3 ; + state->CH_Ctrl[24].size = 1 ; + state->CH_Ctrl[24].addr[0] = 111; + state->CH_Ctrl[24].bit[0] = 3; + state->CH_Ctrl[24].val[0] = 0; + + state->CH_Ctrl[25].Ctrl_Num = OVERRIDE_4 ; + state->CH_Ctrl[25].size = 1 ; + state->CH_Ctrl[25].addr[0] = 112; + state->CH_Ctrl[25].bit[0] = 7; + state->CH_Ctrl[25].val[0] = 0; + + state->CH_Ctrl[26].Ctrl_Num = SEQ_FSM_PULSE ; + state->CH_Ctrl[26].size = 1 ; + state->CH_Ctrl[26].addr[0] = 136; + state->CH_Ctrl[26].bit[0] = 7; + state->CH_Ctrl[26].val[0] = 0; + + state->CH_Ctrl[27].Ctrl_Num = GPIO_4B ; + state->CH_Ctrl[27].size = 1 ; + state->CH_Ctrl[27].addr[0] = 149; + state->CH_Ctrl[27].bit[0] = 7; + state->CH_Ctrl[27].val[0] = 0; + + state->CH_Ctrl[28].Ctrl_Num = GPIO_3B ; + state->CH_Ctrl[28].size = 1 ; + state->CH_Ctrl[28].addr[0] = 149; + state->CH_Ctrl[28].bit[0] = 6; + state->CH_Ctrl[28].val[0] = 0; + + state->CH_Ctrl[29].Ctrl_Num = GPIO_4 ; + state->CH_Ctrl[29].size = 1 ; + state->CH_Ctrl[29].addr[0] = 149; + state->CH_Ctrl[29].bit[0] = 5; + state->CH_Ctrl[29].val[0] = 1; + + state->CH_Ctrl[30].Ctrl_Num = GPIO_3 ; + state->CH_Ctrl[30].size = 1 ; + state->CH_Ctrl[30].addr[0] = 149; + state->CH_Ctrl[30].bit[0] = 4; + state->CH_Ctrl[30].val[0] = 1; + + state->CH_Ctrl[31].Ctrl_Num = GPIO_1B ; + state->CH_Ctrl[31].size = 1 ; + state->CH_Ctrl[31].addr[0] = 149; + state->CH_Ctrl[31].bit[0] = 3; + state->CH_Ctrl[31].val[0] = 0; + + state->CH_Ctrl[32].Ctrl_Num = DAC_A_ENABLE ; + state->CH_Ctrl[32].size = 1 ; + state->CH_Ctrl[32].addr[0] = 93; + state->CH_Ctrl[32].bit[0] = 1; + state->CH_Ctrl[32].val[0] = 0; + + state->CH_Ctrl[33].Ctrl_Num = DAC_B_ENABLE ; + state->CH_Ctrl[33].size = 1 ; + state->CH_Ctrl[33].addr[0] = 93; + state->CH_Ctrl[33].bit[0] = 0; + state->CH_Ctrl[33].val[0] = 0; + + state->CH_Ctrl[34].Ctrl_Num = DAC_DIN_A ; + state->CH_Ctrl[34].size = 6 ; + state->CH_Ctrl[34].addr[0] = 92; + state->CH_Ctrl[34].bit[0] = 2; + state->CH_Ctrl[34].val[0] = 0; + state->CH_Ctrl[34].addr[1] = 92; + state->CH_Ctrl[34].bit[1] = 3; + state->CH_Ctrl[34].val[1] = 0; + state->CH_Ctrl[34].addr[2] = 92; + state->CH_Ctrl[34].bit[2] = 4; + state->CH_Ctrl[34].val[2] = 0; + state->CH_Ctrl[34].addr[3] = 92; + state->CH_Ctrl[34].bit[3] = 5; + state->CH_Ctrl[34].val[3] = 0; + state->CH_Ctrl[34].addr[4] = 92; + state->CH_Ctrl[34].bit[4] = 6; + state->CH_Ctrl[34].val[4] = 0; + state->CH_Ctrl[34].addr[5] = 92; + state->CH_Ctrl[34].bit[5] = 7; + state->CH_Ctrl[34].val[5] = 0; + + state->CH_Ctrl[35].Ctrl_Num = DAC_DIN_B ; + state->CH_Ctrl[35].size = 6 ; + state->CH_Ctrl[35].addr[0] = 93; + state->CH_Ctrl[35].bit[0] = 2; + state->CH_Ctrl[35].val[0] = 0; + state->CH_Ctrl[35].addr[1] = 93; + state->CH_Ctrl[35].bit[1] = 3; + state->CH_Ctrl[35].val[1] = 0; + state->CH_Ctrl[35].addr[2] = 93; + state->CH_Ctrl[35].bit[2] = 4; + state->CH_Ctrl[35].val[2] = 0; + state->CH_Ctrl[35].addr[3] = 93; + state->CH_Ctrl[35].bit[3] = 5; + state->CH_Ctrl[35].val[3] = 0; + state->CH_Ctrl[35].addr[4] = 93; + state->CH_Ctrl[35].bit[4] = 6; + state->CH_Ctrl[35].val[4] = 0; + state->CH_Ctrl[35].addr[5] = 93; + state->CH_Ctrl[35].bit[5] = 7; + state->CH_Ctrl[35].val[5] = 0; + +#ifdef _MXL_PRODUCTION + state->CH_Ctrl[36].Ctrl_Num = RFSYN_EN_DIV ; + state->CH_Ctrl[36].size = 1 ; + state->CH_Ctrl[36].addr[0] = 109; + state->CH_Ctrl[36].bit[0] = 1; + state->CH_Ctrl[36].val[0] = 1; + + state->CH_Ctrl[37].Ctrl_Num = RFSYN_DIVM ; + state->CH_Ctrl[37].size = 2 ; + state->CH_Ctrl[37].addr[0] = 112; + state->CH_Ctrl[37].bit[0] = 5; + state->CH_Ctrl[37].val[0] = 0; + state->CH_Ctrl[37].addr[1] = 112; + state->CH_Ctrl[37].bit[1] = 6; + state->CH_Ctrl[37].val[1] = 0; + + state->CH_Ctrl[38].Ctrl_Num = DN_BYPASS_AGC_I2C ; + state->CH_Ctrl[38].size = 1 ; + state->CH_Ctrl[38].addr[0] = 65; + state->CH_Ctrl[38].bit[0] = 1; + state->CH_Ctrl[38].val[0] = 0; +#endif + + return 0 ; +} + +static void InitTunerControls(struct dvb_frontend *fe) +{ + MXL5005_RegisterInit(fe); + MXL5005_ControlInit(fe); +#ifdef _MXL_INTERNAL + MXL5005_MXLControlInit(fe); +#endif +} + +static u16 MXL5005_TunerConfig(struct dvb_frontend *fe, + u8 Mode, /* 0: Analog Mode ; 1: Digital Mode */ + u8 IF_mode, /* for Analog Mode, 0: zero IF; 1: low IF */ + u32 Bandwidth, /* filter channel bandwidth (6, 7, 8) */ + u32 IF_out, /* Desired IF Out Frequency */ + u32 Fxtal, /* XTAL Frequency */ + u8 AGC_Mode, /* AGC Mode - Dual AGC: 0, Single AGC: 1 */ + u16 TOP, /* 0: Dual AGC; Value: take over point */ + u16 IF_OUT_LOAD, /* IF Out Load Resistor (200 / 300 Ohms) */ + u8 CLOCK_OUT, /* 0: turn off clk out; 1: turn on clock out */ + u8 DIV_OUT, /* 0: Div-1; 1: Div-4 */ + u8 CAPSELECT, /* 0: disable On-Chip pulling cap; 1: enable */ + u8 EN_RSSI, /* 0: disable RSSI; 1: enable RSSI */ + + /* Modulation Type; */ + /* 0 - Default; 1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */ + u8 Mod_Type, + + /* Tracking Filter */ + /* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */ + u8 TF_Type + ) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u16 status = 0; + + state->Mode = Mode; + state->IF_Mode = IF_mode; + state->Chan_Bandwidth = Bandwidth; + state->IF_OUT = IF_out; + state->Fxtal = Fxtal; + state->AGC_Mode = AGC_Mode; + state->TOP = TOP; + state->IF_OUT_LOAD = IF_OUT_LOAD; + state->CLOCK_OUT = CLOCK_OUT; + state->DIV_OUT = DIV_OUT; + state->CAPSELECT = CAPSELECT; + state->EN_RSSI = EN_RSSI; + state->Mod_Type = Mod_Type; + state->TF_Type = TF_Type; + + /* Initialize all the controls and registers */ + InitTunerControls(fe); + + /* Synthesizer LO frequency calculation */ + MXL_SynthIFLO_Calc(fe); + + return status; +} + +static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe) +{ + struct mxl5005s_state *state = fe->tuner_priv; + if (state->Mode == 1) /* Digital Mode */ + state->IF_LO = state->IF_OUT; + else /* Analog Mode */ { + if (state->IF_Mode == 0) /* Analog Zero IF mode */ + state->IF_LO = state->IF_OUT + 400000; + else /* Analog Low IF mode */ + state->IF_LO = state->IF_OUT + state->Chan_Bandwidth/2; + } +} + +static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe) +{ + struct mxl5005s_state *state = fe->tuner_priv; + + if (state->Mode == 1) /* Digital Mode */ { + /* remove 20.48MHz setting for 2.6.10 */ + state->RF_LO = state->RF_IN; + /* change for 2.6.6 */ + state->TG_LO = state->RF_IN - 750000; + } else /* Analog Mode */ { + if (state->IF_Mode == 0) /* Analog Zero IF mode */ { + state->RF_LO = state->RF_IN - 400000; + state->TG_LO = state->RF_IN - 1750000; + } else /* Analog Low IF mode */ { + state->RF_LO = state->RF_IN - state->Chan_Bandwidth/2; + state->TG_LO = state->RF_IN - + state->Chan_Bandwidth + 500000; + } + } +} + +static u16 MXL_OverwriteICDefault(struct dvb_frontend *fe) +{ + u16 status = 0; + + status += MXL_ControlWrite(fe, OVERRIDE_1, 1); + status += MXL_ControlWrite(fe, OVERRIDE_2, 1); + status += MXL_ControlWrite(fe, OVERRIDE_3, 1); + status += MXL_ControlWrite(fe, OVERRIDE_4, 1); + + return status; +} + +static u16 MXL_BlockInit(struct dvb_frontend *fe) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u16 status = 0; + + status += MXL_OverwriteICDefault(fe); + + /* Downconverter Control Dig Ana */ + status += MXL_ControlWrite(fe, DN_IQTN_AMP_CUT, state->Mode ? 1 : 0); + + /* Filter Control Dig Ana */ + status += MXL_ControlWrite(fe, BB_MODE, state->Mode ? 0 : 1); + status += MXL_ControlWrite(fe, BB_BUF, state->Mode ? 3 : 2); + status += MXL_ControlWrite(fe, BB_BUF_OA, state->Mode ? 1 : 0); + status += MXL_ControlWrite(fe, BB_IQSWAP, state->Mode ? 0 : 1); + status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 0); + + /* Initialize Low-Pass Filter */ + if (state->Mode) { /* Digital Mode */ + switch (state->Chan_Bandwidth) { + case 8000000: + status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 0); + break; + case 7000000: + status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 2); + break; + case 6000000: + status += MXL_ControlWrite(fe, + BB_DLPF_BANDSEL, 3); + break; + } + } else { /* Analog Mode */ + switch (state->Chan_Bandwidth) { + case 8000000: /* Low Zero */ + status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, + (state->IF_Mode ? 0 : 3)); + break; + case 7000000: + status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, + (state->IF_Mode ? 1 : 4)); + break; + case 6000000: + status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, + (state->IF_Mode ? 2 : 5)); + break; + } + } + + /* Charge Pump Control Dig Ana */ + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, state->Mode ? 5 : 8); + status += MXL_ControlWrite(fe, + RFSYN_EN_CHP_HIGAIN, state->Mode ? 1 : 1); + status += MXL_ControlWrite(fe, EN_CHP_LIN_B, state->Mode ? 0 : 0); + + /* AGC TOP Control */ + if (state->AGC_Mode == 0) /* Dual AGC */ { + status += MXL_ControlWrite(fe, AGC_IF, 15); + status += MXL_ControlWrite(fe, AGC_RF, 15); + } else /* Single AGC Mode Dig Ana */ + status += MXL_ControlWrite(fe, AGC_RF, state->Mode ? 15 : 12); + + if (state->TOP == 55) /* TOP == 5.5 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x0); + + if (state->TOP == 72) /* TOP == 7.2 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x1); + + if (state->TOP == 92) /* TOP == 9.2 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x2); + + if (state->TOP == 110) /* TOP == 11.0 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x3); + + if (state->TOP == 129) /* TOP == 12.9 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x4); + + if (state->TOP == 147) /* TOP == 14.7 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x5); + + if (state->TOP == 168) /* TOP == 16.8 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x6); + + if (state->TOP == 194) /* TOP == 19.4 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x7); + + if (state->TOP == 212) /* TOP == 21.2 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x9); + + if (state->TOP == 232) /* TOP == 23.2 */ + status += MXL_ControlWrite(fe, AGC_IF, 0xA); + + if (state->TOP == 252) /* TOP == 25.2 */ + status += MXL_ControlWrite(fe, AGC_IF, 0xB); + + if (state->TOP == 271) /* TOP == 27.1 */ + status += MXL_ControlWrite(fe, AGC_IF, 0xC); + + if (state->TOP == 292) /* TOP == 29.2 */ + status += MXL_ControlWrite(fe, AGC_IF, 0xD); + + if (state->TOP == 317) /* TOP == 31.7 */ + status += MXL_ControlWrite(fe, AGC_IF, 0xE); + + if (state->TOP == 349) /* TOP == 34.9 */ + status += MXL_ControlWrite(fe, AGC_IF, 0xF); + + /* IF Synthesizer Control */ + status += MXL_IFSynthInit(fe); + + /* IF UpConverter Control */ + if (state->IF_OUT_LOAD == 200) { + status += MXL_ControlWrite(fe, DRV_RES_SEL, 6); + status += MXL_ControlWrite(fe, I_DRIVER, 2); + } + if (state->IF_OUT_LOAD == 300) { + status += MXL_ControlWrite(fe, DRV_RES_SEL, 4); + status += MXL_ControlWrite(fe, I_DRIVER, 1); + } + + /* Anti-Alias Filtering Control + * initialise Anti-Aliasing Filter + */ + if (state->Mode) { /* Digital Mode */ + if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 6280000UL) { + status += MXL_ControlWrite(fe, EN_AAF, 1); + status += MXL_ControlWrite(fe, EN_3P, 1); + status += MXL_ControlWrite(fe, EN_AUX_3P, 1); + status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); + } + if ((state->IF_OUT == 36125000UL) || + (state->IF_OUT == 36150000UL)) { + status += MXL_ControlWrite(fe, EN_AAF, 1); + status += MXL_ControlWrite(fe, EN_3P, 1); + status += MXL_ControlWrite(fe, EN_AUX_3P, 1); + status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1); + } + if (state->IF_OUT > 36150000UL) { + status += MXL_ControlWrite(fe, EN_AAF, 0); + status += MXL_ControlWrite(fe, EN_3P, 1); + status += MXL_ControlWrite(fe, EN_AUX_3P, 1); + status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1); + } + } else { /* Analog Mode */ + if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 5000000UL) { + status += MXL_ControlWrite(fe, EN_AAF, 1); + status += MXL_ControlWrite(fe, EN_3P, 1); + status += MXL_ControlWrite(fe, EN_AUX_3P, 1); + status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); + } + if (state->IF_OUT > 5000000UL) { + status += MXL_ControlWrite(fe, EN_AAF, 0); + status += MXL_ControlWrite(fe, EN_3P, 0); + status += MXL_ControlWrite(fe, EN_AUX_3P, 0); + status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); + } + } + + /* Demod Clock Out */ + if (state->CLOCK_OUT) + status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 1); + else + status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 0); + + if (state->DIV_OUT == 1) + status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 1); + if (state->DIV_OUT == 0) + status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 0); + + /* Crystal Control */ + if (state->CAPSELECT) + status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 1); + else + status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 0); + + if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL) + status += MXL_ControlWrite(fe, IF_SEL_DBL, 1); + if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL) + status += MXL_ControlWrite(fe, IF_SEL_DBL, 0); + + if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL) + status += MXL_ControlWrite(fe, RFSYN_R_DIV, 3); + if (state->Fxtal > 22000000UL && state->Fxtal <= 32000000UL) + status += MXL_ControlWrite(fe, RFSYN_R_DIV, 0); + + /* Misc Controls */ + if (state->Mode == 0 && state->IF_Mode == 1) /* Analog LowIF mode */ + status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 0); + else + status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 1); + + /* status += MXL_ControlRead(fe, IF_DIVVAL, &IF_DIVVAL_Val); */ + + /* Set TG_R_DIV */ + status += MXL_ControlWrite(fe, TG_R_DIV, + MXL_Ceiling(state->Fxtal, 1000000)); + + /* Apply Default value to BB_INITSTATE_DLPF_TUNE */ + + /* RSSI Control */ + if (state->EN_RSSI) { + status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); + status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); + status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); + + /* RSSI reference point */ + status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2); + status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 3); + status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); + + /* TOP point */ + status += MXL_ControlWrite(fe, RFA_FLR, 0); + status += MXL_ControlWrite(fe, RFA_CEIL, 12); + } + + /* Modulation type bit settings + * Override the control values preset + */ + if (state->Mod_Type == MXL_DVBT) /* DVB-T Mode */ { + state->AGC_Mode = 1; /* Single AGC Mode */ + + /* Enable RSSI */ + status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); + status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); + status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); + + /* RSSI reference point */ + status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); + status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); + status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); + + /* TOP point */ + status += MXL_ControlWrite(fe, RFA_FLR, 2); + status += MXL_ControlWrite(fe, RFA_CEIL, 13); + if (state->IF_OUT <= 6280000UL) /* Low IF */ + status += MXL_ControlWrite(fe, BB_IQSWAP, 0); + else /* High IF */ + status += MXL_ControlWrite(fe, BB_IQSWAP, 1); + + } + if (state->Mod_Type == MXL_ATSC) /* ATSC Mode */ { + state->AGC_Mode = 1; /* Single AGC Mode */ + + /* Enable RSSI */ + status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); + status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); + status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); + + /* RSSI reference point */ + status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2); + status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 4); + status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); + + /* TOP point */ + status += MXL_ControlWrite(fe, RFA_FLR, 2); + status += MXL_ControlWrite(fe, RFA_CEIL, 13); + status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 1); + /* Low Zero */ + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5); + + if (state->IF_OUT <= 6280000UL) /* Low IF */ + status += MXL_ControlWrite(fe, BB_IQSWAP, 0); + else /* High IF */ + status += MXL_ControlWrite(fe, BB_IQSWAP, 1); + } + if (state->Mod_Type == MXL_QAM) /* QAM Mode */ { + state->Mode = MXL_DIGITAL_MODE; + + /* state->AGC_Mode = 1; */ /* Single AGC Mode */ + + /* Disable RSSI */ /* change here for v2.6.5 */ + status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); + status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); + status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); + + /* RSSI reference point */ + status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); + status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); + status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); + /* change here for v2.6.5 */ + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); + + if (state->IF_OUT <= 6280000UL) /* Low IF */ + status += MXL_ControlWrite(fe, BB_IQSWAP, 0); + else /* High IF */ + status += MXL_ControlWrite(fe, BB_IQSWAP, 1); + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2); + + } + if (state->Mod_Type == MXL_ANALOG_CABLE) { + /* Analog Cable Mode */ + /* state->Mode = MXL_DIGITAL_MODE; */ + + state->AGC_Mode = 1; /* Single AGC Mode */ + + /* Disable RSSI */ + status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); + status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); + status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); + /* change for 2.6.3 */ + status += MXL_ControlWrite(fe, AGC_IF, 1); + status += MXL_ControlWrite(fe, AGC_RF, 15); + status += MXL_ControlWrite(fe, BB_IQSWAP, 1); + } + + if (state->Mod_Type == MXL_ANALOG_OTA) { + /* Analog OTA Terrestrial mode add for 2.6.7 */ + /* state->Mode = MXL_ANALOG_MODE; */ + + /* Enable RSSI */ + status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); + status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); + status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); + + /* RSSI reference point */ + status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); + status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); + status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); + status += MXL_ControlWrite(fe, BB_IQSWAP, 1); + } + + /* RSSI disable */ + if (state->EN_RSSI == 0) { + status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); + status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); + status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); + } + + return status; +} + +static u16 MXL_IFSynthInit(struct dvb_frontend *fe) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u16 status = 0 ; + u32 Fref = 0 ; + u32 Kdbl, intModVal ; + u32 fracModVal ; + Kdbl = 2 ; + + if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL) + Kdbl = 2 ; + if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL) + Kdbl = 1 ; + + /* IF Synthesizer Control */ + if (state->Mode == 0 && state->IF_Mode == 1) /* Analog Low IF mode */ { + if (state->IF_LO == 41000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); + Fref = 328000000UL ; + } + if (state->IF_LO == 47000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 376000000UL ; + } + if (state->IF_LO == 54000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); + Fref = 324000000UL ; + } + if (state->IF_LO == 60000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 360000000UL ; + } + if (state->IF_LO == 39250000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); + Fref = 314000000UL ; + } + if (state->IF_LO == 39650000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); + Fref = 317200000UL ; + } + if (state->IF_LO == 40150000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); + Fref = 321200000UL ; + } + if (state->IF_LO == 40650000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); + Fref = 325200000UL ; + } + } + + if (state->Mode || (state->Mode == 0 && state->IF_Mode == 0)) { + if (state->IF_LO == 57000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 342000000UL ; + } + if (state->IF_LO == 44000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 352000000UL ; + } + if (state->IF_LO == 43750000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 350000000UL ; + } + if (state->IF_LO == 36650000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 366500000UL ; + } + if (state->IF_LO == 36150000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 361500000UL ; + } + if (state->IF_LO == 36000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 360000000UL ; + } + if (state->IF_LO == 35250000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 352500000UL ; + } + if (state->IF_LO == 34750000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 347500000UL ; + } + if (state->IF_LO == 6280000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 376800000UL ; + } + if (state->IF_LO == 5000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 360000000UL ; + } + if (state->IF_LO == 4500000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 360000000UL ; + } + if (state->IF_LO == 4570000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 365600000UL ; + } + if (state->IF_LO == 4000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x05); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 360000000UL ; + } + if (state->IF_LO == 57400000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 344400000UL ; + } + if (state->IF_LO == 44400000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 355200000UL ; + } + if (state->IF_LO == 44150000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 353200000UL ; + } + if (state->IF_LO == 37050000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 370500000UL ; + } + if (state->IF_LO == 36550000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 365500000UL ; + } + if (state->IF_LO == 36125000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 361250000UL ; + } + if (state->IF_LO == 6000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 360000000UL ; + } + if (state->IF_LO == 5400000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); + Fref = 324000000UL ; + } + if (state->IF_LO == 5380000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); + Fref = 322800000UL ; + } + if (state->IF_LO == 5200000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 374400000UL ; + } + if (state->IF_LO == 4900000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 352800000UL ; + } + if (state->IF_LO == 4400000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 352000000UL ; + } + if (state->IF_LO == 4063000UL) /* add for 2.6.8 */ { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x05); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 365670000UL ; + } + } + /* CHCAL_INT_MOD_IF */ + /* CHCAL_FRAC_MOD_IF */ + intModVal = Fref / (state->Fxtal * Kdbl/2); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_IF, intModVal); + + fracModVal = (2<<15)*(Fref/1000 - (state->Fxtal/1000 * Kdbl/2) * + intModVal); + + fracModVal = fracModVal / ((state->Fxtal * Kdbl/2)/1000); + status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_IF, fracModVal); + + return status ; +} + +static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u16 status = 0; + u32 divider_val, E3, E4, E5, E5A; + u32 Fmax, Fmin, FmaxBin, FminBin; + u32 Kdbl_RF = 2; + u32 tg_divval; + u32 tg_lo; + + u32 Fref_TG; + u32 Fvco; + + state->RF_IN = RF_Freq; + + MXL_SynthRFTGLO_Calc(fe); + + if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL) + Kdbl_RF = 2; + if (state->Fxtal > 22000000 && state->Fxtal <= 32000000) + Kdbl_RF = 1; + + /* Downconverter Controls + * Look-Up Table Implementation for: + * DN_POLY + * DN_RFGAIN + * DN_CAP_RFLPF + * DN_EN_VHFUHFBAR + * DN_GAIN_ADJUST + * Change the boundary reference from RF_IN to RF_LO + */ + if (state->RF_LO < 40000000UL) + return -1; + + if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) { + status += MXL_ControlWrite(fe, DN_POLY, 2); + status += MXL_ControlWrite(fe, DN_RFGAIN, 3); + status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 423); + status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); + status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 1); + } + if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) { + status += MXL_ControlWrite(fe, DN_POLY, 3); + status += MXL_ControlWrite(fe, DN_RFGAIN, 3); + status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 222); + status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); + status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 1); + } + if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) { + status += MXL_ControlWrite(fe, DN_POLY, 3); + status += MXL_ControlWrite(fe, DN_RFGAIN, 3); + status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 147); + status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); + status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 2); + } + if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) { + status += MXL_ControlWrite(fe, DN_POLY, 3); + status += MXL_ControlWrite(fe, DN_RFGAIN, 3); + status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 9); + status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); + status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 2); + } + if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) { + status += MXL_ControlWrite(fe, DN_POLY, 3); + status += MXL_ControlWrite(fe, DN_RFGAIN, 3); + status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); + status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); + status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); + } + if (state->RF_LO > 300000000UL && state->RF_LO <= 650000000UL) { + status += MXL_ControlWrite(fe, DN_POLY, 3); + status += MXL_ControlWrite(fe, DN_RFGAIN, 1); + status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); + status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 0); + status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); + } + if (state->RF_LO > 650000000UL && state->RF_LO <= 900000000UL) { + status += MXL_ControlWrite(fe, DN_POLY, 3); + status += MXL_ControlWrite(fe, DN_RFGAIN, 2); + status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); + status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 0); + status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); + } + if (state->RF_LO > 900000000UL) + return -1; + + /* DN_IQTNBUF_AMP */ + /* DN_IQTNGNBFBIAS_BST */ + if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 300000000UL && state->RF_LO <= 400000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 400000000UL && state->RF_LO <= 450000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 450000000UL && state->RF_LO <= 500000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 500000000UL && state->RF_LO <= 550000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 550000000UL && state->RF_LO <= 600000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 600000000UL && state->RF_LO <= 650000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 650000000UL && state->RF_LO <= 700000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 700000000UL && state->RF_LO <= 750000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 750000000UL && state->RF_LO <= 800000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 800000000UL && state->RF_LO <= 850000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 10); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 1); + } + if (state->RF_LO > 850000000UL && state->RF_LO <= 900000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 10); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 1); + } + + /* + * Set RF Synth and LO Path Control + * + * Look-Up table implementation for: + * RFSYN_EN_OUTMUX + * RFSYN_SEL_VCO_OUT + * RFSYN_SEL_VCO_HI + * RFSYN_SEL_DIVM + * RFSYN_RF_DIV_BIAS + * DN_SEL_FREQ + * + * Set divider_val, Fmax, Fmix to use in Equations + */ + FminBin = 28000000UL ; + FmaxBin = 42500000UL ; + if (state->RF_LO >= 40000000UL && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); + divider_val = 64 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 42500000UL ; + FmaxBin = 56000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); + divider_val = 64 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 56000000UL ; + FmaxBin = 85000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); + divider_val = 32 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 85000000UL ; + FmaxBin = 112000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); + divider_val = 32 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 112000000UL ; + FmaxBin = 170000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 2); + divider_val = 16 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 170000000UL ; + FmaxBin = 225000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 2); + divider_val = 16 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 225000000UL ; + FmaxBin = 300000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 4); + divider_val = 8 ; + Fmax = 340000000UL ; + Fmin = FminBin ; + } + FminBin = 300000000UL ; + FmaxBin = 340000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); + divider_val = 8 ; + Fmax = FmaxBin ; + Fmin = 225000000UL ; + } + FminBin = 340000000UL ; + FmaxBin = 450000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 2); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); + divider_val = 8 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 450000000UL ; + FmaxBin = 680000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 1); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); + divider_val = 4 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 680000000UL ; + FmaxBin = 900000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 1); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); + divider_val = 4 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + + /* CHCAL_INT_MOD_RF + * CHCAL_FRAC_MOD_RF + * RFSYN_LPF_R + * CHCAL_EN_INT_RF + */ + /* Equation E3 RFSYN_VCO_BIAS */ + E3 = (((Fmax-state->RF_LO)/1000)*32)/((Fmax-Fmin)/1000) + 8 ; + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, E3); + + /* Equation E4 CHCAL_INT_MOD_RF */ + E4 = (state->RF_LO*divider_val/1000)/(2*state->Fxtal*Kdbl_RF/1000); + MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, E4); + + /* Equation E5 CHCAL_FRAC_MOD_RF CHCAL_EN_INT_RF */ + E5 = ((2<<17)*(state->RF_LO/10000*divider_val - + (E4*(2*state->Fxtal*Kdbl_RF)/10000))) / + (2*state->Fxtal*Kdbl_RF/10000); + + status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5); + + /* Equation E5A RFSYN_LPF_R */ + E5A = (((Fmax - state->RF_LO)/1000)*4/((Fmax-Fmin)/1000)) + 1 ; + status += MXL_ControlWrite(fe, RFSYN_LPF_R, E5A); + + /* Euqation E5B CHCAL_EN_INIT_RF */ + status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, ((E5 == 0) ? 1 : 0)); + /*if (E5 == 0) + * status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, 1); + *else + * status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5); + */ + + /* + * Set TG Synth + * + * Look-Up table implementation for: + * TG_LO_DIVVAL + * TG_LO_SELVAL + * + * Set divider_val, Fmax, Fmix to use in Equations + */ + if (state->TG_LO < 33000000UL) + return -1; + + FminBin = 33000000UL ; + FmaxBin = 50000000UL ; + if (state->TG_LO >= FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x6); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x0); + divider_val = 36 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 50000000UL ; + FmaxBin = 67000000UL ; + if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x1); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x0); + divider_val = 24 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 67000000UL ; + FmaxBin = 100000000UL ; + if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0xC); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); + divider_val = 18 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 100000000UL ; + FmaxBin = 150000000UL ; + if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); + divider_val = 12 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 150000000UL ; + FmaxBin = 200000000UL ; + if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); + divider_val = 8 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 200000000UL ; + FmaxBin = 300000000UL ; + if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x3); + divider_val = 6 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 300000000UL ; + FmaxBin = 400000000UL ; + if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x3); + divider_val = 4 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 400000000UL ; + FmaxBin = 600000000UL ; + if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x7); + divider_val = 3 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 600000000UL ; + FmaxBin = 900000000UL ; + if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x7); + divider_val = 2 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + + /* TG_DIV_VAL */ + tg_divval = (state->TG_LO*divider_val/100000) * + (MXL_Ceiling(state->Fxtal, 1000000) * 100) / + (state->Fxtal/1000); + + status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval); + + if (state->TG_LO > 600000000UL) + status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval + 1); + + Fmax = 1800000000UL ; + Fmin = 1200000000UL ; + + /* prevent overflow of 32 bit unsigned integer, use + * following equation. Edit for v2.6.4 + */ + /* Fref_TF = Fref_TG * 1000 */ + Fref_TG = (state->Fxtal/1000) / MXL_Ceiling(state->Fxtal, 1000000); + + /* Fvco = Fvco/10 */ + Fvco = (state->TG_LO/10000) * divider_val * Fref_TG; + + tg_lo = (((Fmax/10 - Fvco)/100)*32) / ((Fmax-Fmin)/1000)+8; + + /* below equation is same as above but much harder to debug. + * + * static u32 MXL_GetXtalInt(u32 Xtal_Freq) + * { + * if ((Xtal_Freq % 1000000) == 0) + * return (Xtal_Freq / 10000); + * else + * return (((Xtal_Freq / 1000000) + 1)*100); + * } + * + * u32 Xtal_Int = MXL_GetXtalInt(state->Fxtal); + * tg_lo = ( ((Fmax/10000 * Xtal_Int)/100) - + * ((state->TG_LO/10000)*divider_val * + * (state->Fxtal/10000)/100) )*32/((Fmax-Fmin)/10000 * + * Xtal_Int/100) + 8; + */ + + status += MXL_ControlWrite(fe, TG_VCO_BIAS , tg_lo); + + /* add for 2.6.5 Special setting for QAM */ + if (state->Mod_Type == MXL_QAM) { + if (state->config->qam_gain != 0) + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, + state->config->qam_gain); + else if (state->RF_IN < 680000000) + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); + else + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2); + } + + /* Off Chip Tracking Filter Control */ + if (state->TF_Type == MXL_TF_OFF) { + /* Tracking Filter Off State; turn off all the banks */ + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 3, 1); /* Bank1 Off */ + status += MXL_SetGPIO(fe, 1, 1); /* Bank2 Off */ + status += MXL_SetGPIO(fe, 4, 1); /* Bank3 Off */ + } + + if (state->TF_Type == MXL_TF_C) /* Tracking Filter type C */ { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_ControlWrite(fe, DAC_DIN_A, 0); + + if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + status += MXL_SetGPIO(fe, 3, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 1); + } + if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 4, 1); + } + if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 4, 0); + } + if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 0); + } + if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_ControlWrite(fe, DAC_DIN_B, 29); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 0); + } + if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 0); + } + if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_ControlWrite(fe, DAC_DIN_B, 16); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 1); + } + if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_ControlWrite(fe, DAC_DIN_B, 7); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 1); + } + if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 1); + } + } + + if (state->TF_Type == MXL_TF_C_H) { + + /* Tracking Filter type C-H for Hauppauge only */ + status += MXL_ControlWrite(fe, DAC_DIN_A, 0); + + if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + } + if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 3, 0); + status += MXL_SetGPIO(fe, 1, 1); + } + if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 3, 0); + status += MXL_SetGPIO(fe, 1, 0); + } + if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 0); + } + if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 0); + } + if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 0); + } + if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + } + if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + } + if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + } + } + + if (state->TF_Type == MXL_TF_D) { /* Tracking Filter type D */ + + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + + if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + } + + if (state->TF_Type == MXL_TF_D_L) { + + /* Tracking Filter type D-L for Lumanate ONLY change 2.6.3 */ + status += MXL_ControlWrite(fe, DAC_DIN_A, 0); + + /* if UHF and terrestrial => Turn off Tracking Filter */ + if (state->RF_IN >= 471000000 && + (state->RF_IN - 471000000)%6000000 != 0) { + /* Turn off all the banks */ + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_ControlWrite(fe, AGC_IF, 10); + } else { + /* if VHF or cable => Turn on Tracking Filter */ + if (state->RF_IN >= 43000000 && + state->RF_IN < 140000000) { + + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 140000000 && + state->RF_IN < 240000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 240000000 && + state->RF_IN < 340000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 340000000 && + state->RF_IN < 430000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 430000000 && + state->RF_IN < 470000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 470000000 && + state->RF_IN < 570000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 570000000 && + state->RF_IN < 620000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 620000000 && + state->RF_IN < 760000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 760000000 && + state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + } + } + + if (state->TF_Type == MXL_TF_E) /* Tracking Filter type E */ { + + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + + if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + } + + if (state->TF_Type == MXL_TF_F) { + + /* Tracking Filter type F */ + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + + if (state->RF_IN >= 43000000 && state->RF_IN < 160000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 160000000 && state->RF_IN < 210000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 210000000 && state->RF_IN < 300000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 300000000 && state->RF_IN < 390000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 390000000 && state->RF_IN < 515000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 515000000 && state->RF_IN < 650000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 650000000 && state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + } + + if (state->TF_Type == MXL_TF_E_2) { + + /* Tracking Filter type E_2 */ + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + + if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + } + + if (state->TF_Type == MXL_TF_G) { + + /* Tracking Filter type G add for v2.6.8 */ + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + + if (state->RF_IN >= 50000000 && state->RF_IN < 190000000) { + + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 190000000 && state->RF_IN < 280000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 280000000 && state->RF_IN < 350000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 400000000 && state->RF_IN < 470000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 640000000 && state->RF_IN < 820000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 820000000 && state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + } + + if (state->TF_Type == MXL_TF_E_NA) { + + /* Tracking Filter type E-NA for Empia ONLY change for 2.6.8 */ + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + + /* if UHF and terrestrial=> Turn off Tracking Filter */ + if (state->RF_IN >= 471000000 && + (state->RF_IN - 471000000)%6000000 != 0) { + + /* Turn off all the banks */ + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + + /* 2.6.12 Turn on RSSI */ + status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); + status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); + status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); + + /* RSSI reference point */ + status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); + status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); + status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); + + /* following parameter is from analog OTA mode, + * can be change to seek better performance */ + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); + } else { + /* if VHF or Cable => Turn on Tracking Filter */ + + /* 2.6.12 Turn off RSSI */ + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); + + /* change back from above condition */ + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5); + + + if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { + + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + } + } + return status ; +} + +static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val) +{ + u16 status = 0; + + if (GPIO_Num == 1) + status += MXL_ControlWrite(fe, GPIO_1B, GPIO_Val ? 0 : 1); + + /* GPIO2 is not available */ + + if (GPIO_Num == 3) { + if (GPIO_Val == 1) { + status += MXL_ControlWrite(fe, GPIO_3, 0); + status += MXL_ControlWrite(fe, GPIO_3B, 0); + } + if (GPIO_Val == 0) { + status += MXL_ControlWrite(fe, GPIO_3, 1); + status += MXL_ControlWrite(fe, GPIO_3B, 1); + } + if (GPIO_Val == 3) { /* tri-state */ + status += MXL_ControlWrite(fe, GPIO_3, 0); + status += MXL_ControlWrite(fe, GPIO_3B, 1); + } + } + if (GPIO_Num == 4) { + if (GPIO_Val == 1) { + status += MXL_ControlWrite(fe, GPIO_4, 0); + status += MXL_ControlWrite(fe, GPIO_4B, 0); + } + if (GPIO_Val == 0) { + status += MXL_ControlWrite(fe, GPIO_4, 1); + status += MXL_ControlWrite(fe, GPIO_4B, 1); + } + if (GPIO_Val == 3) { /* tri-state */ + status += MXL_ControlWrite(fe, GPIO_4, 0); + status += MXL_ControlWrite(fe, GPIO_4B, 1); + } + } + + return status; +} + +static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value) +{ + u16 status = 0; + + /* Will write ALL Matching Control Name */ + /* Write Matching INIT Control */ + status += MXL_ControlWrite_Group(fe, ControlNum, value, 1); + /* Write Matching CH Control */ + status += MXL_ControlWrite_Group(fe, ControlNum, value, 2); +#ifdef _MXL_INTERNAL + /* Write Matching MXL Control */ + status += MXL_ControlWrite_Group(fe, ControlNum, value, 3); +#endif + return status; +} + +static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, + u32 value, u16 controlGroup) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u16 i, j, k; + u32 highLimit; + u32 ctrlVal; + + if (controlGroup == 1) /* Initial Control */ { + + for (i = 0; i < state->Init_Ctrl_Num; i++) { + + if (controlNum == state->Init_Ctrl[i].Ctrl_Num) { + + highLimit = 1 << state->Init_Ctrl[i].size; + if (value < highLimit) { + for (j = 0; j < state->Init_Ctrl[i].size; j++) { + state->Init_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); + MXL_RegWriteBit(fe, (u8)(state->Init_Ctrl[i].addr[j]), + (u8)(state->Init_Ctrl[i].bit[j]), + (u8)((value>>j) & 0x01)); + } + ctrlVal = 0; + for (k = 0; k < state->Init_Ctrl[i].size; k++) + ctrlVal += state->Init_Ctrl[i].val[k] * (1 << k); + } else + return -1; + } + } + } + if (controlGroup == 2) /* Chan change Control */ { + + for (i = 0; i < state->CH_Ctrl_Num; i++) { + + if (controlNum == state->CH_Ctrl[i].Ctrl_Num) { + + highLimit = 1 << state->CH_Ctrl[i].size; + if (value < highLimit) { + for (j = 0; j < state->CH_Ctrl[i].size; j++) { + state->CH_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); + MXL_RegWriteBit(fe, (u8)(state->CH_Ctrl[i].addr[j]), + (u8)(state->CH_Ctrl[i].bit[j]), + (u8)((value>>j) & 0x01)); + } + ctrlVal = 0; + for (k = 0; k < state->CH_Ctrl[i].size; k++) + ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k); + } else + return -1; + } + } + } +#ifdef _MXL_INTERNAL + if (controlGroup == 3) /* Maxlinear Control */ { + + for (i = 0; i < state->MXL_Ctrl_Num; i++) { + + if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) { + + highLimit = (1 << state->MXL_Ctrl[i].size); + if (value < highLimit) { + for (j = 0; j < state->MXL_Ctrl[i].size; j++) { + state->MXL_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); + MXL_RegWriteBit(fe, (u8)(state->MXL_Ctrl[i].addr[j]), + (u8)(state->MXL_Ctrl[i].bit[j]), + (u8)((value>>j) & 0x01)); + } + ctrlVal = 0; + for (k = 0; k < state->MXL_Ctrl[i].size; k++) + ctrlVal += state-> + MXL_Ctrl[i].val[k] * + (1 << k); + } else + return -1; + } + } + } +#endif + return 0 ; /* successful return */ +} + +static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal) +{ + struct mxl5005s_state *state = fe->tuner_priv; + int i ; + + for (i = 0; i < 104; i++) { + if (RegNum == state->TunerRegs[i].Reg_Num) { + *RegVal = (u8)(state->TunerRegs[i].Reg_Val); + return 0; + } + } + + return 1; +} + +static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u32 ctrlVal ; + u16 i, k ; + + for (i = 0; i < state->Init_Ctrl_Num ; i++) { + + if (controlNum == state->Init_Ctrl[i].Ctrl_Num) { + + ctrlVal = 0; + for (k = 0; k < state->Init_Ctrl[i].size; k++) + ctrlVal += state->Init_Ctrl[i].val[k] * (1<CH_Ctrl_Num ; i++) { + + if (controlNum == state->CH_Ctrl[i].Ctrl_Num) { + + ctrlVal = 0; + for (k = 0; k < state->CH_Ctrl[i].size; k++) + ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k); + *value = ctrlVal; + return 0; + + } + } + +#ifdef _MXL_INTERNAL + for (i = 0; i < state->MXL_Ctrl_Num ; i++) { + + if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) { + + ctrlVal = 0; + for (k = 0; k < state->MXL_Ctrl[i].size; k++) + ctrlVal += state->MXL_Ctrl[i].val[k] * (1<tuner_priv; + int i ; + + const u8 AND_MAP[8] = { + 0xFE, 0xFD, 0xFB, 0xF7, + 0xEF, 0xDF, 0xBF, 0x7F } ; + + const u8 OR_MAP[8] = { + 0x01, 0x02, 0x04, 0x08, + 0x10, 0x20, 0x40, 0x80 } ; + + for (i = 0; i < state->TunerRegs_Num; i++) { + if (state->TunerRegs[i].Reg_Num == address) { + if (bitVal) + state->TunerRegs[i].Reg_Val |= OR_MAP[bit]; + else + state->TunerRegs[i].Reg_Val &= AND_MAP[bit]; + break ; + } + } +} + +static u32 MXL_Ceiling(u32 value, u32 resolution) +{ + return value / resolution + (value % resolution > 0 ? 1 : 0); +} + +/* Retrieve the Initialzation Registers */ +static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum, + u8 *RegVal, int *count) +{ + u16 status = 0; + int i ; + + u8 RegAddr[] = { + 11, 12, 13, 22, 32, 43, 44, 53, 56, 59, 73, + 76, 77, 91, 134, 135, 137, 147, + 156, 166, 167, 168, 25 }; + + *count = ARRAY_SIZE(RegAddr); + + status += MXL_BlockInit(fe); + + for (i = 0 ; i < *count; i++) { + RegNum[i] = RegAddr[i]; + status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); + } + + return status; +} + +static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal, + int *count) +{ + u16 status = 0; + int i ; + +/* add 77, 166, 167, 168 register for 2.6.12 */ +#ifdef _MXL_PRODUCTION + u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 65, 68, 69, 70, 73, 92, 93, 106, + 107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ; +#else + u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 68, 69, 70, 73, 92, 93, 106, + 107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ; + /* + u8 RegAddr[171]; + for (i = 0; i <= 170; i++) + RegAddr[i] = i; + */ +#endif + + *count = ARRAY_SIZE(RegAddr); + + for (i = 0 ; i < *count; i++) { + RegNum[i] = RegAddr[i]; + status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); + } + + return status; +} + +static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum, + u8 *RegVal, int *count) +{ + u16 status = 0; + int i; + + u8 RegAddr[] = {43, 136}; + + *count = ARRAY_SIZE(RegAddr); + + for (i = 0; i < *count; i++) { + RegNum[i] = RegAddr[i]; + status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); + } + + return status; +} + +static u16 MXL_GetMasterControl(u8 *MasterReg, int state) +{ + if (state == 1) /* Load_Start */ + *MasterReg = 0xF3; + if (state == 2) /* Power_Down */ + *MasterReg = 0x41; + if (state == 3) /* Synth_Reset */ + *MasterReg = 0xB1; + if (state == 4) /* Seq_Off */ + *MasterReg = 0xF1; + + return 0; +} + +#ifdef _MXL_PRODUCTION +static u16 MXL_VCORange_Test(struct dvb_frontend *fe, int VCO_Range) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u16 status = 0 ; + + if (VCO_Range == 1) { + status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); + if (state->Mode == 0 && state->IF_Mode == 1) { + /* Analog Low IF Mode */ + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 180224); + } + if (state->Mode == 0 && state->IF_Mode == 0) { + /* Analog Zero IF Mode */ + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 222822); + } + if (state->Mode == 1) /* Digital Mode */ { + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 229376); + } + } + + if (VCO_Range == 2) { + status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41); + if (state->Mode == 0 && state->IF_Mode == 1) { + /* Analog Low IF Mode */ + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 206438); + } + if (state->Mode == 0 && state->IF_Mode == 0) { + /* Analog Zero IF Mode */ + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 206438); + } + if (state->Mode == 1) /* Digital Mode */ { + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 16384); + } + } + + if (VCO_Range == 3) { + status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); + if (state->Mode == 0 && state->IF_Mode == 1) { + /* Analog Low IF Mode */ + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 173670); + } + if (state->Mode == 0 && state->IF_Mode == 0) { + /* Analog Zero IF Mode */ + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 173670); + } + if (state->Mode == 1) /* Digital Mode */ { + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 245760); + } + } + + if (VCO_Range == 4) { + status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); + if (state->Mode == 0 && state->IF_Mode == 1) { + /* Analog Low IF Mode */ + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 206438); + } + if (state->Mode == 0 && state->IF_Mode == 0) { + /* Analog Zero IF Mode */ + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 206438); + } + if (state->Mode == 1) /* Digital Mode */ { + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 212992); + } + } + + return status; +} + +static u16 MXL_Hystersis_Test(struct dvb_frontend *fe, int Hystersis) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u16 status = 0; + + if (Hystersis == 1) + status += MXL_ControlWrite(fe, DN_BYPASS_AGC_I2C, 1); + + return status; +} +#endif +/* End: Reference driver code found in the Realtek driver that + * is copyright MaxLinear */ + +/* ---------------------------------------------------------------- + * Begin: Everything after here is new code to adapt the + * proprietary Realtek driver into a Linux API tuner. + * Copyright (C) 2008 Steven Toth + */ +static int mxl5005s_reset(struct dvb_frontend *fe) +{ + struct mxl5005s_state *state = fe->tuner_priv; + int ret = 0; + + u8 buf[2] = { 0xff, 0x00 }; + struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0, + .buf = buf, .len = 2 }; + + dprintk(2, "%s()\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mxl5005s I2C reset failed\n"); + ret = -EREMOTEIO; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return ret; +} + +/* Write a single byte to a single reg, latch the value if required by + * following the transaction with the latch byte. + */ +static int mxl5005s_writereg(struct dvb_frontend *fe, u8 reg, u8 val, int latch) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u8 buf[3] = { reg, val, MXL5005S_LATCH_BYTE }; + struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0, + .buf = buf, .len = 3 }; + + if (latch == 0) + msg.len = 2; + + dprintk(2, "%s(0x%x, 0x%x, 0x%x)\n", __func__, reg, val, msg.addr); + + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mxl5005s I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable, + u8 *datatable, u8 len) +{ + int ret = 0, i; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + for (i = 0 ; i < len-1; i++) { + ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 0); + if (ret < 0) + break; + } + + ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 1); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return ret; +} + +static int mxl5005s_init(struct dvb_frontend *fe) +{ + struct mxl5005s_state *state = fe->tuner_priv; + + dprintk(1, "%s()\n", __func__); + state->current_mode = MXL_QAM; + return mxl5005s_reconfigure(fe, MXL_QAM, MXL5005S_BANDWIDTH_6MHZ); +} + +static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type, + u32 bandwidth) +{ + struct mxl5005s_state *state = fe->tuner_priv; + + u8 AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; + u8 ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; + int TableLen; + + dprintk(1, "%s(type=%d, bw=%d)\n", __func__, mod_type, bandwidth); + + mxl5005s_reset(fe); + + /* Tuner initialization stage 0 */ + MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET); + AddrTable[0] = MASTER_CONTROL_ADDR; + ByteTable[0] |= state->config->AgcMasterByte; + + mxl5005s_writeregs(fe, AddrTable, ByteTable, 1); + + mxl5005s_AssignTunerMode(fe, mod_type, bandwidth); + + /* Tuner initialization stage 1 */ + MXL_GetInitRegister(fe, AddrTable, ByteTable, &TableLen); + + mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); + + return 0; +} + +static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type, + u32 bandwidth) +{ + struct mxl5005s_state *state = fe->tuner_priv; + struct mxl5005s_config *c = state->config; + + InitTunerControls(fe); + + /* Set MxL5005S parameters. */ + MXL5005_TunerConfig( + fe, + c->mod_mode, + c->if_mode, + bandwidth, + c->if_freq, + c->xtal_freq, + c->agc_mode, + c->top, + c->output_load, + c->clock_out, + c->div_out, + c->cap_select, + c->rssi_enable, + mod_type, + c->tracking_filter); + + return 0; +} + +static int mxl5005s_set_params(struct dvb_frontend *fe) +{ + struct mxl5005s_state *state = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; + u32 req_mode, req_bw = 0; + int ret; + + dprintk(1, "%s()\n", __func__); + + switch (delsys) { + case SYS_ATSC: + req_mode = MXL_ATSC; + req_bw = MXL5005S_BANDWIDTH_6MHZ; + break; + case SYS_DVBC_ANNEX_B: + req_mode = MXL_QAM; + req_bw = MXL5005S_BANDWIDTH_6MHZ; + break; + default: /* Assume DVB-T */ + req_mode = MXL_DVBT; + switch (bw) { + case 6000000: + req_bw = MXL5005S_BANDWIDTH_6MHZ; + break; + case 7000000: + req_bw = MXL5005S_BANDWIDTH_7MHZ; + break; + case 8000000: + case 0: + req_bw = MXL5005S_BANDWIDTH_8MHZ; + break; + default: + return -EINVAL; + } + } + + /* Change tuner for new modulation type if reqd */ + if (req_mode != state->current_mode || + req_bw != state->Chan_Bandwidth) { + state->current_mode = req_mode; + ret = mxl5005s_reconfigure(fe, req_mode, req_bw); + + } else + ret = 0; + + if (ret == 0) { + dprintk(1, "%s() freq=%d\n", __func__, c->frequency); + ret = mxl5005s_SetRfFreqHz(fe, c->frequency); + } + + return ret; +} + +static int mxl5005s_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mxl5005s_state *state = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + + *frequency = state->RF_IN; + + return 0; +} + +static int mxl5005s_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mxl5005s_state *state = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + + *bandwidth = state->Chan_Bandwidth; + + return 0; +} + +static int mxl5005s_release(struct dvb_frontend *fe) +{ + dprintk(1, "%s()\n", __func__); + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops mxl5005s_tuner_ops = { + .info = { + .name = "MaxLinear MXL5005S", + .frequency_min = 48000000, + .frequency_max = 860000000, + .frequency_step = 50000, + }, + + .release = mxl5005s_release, + .init = mxl5005s_init, + + .set_params = mxl5005s_set_params, + .get_frequency = mxl5005s_get_frequency, + .get_bandwidth = mxl5005s_get_bandwidth, +}; + +struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mxl5005s_config *config) +{ + struct mxl5005s_state *state = NULL; + dprintk(1, "%s()\n", __func__); + + state = kzalloc(sizeof(struct mxl5005s_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + state->frontend = fe; + state->config = config; + state->i2c = i2c; + + printk(KERN_INFO "MXL5005S: Attached at address 0x%02x\n", + config->i2c_address); + + memcpy(&fe->ops.tuner_ops, &mxl5005s_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = state; + return fe; +} +EXPORT_SYMBOL(mxl5005s_attach); + +MODULE_DESCRIPTION("MaxLinear MXL5005S silicon tuner driver"); +MODULE_AUTHOR("Steven Toth"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/mxl5005s.h b/drivers/media/tuners/mxl5005s.h new file mode 100644 index 000000000000..fc8a1ffc53b4 --- /dev/null +++ b/drivers/media/tuners/mxl5005s.h @@ -0,0 +1,135 @@ +/* + MaxLinear MXL5005S VSB/QAM/DVBT tuner driver + + Copyright (C) 2008 MaxLinear + Copyright (C) 2008 Steven Toth + + 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 __MXL5005S_H +#define __MXL5005S_H + +#include +#include "dvb_frontend.h" + +struct mxl5005s_config { + + /* 7 bit i2c address */ + u8 i2c_address; + +#define IF_FREQ_4570000HZ 4570000 +#define IF_FREQ_4571429HZ 4571429 +#define IF_FREQ_5380000HZ 5380000 +#define IF_FREQ_36000000HZ 36000000 +#define IF_FREQ_36125000HZ 36125000 +#define IF_FREQ_36166667HZ 36166667 +#define IF_FREQ_44000000HZ 44000000 + u32 if_freq; + +#define CRYSTAL_FREQ_4000000HZ 4000000 +#define CRYSTAL_FREQ_16000000HZ 16000000 +#define CRYSTAL_FREQ_25000000HZ 25000000 +#define CRYSTAL_FREQ_28800000HZ 28800000 + u32 xtal_freq; + +#define MXL_DUAL_AGC 0 +#define MXL_SINGLE_AGC 1 + u8 agc_mode; + +#define MXL_TF_DEFAULT 0 +#define MXL_TF_OFF 1 +#define MXL_TF_C 2 +#define MXL_TF_C_H 3 +#define MXL_TF_D 4 +#define MXL_TF_D_L 5 +#define MXL_TF_E 6 +#define MXL_TF_F 7 +#define MXL_TF_E_2 8 +#define MXL_TF_E_NA 9 +#define MXL_TF_G 10 + u8 tracking_filter; + +#define MXL_RSSI_DISABLE 0 +#define MXL_RSSI_ENABLE 1 + u8 rssi_enable; + +#define MXL_CAP_SEL_DISABLE 0 +#define MXL_CAP_SEL_ENABLE 1 + u8 cap_select; + +#define MXL_DIV_OUT_1 0 +#define MXL_DIV_OUT_4 1 + u8 div_out; + +#define MXL_CLOCK_OUT_DISABLE 0 +#define MXL_CLOCK_OUT_ENABLE 1 + u8 clock_out; + +#define MXL5005S_IF_OUTPUT_LOAD_200_OHM 200 +#define MXL5005S_IF_OUTPUT_LOAD_300_OHM 300 + u32 output_load; + +#define MXL5005S_TOP_5P5 55 +#define MXL5005S_TOP_7P2 72 +#define MXL5005S_TOP_9P2 92 +#define MXL5005S_TOP_11P0 110 +#define MXL5005S_TOP_12P9 129 +#define MXL5005S_TOP_14P7 147 +#define MXL5005S_TOP_16P8 168 +#define MXL5005S_TOP_19P4 194 +#define MXL5005S_TOP_21P2 212 +#define MXL5005S_TOP_23P2 232 +#define MXL5005S_TOP_25P2 252 +#define MXL5005S_TOP_27P1 271 +#define MXL5005S_TOP_29P2 292 +#define MXL5005S_TOP_31P7 317 +#define MXL5005S_TOP_34P9 349 + u32 top; + +#define MXL_ANALOG_MODE 0 +#define MXL_DIGITAL_MODE 1 + u8 mod_mode; + +#define MXL_ZERO_IF 0 +#define MXL_LOW_IF 1 + u8 if_mode; + + /* Some boards need to override the built-in logic for determining + the gain when in QAM mode (the HVR-1600 is one such case) */ + u8 qam_gain; + + /* Stuff I don't know what to do with */ + u8 AgcMasterByte; +}; + +#if defined(CONFIG_MEDIA_TUNER_MXL5005S) || \ + (defined(CONFIG_MEDIA_TUNER_MXL5005S_MODULE) && defined(MODULE)) +extern struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mxl5005s_config *config); +#else +static inline struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mxl5005s_config *config) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_TUNER_MXL5005S */ + +#endif /* __MXL5005S_H */ + diff --git a/drivers/media/tuners/mxl5007t.c b/drivers/media/tuners/mxl5007t.c new file mode 100644 index 000000000000..69e453ef0a1a --- /dev/null +++ b/drivers/media/tuners/mxl5007t.c @@ -0,0 +1,928 @@ +/* + * mxl5007t.c - driver for the MaxLinear MxL5007T silicon tuner + * + * Copyright (C) 2008, 2009 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 +#include +#include +#include "tuner-i2c.h" +#include "mxl5007t.h" + +static DEFINE_MUTEX(mxl5007t_list_mutex); +static LIST_HEAD(hybrid_tuner_instance_list); + +static int mxl5007t_debug; +module_param_named(debug, mxl5007t_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debug level"); + +/* ------------------------------------------------------------------------- */ + +#define mxl_printk(kern, fmt, arg...) \ + printk(kern "%s: " fmt "\n", __func__, ##arg) + +#define mxl_err(fmt, arg...) \ + mxl_printk(KERN_ERR, "%d: " fmt, __LINE__, ##arg) + +#define mxl_warn(fmt, arg...) \ + mxl_printk(KERN_WARNING, fmt, ##arg) + +#define mxl_info(fmt, arg...) \ + mxl_printk(KERN_INFO, fmt, ##arg) + +#define mxl_debug(fmt, arg...) \ +({ \ + if (mxl5007t_debug) \ + mxl_printk(KERN_DEBUG, fmt, ##arg); \ +}) + +#define mxl_fail(ret) \ +({ \ + int __ret; \ + __ret = (ret < 0); \ + if (__ret) \ + mxl_printk(KERN_ERR, "error %d on line %d", \ + ret, __LINE__); \ + __ret; \ +}) + +/* ------------------------------------------------------------------------- */ + +#define MHz 1000000 + +enum mxl5007t_mode { + MxL_MODE_ISDBT = 0, + MxL_MODE_DVBT = 1, + MxL_MODE_ATSC = 2, + MxL_MODE_CABLE = 0x10, +}; + +enum mxl5007t_chip_version { + MxL_UNKNOWN_ID = 0x00, + MxL_5007_V1_F1 = 0x11, + MxL_5007_V1_F2 = 0x12, + MxL_5007_V4 = 0x14, + MxL_5007_V2_100_F1 = 0x21, + MxL_5007_V2_100_F2 = 0x22, + MxL_5007_V2_200_F1 = 0x23, + MxL_5007_V2_200_F2 = 0x24, +}; + +struct reg_pair_t { + u8 reg; + u8 val; +}; + +/* ------------------------------------------------------------------------- */ + +static struct reg_pair_t init_tab[] = { + { 0x02, 0x06 }, + { 0x03, 0x48 }, + { 0x05, 0x04 }, + { 0x06, 0x10 }, + { 0x2e, 0x15 }, /* OVERRIDE */ + { 0x30, 0x10 }, /* OVERRIDE */ + { 0x45, 0x58 }, /* OVERRIDE */ + { 0x48, 0x19 }, /* OVERRIDE */ + { 0x52, 0x03 }, /* OVERRIDE */ + { 0x53, 0x44 }, /* OVERRIDE */ + { 0x6a, 0x4b }, /* OVERRIDE */ + { 0x76, 0x00 }, /* OVERRIDE */ + { 0x78, 0x18 }, /* OVERRIDE */ + { 0x7a, 0x17 }, /* OVERRIDE */ + { 0x85, 0x06 }, /* OVERRIDE */ + { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ + { 0, 0 } +}; + +static struct reg_pair_t init_tab_cable[] = { + { 0x02, 0x06 }, + { 0x03, 0x48 }, + { 0x05, 0x04 }, + { 0x06, 0x10 }, + { 0x09, 0x3f }, + { 0x0a, 0x3f }, + { 0x0b, 0x3f }, + { 0x2e, 0x15 }, /* OVERRIDE */ + { 0x30, 0x10 }, /* OVERRIDE */ + { 0x45, 0x58 }, /* OVERRIDE */ + { 0x48, 0x19 }, /* OVERRIDE */ + { 0x52, 0x03 }, /* OVERRIDE */ + { 0x53, 0x44 }, /* OVERRIDE */ + { 0x6a, 0x4b }, /* OVERRIDE */ + { 0x76, 0x00 }, /* OVERRIDE */ + { 0x78, 0x18 }, /* OVERRIDE */ + { 0x7a, 0x17 }, /* OVERRIDE */ + { 0x85, 0x06 }, /* OVERRIDE */ + { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ + { 0, 0 } +}; + +/* ------------------------------------------------------------------------- */ + +static struct reg_pair_t reg_pair_rftune[] = { + { 0x0f, 0x00 }, /* abort tune */ + { 0x0c, 0x15 }, + { 0x0d, 0x40 }, + { 0x0e, 0x0e }, + { 0x1f, 0x87 }, /* OVERRIDE */ + { 0x20, 0x1f }, /* OVERRIDE */ + { 0x21, 0x87 }, /* OVERRIDE */ + { 0x22, 0x1f }, /* OVERRIDE */ + { 0x80, 0x01 }, /* freq dependent */ + { 0x0f, 0x01 }, /* start tune */ + { 0, 0 } +}; + +/* ------------------------------------------------------------------------- */ + +struct mxl5007t_state { + struct list_head hybrid_tuner_instance_list; + struct tuner_i2c_props i2c_props; + + struct mutex lock; + + struct mxl5007t_config *config; + + enum mxl5007t_chip_version chip_id; + + struct reg_pair_t tab_init[ARRAY_SIZE(init_tab)]; + struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)]; + struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)]; + + enum mxl5007t_if_freq if_freq; + + u32 frequency; + u32 bandwidth; +}; + +/* ------------------------------------------------------------------------- */ + +/* called by _init and _rftun to manipulate the register arrays */ + +static void set_reg_bits(struct reg_pair_t *reg_pair, u8 reg, u8 mask, u8 val) +{ + unsigned int i = 0; + + while (reg_pair[i].reg || reg_pair[i].val) { + if (reg_pair[i].reg == reg) { + reg_pair[i].val &= ~mask; + reg_pair[i].val |= val; + } + i++; + + } + return; +} + +static void copy_reg_bits(struct reg_pair_t *reg_pair1, + struct reg_pair_t *reg_pair2) +{ + unsigned int i, j; + + i = j = 0; + + while (reg_pair1[i].reg || reg_pair1[i].val) { + while (reg_pair2[j].reg || reg_pair2[j].val) { + if (reg_pair1[i].reg != reg_pair2[j].reg) { + j++; + continue; + } + reg_pair2[j].val = reg_pair1[i].val; + break; + } + i++; + } + return; +} + +/* ------------------------------------------------------------------------- */ + +static void mxl5007t_set_mode_bits(struct mxl5007t_state *state, + enum mxl5007t_mode mode, + s32 if_diff_out_level) +{ + switch (mode) { + case MxL_MODE_ATSC: + set_reg_bits(state->tab_init, 0x06, 0x1f, 0x12); + break; + case MxL_MODE_DVBT: + set_reg_bits(state->tab_init, 0x06, 0x1f, 0x11); + break; + case MxL_MODE_ISDBT: + set_reg_bits(state->tab_init, 0x06, 0x1f, 0x10); + break; + case MxL_MODE_CABLE: + set_reg_bits(state->tab_init_cable, 0x09, 0xff, 0xc1); + set_reg_bits(state->tab_init_cable, 0x0a, 0xff, + 8 - if_diff_out_level); + set_reg_bits(state->tab_init_cable, 0x0b, 0xff, 0x17); + break; + default: + mxl_fail(-EINVAL); + } + return; +} + +static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state, + enum mxl5007t_if_freq if_freq, + int invert_if) +{ + u8 val; + + switch (if_freq) { + case MxL_IF_4_MHZ: + val = 0x00; + break; + case MxL_IF_4_5_MHZ: + val = 0x02; + break; + case MxL_IF_4_57_MHZ: + val = 0x03; + break; + case MxL_IF_5_MHZ: + val = 0x04; + break; + case MxL_IF_5_38_MHZ: + val = 0x05; + break; + case MxL_IF_6_MHZ: + val = 0x06; + break; + case MxL_IF_6_28_MHZ: + val = 0x07; + break; + case MxL_IF_9_1915_MHZ: + val = 0x08; + break; + case MxL_IF_35_25_MHZ: + val = 0x09; + break; + case MxL_IF_36_15_MHZ: + val = 0x0a; + break; + case MxL_IF_44_MHZ: + val = 0x0b; + break; + default: + mxl_fail(-EINVAL); + return; + } + set_reg_bits(state->tab_init, 0x02, 0x0f, val); + + /* set inverted IF or normal IF */ + set_reg_bits(state->tab_init, 0x02, 0x10, invert_if ? 0x10 : 0x00); + + state->if_freq = if_freq; + + return; +} + +static void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state, + enum mxl5007t_xtal_freq xtal_freq) +{ + switch (xtal_freq) { + case MxL_XTAL_16_MHZ: + /* select xtal freq & ref freq */ + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x00); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x00); + break; + case MxL_XTAL_20_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x10); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x01); + break; + case MxL_XTAL_20_25_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x20); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x02); + break; + case MxL_XTAL_20_48_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x30); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x03); + break; + case MxL_XTAL_24_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x40); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x04); + break; + case MxL_XTAL_25_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x50); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x05); + break; + case MxL_XTAL_25_14_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x60); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x06); + break; + case MxL_XTAL_27_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x70); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x07); + break; + case MxL_XTAL_28_8_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x80); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x08); + break; + case MxL_XTAL_32_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x90); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x09); + break; + case MxL_XTAL_40_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0xa0); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0a); + break; + case MxL_XTAL_44_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0xb0); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0b); + break; + case MxL_XTAL_48_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0xc0); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0c); + break; + case MxL_XTAL_49_3811_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0xd0); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0d); + break; + default: + mxl_fail(-EINVAL); + return; + } + + return; +} + +static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state, + enum mxl5007t_mode mode) +{ + struct mxl5007t_config *cfg = state->config; + + memcpy(&state->tab_init, &init_tab, sizeof(init_tab)); + memcpy(&state->tab_init_cable, &init_tab_cable, sizeof(init_tab_cable)); + + mxl5007t_set_mode_bits(state, mode, cfg->if_diff_out_level); + mxl5007t_set_if_freq_bits(state, cfg->if_freq_hz, cfg->invert_if); + mxl5007t_set_xtal_freq_bits(state, cfg->xtal_freq_hz); + + set_reg_bits(state->tab_init, 0x04, 0x01, cfg->loop_thru_enable); + set_reg_bits(state->tab_init, 0x03, 0x08, cfg->clk_out_enable << 3); + set_reg_bits(state->tab_init, 0x03, 0x07, cfg->clk_out_amp); + + if (mode >= MxL_MODE_CABLE) { + copy_reg_bits(state->tab_init, state->tab_init_cable); + return state->tab_init_cable; + } else + return state->tab_init; +} + +/* ------------------------------------------------------------------------- */ + +enum mxl5007t_bw_mhz { + MxL_BW_6MHz = 6, + MxL_BW_7MHz = 7, + MxL_BW_8MHz = 8, +}; + +static void mxl5007t_set_bw_bits(struct mxl5007t_state *state, + enum mxl5007t_bw_mhz bw) +{ + u8 val; + + switch (bw) { + case MxL_BW_6MHz: + val = 0x15; /* set DIG_MODEINDEX, DIG_MODEINDEX_A, + * and DIG_MODEINDEX_CSF */ + break; + case MxL_BW_7MHz: + val = 0x2a; + break; + case MxL_BW_8MHz: + val = 0x3f; + break; + default: + mxl_fail(-EINVAL); + return; + } + set_reg_bits(state->tab_rftune, 0x0c, 0x3f, val); + + return; +} + +static struct +reg_pair_t *mxl5007t_calc_rf_tune_regs(struct mxl5007t_state *state, + u32 rf_freq, enum mxl5007t_bw_mhz bw) +{ + u32 dig_rf_freq = 0; + u32 temp; + u32 frac_divider = 1000000; + unsigned int i; + + memcpy(&state->tab_rftune, ®_pair_rftune, sizeof(reg_pair_rftune)); + + mxl5007t_set_bw_bits(state, bw); + + /* Convert RF frequency into 16 bits => + * 10 bit integer (MHz) + 6 bit fraction */ + dig_rf_freq = rf_freq / MHz; + + temp = rf_freq % MHz; + + for (i = 0; i < 6; i++) { + dig_rf_freq <<= 1; + frac_divider /= 2; + if (temp > frac_divider) { + temp -= frac_divider; + dig_rf_freq++; + } + } + + /* add to have shift center point by 7.8124 kHz */ + if (temp > 7812) + dig_rf_freq++; + + set_reg_bits(state->tab_rftune, 0x0d, 0xff, (u8) dig_rf_freq); + set_reg_bits(state->tab_rftune, 0x0e, 0xff, (u8) (dig_rf_freq >> 8)); + + if (rf_freq >= 333000000) + set_reg_bits(state->tab_rftune, 0x80, 0x40, 0x40); + + return state->tab_rftune; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_write_reg(struct mxl5007t_state *state, u8 reg, u8 val) +{ + u8 buf[] = { reg, val }; + struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0, + .buf = buf, .len = 2 }; + int ret; + + ret = i2c_transfer(state->i2c_props.adap, &msg, 1); + if (ret != 1) { + mxl_err("failed!"); + return -EREMOTEIO; + } + return 0; +} + +static int mxl5007t_write_regs(struct mxl5007t_state *state, + struct reg_pair_t *reg_pair) +{ + unsigned int i = 0; + int ret = 0; + + while ((ret == 0) && (reg_pair[i].reg || reg_pair[i].val)) { + ret = mxl5007t_write_reg(state, + reg_pair[i].reg, reg_pair[i].val); + i++; + } + return ret; +} + +static int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val) +{ + u8 buf[2] = { 0xfb, reg }; + struct i2c_msg msg[] = { + { .addr = state->i2c_props.addr, .flags = 0, + .buf = buf, .len = 2 }, + { .addr = state->i2c_props.addr, .flags = I2C_M_RD, + .buf = val, .len = 1 }, + }; + int ret; + + ret = i2c_transfer(state->i2c_props.adap, msg, 2); + if (ret != 2) { + mxl_err("failed!"); + return -EREMOTEIO; + } + return 0; +} + +static int mxl5007t_soft_reset(struct mxl5007t_state *state) +{ + u8 d = 0xff; + struct i2c_msg msg = { + .addr = state->i2c_props.addr, .flags = 0, + .buf = &d, .len = 1 + }; + int ret = i2c_transfer(state->i2c_props.adap, &msg, 1); + + if (ret != 1) { + mxl_err("failed!"); + return -EREMOTEIO; + } + return 0; +} + +static int mxl5007t_tuner_init(struct mxl5007t_state *state, + enum mxl5007t_mode mode) +{ + struct reg_pair_t *init_regs; + int ret; + + ret = mxl5007t_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + + /* calculate initialization reg array */ + init_regs = mxl5007t_calc_init_regs(state, mode); + + ret = mxl5007t_write_regs(state, init_regs); + if (mxl_fail(ret)) + goto fail; + mdelay(1); +fail: + return ret; +} + +static int mxl5007t_tuner_rf_tune(struct mxl5007t_state *state, u32 rf_freq_hz, + enum mxl5007t_bw_mhz bw) +{ + struct reg_pair_t *rf_tune_regs; + int ret; + + /* calculate channel change reg array */ + rf_tune_regs = mxl5007t_calc_rf_tune_regs(state, rf_freq_hz, bw); + + ret = mxl5007t_write_regs(state, rf_tune_regs); + if (mxl_fail(ret)) + goto fail; + msleep(3); +fail: + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_synth_lock_status(struct mxl5007t_state *state, + int *rf_locked, int *ref_locked) +{ + u8 d; + int ret; + + *rf_locked = 0; + *ref_locked = 0; + + ret = mxl5007t_read_reg(state, 0xd8, &d); + if (mxl_fail(ret)) + goto fail; + + if ((d & 0x0c) == 0x0c) + *rf_locked = 1; + + if ((d & 0x03) == 0x03) + *ref_locked = 1; +fail: + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct mxl5007t_state *state = fe->tuner_priv; + int rf_locked, ref_locked, ret; + + *status = 0; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = mxl5007t_synth_lock_status(state, &rf_locked, &ref_locked); + if (mxl_fail(ret)) + goto fail; + mxl_debug("%s%s", rf_locked ? "rf locked " : "", + ref_locked ? "ref locked" : ""); + + if ((rf_locked) || (ref_locked)) + *status |= TUNER_STATUS_LOCKED; +fail: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + struct mxl5007t_state *state = fe->tuner_priv; + enum mxl5007t_bw_mhz bw; + enum mxl5007t_mode mode; + int ret; + u32 freq = c->frequency; + + switch (delsys) { + case SYS_ATSC: + mode = MxL_MODE_ATSC; + bw = MxL_BW_6MHz; + break; + case SYS_DVBC_ANNEX_B: + mode = MxL_MODE_CABLE; + bw = MxL_BW_6MHz; + break; + case SYS_DVBT: + case SYS_DVBT2: + mode = MxL_MODE_DVBT; + switch (c->bandwidth_hz) { + case 6000000: + bw = MxL_BW_6MHz; + break; + case 7000000: + bw = MxL_BW_7MHz; + break; + case 8000000: + bw = MxL_BW_8MHz; + break; + default: + return -EINVAL; + } + break; + default: + mxl_err("modulation type not supported!"); + return -EINVAL; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + mutex_lock(&state->lock); + + ret = mxl5007t_tuner_init(state, mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl5007t_tuner_rf_tune(state, freq, bw); + if (mxl_fail(ret)) + goto fail; + + state->frequency = freq; + state->bandwidth = c->bandwidth_hz; +fail: + mutex_unlock(&state->lock); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_init(struct dvb_frontend *fe) +{ + struct mxl5007t_state *state = fe->tuner_priv; + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + /* wake from standby */ + ret = mxl5007t_write_reg(state, 0x01, 0x01); + mxl_fail(ret); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return ret; +} + +static int mxl5007t_sleep(struct dvb_frontend *fe) +{ + struct mxl5007t_state *state = fe->tuner_priv; + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + /* enter standby mode */ + ret = mxl5007t_write_reg(state, 0x01, 0x00); + mxl_fail(ret); + ret = mxl5007t_write_reg(state, 0x0f, 0x00); + mxl_fail(ret); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mxl5007t_state *state = fe->tuner_priv; + *frequency = state->frequency; + return 0; +} + +static int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mxl5007t_state *state = fe->tuner_priv; + *bandwidth = state->bandwidth; + return 0; +} + +static int mxl5007t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mxl5007t_state *state = fe->tuner_priv; + + *frequency = 0; + + switch (state->if_freq) { + case MxL_IF_4_MHZ: + *frequency = 4000000; + break; + case MxL_IF_4_5_MHZ: + *frequency = 4500000; + break; + case MxL_IF_4_57_MHZ: + *frequency = 4570000; + break; + case MxL_IF_5_MHZ: + *frequency = 5000000; + break; + case MxL_IF_5_38_MHZ: + *frequency = 5380000; + break; + case MxL_IF_6_MHZ: + *frequency = 6000000; + break; + case MxL_IF_6_28_MHZ: + *frequency = 6280000; + break; + case MxL_IF_9_1915_MHZ: + *frequency = 9191500; + break; + case MxL_IF_35_25_MHZ: + *frequency = 35250000; + break; + case MxL_IF_36_15_MHZ: + *frequency = 36150000; + break; + case MxL_IF_44_MHZ: + *frequency = 44000000; + break; + } + return 0; +} + +static int mxl5007t_release(struct dvb_frontend *fe) +{ + struct mxl5007t_state *state = fe->tuner_priv; + + mutex_lock(&mxl5007t_list_mutex); + + if (state) + hybrid_tuner_release_state(state); + + mutex_unlock(&mxl5007t_list_mutex); + + fe->tuner_priv = NULL; + + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static struct dvb_tuner_ops mxl5007t_tuner_ops = { + .info = { + .name = "MaxLinear MxL5007T", + }, + .init = mxl5007t_init, + .sleep = mxl5007t_sleep, + .set_params = mxl5007t_set_params, + .get_status = mxl5007t_get_status, + .get_frequency = mxl5007t_get_frequency, + .get_bandwidth = mxl5007t_get_bandwidth, + .release = mxl5007t_release, + .get_if_frequency = mxl5007t_get_if_frequency, +}; + +static int mxl5007t_get_chip_id(struct mxl5007t_state *state) +{ + char *name; + int ret; + u8 id; + + ret = mxl5007t_read_reg(state, 0xd9, &id); + if (mxl_fail(ret)) + goto fail; + + switch (id) { + case MxL_5007_V1_F1: + name = "MxL5007.v1.f1"; + break; + case MxL_5007_V1_F2: + name = "MxL5007.v1.f2"; + break; + case MxL_5007_V2_100_F1: + name = "MxL5007.v2.100.f1"; + break; + case MxL_5007_V2_100_F2: + name = "MxL5007.v2.100.f2"; + break; + case MxL_5007_V2_200_F1: + name = "MxL5007.v2.200.f1"; + break; + case MxL_5007_V2_200_F2: + name = "MxL5007.v2.200.f2"; + break; + case MxL_5007_V4: + name = "MxL5007T.v4"; + break; + default: + name = "MxL5007T"; + printk(KERN_WARNING "%s: unknown rev (%02x)\n", __func__, id); + id = MxL_UNKNOWN_ID; + } + state->chip_id = id; + mxl_info("%s detected @ %d-%04x", name, + i2c_adapter_id(state->i2c_props.adap), + state->i2c_props.addr); + return 0; +fail: + mxl_warn("unable to identify device @ %d-%04x", + i2c_adapter_id(state->i2c_props.adap), + state->i2c_props.addr); + + state->chip_id = MxL_UNKNOWN_ID; + return ret; +} + +struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 addr, + struct mxl5007t_config *cfg) +{ + struct mxl5007t_state *state = NULL; + int instance, ret; + + mutex_lock(&mxl5007t_list_mutex); + instance = hybrid_tuner_request_state(struct mxl5007t_state, state, + hybrid_tuner_instance_list, + i2c, addr, "mxl5007t"); + switch (instance) { + case 0: + goto fail; + case 1: + /* new tuner instance */ + state->config = cfg; + + mutex_init(&state->lock); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = mxl5007t_get_chip_id(state); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + /* check return value of mxl5007t_get_chip_id */ + if (mxl_fail(ret)) + goto fail; + break; + default: + /* existing tuner instance */ + break; + } + fe->tuner_priv = state; + mutex_unlock(&mxl5007t_list_mutex); + + memcpy(&fe->ops.tuner_ops, &mxl5007t_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + return fe; +fail: + mutex_unlock(&mxl5007t_list_mutex); + + mxl5007t_release(fe); + return NULL; +} +EXPORT_SYMBOL_GPL(mxl5007t_attach); +MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver"); +MODULE_AUTHOR("Michael Krufky "); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.2"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/tuners/mxl5007t.h b/drivers/media/tuners/mxl5007t.h new file mode 100644 index 000000000000..aa3eea0b5262 --- /dev/null +++ b/drivers/media/tuners/mxl5007t.h @@ -0,0 +1,104 @@ +/* + * mxl5007t.h - driver for the MaxLinear MxL5007T silicon tuner + * + * Copyright (C) 2008 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 __MXL5007T_H__ +#define __MXL5007T_H__ + +#include "dvb_frontend.h" + +/* ------------------------------------------------------------------------- */ + +enum mxl5007t_if_freq { + MxL_IF_4_MHZ, /* 4000000 */ + MxL_IF_4_5_MHZ, /* 4500000 */ + MxL_IF_4_57_MHZ, /* 4570000 */ + MxL_IF_5_MHZ, /* 5000000 */ + MxL_IF_5_38_MHZ, /* 5380000 */ + MxL_IF_6_MHZ, /* 6000000 */ + MxL_IF_6_28_MHZ, /* 6280000 */ + MxL_IF_9_1915_MHZ, /* 9191500 */ + MxL_IF_35_25_MHZ, /* 35250000 */ + MxL_IF_36_15_MHZ, /* 36150000 */ + MxL_IF_44_MHZ, /* 44000000 */ +}; + +enum mxl5007t_xtal_freq { + MxL_XTAL_16_MHZ, /* 16000000 */ + MxL_XTAL_20_MHZ, /* 20000000 */ + MxL_XTAL_20_25_MHZ, /* 20250000 */ + MxL_XTAL_20_48_MHZ, /* 20480000 */ + MxL_XTAL_24_MHZ, /* 24000000 */ + MxL_XTAL_25_MHZ, /* 25000000 */ + MxL_XTAL_25_14_MHZ, /* 25140000 */ + MxL_XTAL_27_MHZ, /* 27000000 */ + MxL_XTAL_28_8_MHZ, /* 28800000 */ + MxL_XTAL_32_MHZ, /* 32000000 */ + MxL_XTAL_40_MHZ, /* 40000000 */ + MxL_XTAL_44_MHZ, /* 44000000 */ + MxL_XTAL_48_MHZ, /* 48000000 */ + MxL_XTAL_49_3811_MHZ, /* 49381100 */ +}; + +enum mxl5007t_clkout_amp { + MxL_CLKOUT_AMP_0_94V = 0, + MxL_CLKOUT_AMP_0_53V = 1, + MxL_CLKOUT_AMP_0_37V = 2, + MxL_CLKOUT_AMP_0_28V = 3, + MxL_CLKOUT_AMP_0_23V = 4, + MxL_CLKOUT_AMP_0_20V = 5, + MxL_CLKOUT_AMP_0_17V = 6, + MxL_CLKOUT_AMP_0_15V = 7, +}; + +struct mxl5007t_config { + s32 if_diff_out_level; + enum mxl5007t_clkout_amp clk_out_amp; + enum mxl5007t_xtal_freq xtal_freq_hz; + enum mxl5007t_if_freq if_freq_hz; + unsigned int invert_if:1; + unsigned int loop_thru_enable:1; + unsigned int clk_out_enable:1; +}; + +#if defined(CONFIG_MEDIA_TUNER_MXL5007T) || (defined(CONFIG_MEDIA_TUNER_MXL5007T_MODULE) && defined(MODULE)) +extern struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 addr, + struct mxl5007t_config *cfg); +#else +static inline struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + u8 addr, + struct mxl5007t_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __MXL5007T_H__ */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ + diff --git a/drivers/media/tuners/qt1010.c b/drivers/media/tuners/qt1010.c new file mode 100644 index 000000000000..bdc39e11030e --- /dev/null +++ b/drivers/media/tuners/qt1010.c @@ -0,0 +1,480 @@ +/* + * Driver for Quantek QT1010 silicon tuner + * + * Copyright (C) 2006 Antti Palosaari + * Aapo Tahkola + * + * 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 "qt1010.h" +#include "qt1010_priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "QT1010: " args); \ + } while (0) + +/* read single register */ +static int qt1010_readreg(struct qt1010_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, + .flags = 0, .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, + .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "qt1010 I2C read failed\n"); + return -EREMOTEIO; + } + return 0; +} + +/* write single register */ +static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, + .flags = 0, .buf = buf, .len = 2 }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "qt1010 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +/* dump all registers */ +static void qt1010_dump_regs(struct qt1010_priv *priv) +{ + u8 reg, val; + + for (reg = 0; ; reg++) { + if (reg % 16 == 0) { + if (reg) + printk(KERN_CONT "\n"); + printk(KERN_DEBUG "%02x:", reg); + } + if (qt1010_readreg(priv, reg, &val) == 0) + printk(KERN_CONT " %02x", val); + else + printk(KERN_CONT " --"); + if (reg == 0x2f) + break; + } + printk(KERN_CONT "\n"); +} + +static int qt1010_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct qt1010_priv *priv; + int err; + u32 freq, div, mod1, mod2; + u8 i, tmpval, reg05; + qt1010_i2c_oper_t rd[48] = { + { QT1010_WR, 0x01, 0x80 }, + { QT1010_WR, 0x02, 0x3f }, + { QT1010_WR, 0x05, 0xff }, /* 02 c write */ + { QT1010_WR, 0x06, 0x44 }, + { QT1010_WR, 0x07, 0xff }, /* 04 c write */ + { QT1010_WR, 0x08, 0x08 }, + { QT1010_WR, 0x09, 0xff }, /* 06 c write */ + { QT1010_WR, 0x0a, 0xff }, /* 07 c write */ + { QT1010_WR, 0x0b, 0xff }, /* 08 c write */ + { QT1010_WR, 0x0c, 0xe1 }, + { QT1010_WR, 0x1a, 0xff }, /* 10 c write */ + { QT1010_WR, 0x1b, 0x00 }, + { QT1010_WR, 0x1c, 0x89 }, + { QT1010_WR, 0x11, 0xff }, /* 13 c write */ + { QT1010_WR, 0x12, 0xff }, /* 14 c write */ + { QT1010_WR, 0x22, 0xff }, /* 15 c write */ + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x1e, 0xd0 }, + { QT1010_RD, 0x22, 0xff }, /* 16 c read */ + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_RD, 0x05, 0xff }, /* 20 c read */ + { QT1010_RD, 0x22, 0xff }, /* 21 c read */ + { QT1010_WR, 0x23, 0xd0 }, + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x1e, 0xe0 }, + { QT1010_RD, 0x23, 0xff }, /* 25 c read */ + { QT1010_RD, 0x23, 0xff }, /* 26 c read */ + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x24, 0xd0 }, + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x1e, 0xf0 }, + { QT1010_RD, 0x24, 0xff }, /* 31 c read */ + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x14, 0x7f }, + { QT1010_WR, 0x15, 0x7f }, + { QT1010_WR, 0x05, 0xff }, /* 35 c write */ + { QT1010_WR, 0x06, 0x00 }, + { QT1010_WR, 0x15, 0x1f }, + { QT1010_WR, 0x16, 0xff }, + { QT1010_WR, 0x18, 0xff }, + { QT1010_WR, 0x1f, 0xff }, /* 40 c write */ + { QT1010_WR, 0x20, 0xff }, /* 41 c write */ + { QT1010_WR, 0x21, 0x53 }, + { QT1010_WR, 0x25, 0xff }, /* 43 c write */ + { QT1010_WR, 0x26, 0x15 }, + { QT1010_WR, 0x00, 0xff }, /* 45 c write */ + { QT1010_WR, 0x02, 0x00 }, + { QT1010_WR, 0x01, 0x00 } + }; + +#define FREQ1 32000000 /* 32 MHz */ +#define FREQ2 4000000 /* 4 MHz Quartz oscillator in the stick? */ + + priv = fe->tuner_priv; + freq = c->frequency; + div = (freq + QT1010_OFFSET) / QT1010_STEP; + freq = (div * QT1010_STEP) - QT1010_OFFSET; + mod1 = (freq + QT1010_OFFSET) % FREQ1; + mod2 = (freq + QT1010_OFFSET) % FREQ2; + priv->frequency = freq; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + /* reg 05 base value */ + if (freq < 290000000) reg05 = 0x14; /* 290 MHz */ + else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */ + else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */ + else reg05 = 0x74; + + /* 0x5 */ + rd[2].val = reg05; + + /* 07 - set frequency: 32 MHz scale */ + rd[4].val = (freq + QT1010_OFFSET) / FREQ1; + + /* 09 - changes every 8/24 MHz */ + if (mod1 < 8000000) rd[6].val = 0x1d; + else rd[6].val = 0x1c; + + /* 0a - set frequency: 4 MHz scale (max 28 MHz) */ + if (mod1 < 1*FREQ2) rd[7].val = 0x09; /* +0 MHz */ + else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /* +4 MHz */ + else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /* +8 MHz */ + else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */ + else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */ + else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */ + else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */ + else rd[7].val = 0x0a; /* +28 MHz */ + + /* 0b - changes every 2/2 MHz */ + if (mod2 < 2000000) rd[8].val = 0x45; + else rd[8].val = 0x44; + + /* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/ + tmpval = 0x78; /* byte, overflows intentionally */ + rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08); + + /* 11 */ + rd[13].val = 0xfd; /* TODO: correct value calculation */ + + /* 12 */ + rd[14].val = 0x91; /* TODO: correct value calculation */ + + /* 22 */ + if (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */ + else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */ + else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */ + else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */ + else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */ + else rd[15].val = 0xd0; + + /* 05 */ + rd[35].val = (reg05 & 0xf0); + + /* 1f */ + if (mod1 < 8000000) tmpval = 0x00; + else if (mod1 < 12000000) tmpval = 0x01; + else if (mod1 < 16000000) tmpval = 0x02; + else if (mod1 < 24000000) tmpval = 0x03; + else if (mod1 < 28000000) tmpval = 0x04; + else tmpval = 0x05; + rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval); + + /* 20 */ + if (mod1 < 8000000) tmpval = 0x00; + else if (mod1 < 12000000) tmpval = 0x01; + else if (mod1 < 20000000) tmpval = 0x02; + else if (mod1 < 24000000) tmpval = 0x03; + else if (mod1 < 28000000) tmpval = 0x04; + else tmpval = 0x05; + rd[41].val = (priv->reg20_init_val + 0x0d + tmpval); + + /* 25 */ + rd[43].val = priv->reg25_init_val; + + /* 00 */ + rd[45].val = 0x92; /* TODO: correct value calculation */ + + dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \ + "1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \ + "20:%02x 25:%02x 00:%02x", \ + freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \ + rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \ + rd[40].val, rd[41].val, rd[43].val, rd[45].val); + + for (i = 0; i < ARRAY_SIZE(rd); i++) { + if (rd[i].oper == QT1010_WR) { + err = qt1010_writereg(priv, rd[i].reg, rd[i].val); + } else { /* read is required to proper locking */ + err = qt1010_readreg(priv, rd[i].reg, &tmpval); + } + if (err) return err; + } + + if (debug) + qt1010_dump_regs(priv); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + return 0; +} + +static int qt1010_init_meas1(struct qt1010_priv *priv, + u8 oper, u8 reg, u8 reg_init_val, u8 *retval) +{ + u8 i, val1, val2; + int err; + + qt1010_i2c_oper_t i2c_data[] = { + { QT1010_WR, reg, reg_init_val }, + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x1e, oper }, + { QT1010_RD, reg, 0xff } + }; + + for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { + if (i2c_data[i].oper == QT1010_WR) { + err = qt1010_writereg(priv, i2c_data[i].reg, + i2c_data[i].val); + } else { + err = qt1010_readreg(priv, i2c_data[i].reg, &val2); + } + if (err) return err; + } + + do { + val1 = val2; + err = qt1010_readreg(priv, reg, &val2); + if (err) return err; + dprintk("compare reg:%02x %02x %02x", reg, val1, val2); + } while (val1 != val2); + *retval = val1; + + return qt1010_writereg(priv, 0x1e, 0x00); +} + +static int qt1010_init_meas2(struct qt1010_priv *priv, + u8 reg_init_val, u8 *retval) +{ + u8 i, val; + int err; + qt1010_i2c_oper_t i2c_data[] = { + { QT1010_WR, 0x07, reg_init_val }, + { QT1010_WR, 0x22, 0xd0 }, + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x1e, 0xd0 }, + { QT1010_RD, 0x22, 0xff }, + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x22, 0xff } + }; + for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { + if (i2c_data[i].oper == QT1010_WR) { + err = qt1010_writereg(priv, i2c_data[i].reg, + i2c_data[i].val); + } else { + err = qt1010_readreg(priv, i2c_data[i].reg, &val); + } + if (err) return err; + } + *retval = val; + return 0; +} + +static int qt1010_init(struct dvb_frontend *fe) +{ + struct qt1010_priv *priv = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int err = 0; + u8 i, tmpval, *valptr = NULL; + + qt1010_i2c_oper_t i2c_data[] = { + { QT1010_WR, 0x01, 0x80 }, + { QT1010_WR, 0x0d, 0x84 }, + { QT1010_WR, 0x0e, 0xb7 }, + { QT1010_WR, 0x2a, 0x23 }, + { QT1010_WR, 0x2c, 0xdc }, + { QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */ + { QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */ + { QT1010_WR, 0x2b, 0x70 }, + { QT1010_WR, 0x2a, 0x23 }, + { QT1010_M1, 0x26, 0x08 }, + { QT1010_M1, 0x82, 0xff }, + { QT1010_WR, 0x05, 0x14 }, + { QT1010_WR, 0x06, 0x44 }, + { QT1010_WR, 0x07, 0x28 }, + { QT1010_WR, 0x08, 0x0b }, + { QT1010_WR, 0x11, 0xfd }, + { QT1010_M1, 0x22, 0x0d }, + { QT1010_M1, 0xd0, 0xff }, + { QT1010_WR, 0x06, 0x40 }, + { QT1010_WR, 0x16, 0xf0 }, + { QT1010_WR, 0x02, 0x38 }, + { QT1010_WR, 0x03, 0x18 }, + { QT1010_WR, 0x20, 0xe0 }, + { QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */ + { QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */ + { QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */ + { QT1010_WR, 0x03, 0x19 }, + { QT1010_WR, 0x02, 0x3f }, + { QT1010_WR, 0x21, 0x53 }, + { QT1010_RD, 0x21, 0xff }, + { QT1010_WR, 0x11, 0xfd }, + { QT1010_WR, 0x05, 0x34 }, + { QT1010_WR, 0x06, 0x44 }, + { QT1010_WR, 0x08, 0x08 } + }; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { + switch (i2c_data[i].oper) { + case QT1010_WR: + err = qt1010_writereg(priv, i2c_data[i].reg, + i2c_data[i].val); + break; + case QT1010_RD: + if (i2c_data[i].val == 0x20) + valptr = &priv->reg20_init_val; + else + valptr = &tmpval; + err = qt1010_readreg(priv, i2c_data[i].reg, valptr); + break; + case QT1010_M1: + if (i2c_data[i].val == 0x25) + valptr = &priv->reg25_init_val; + else if (i2c_data[i].val == 0x1f) + valptr = &priv->reg1f_init_val; + else + valptr = &tmpval; + err = qt1010_init_meas1(priv, i2c_data[i+1].reg, + i2c_data[i].reg, + i2c_data[i].val, valptr); + i++; + break; + } + if (err) return err; + } + + for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */ + if ((err = qt1010_init_meas2(priv, i, &tmpval))) + return err; + + c->frequency = 545000000; /* Sigmatek DVB-110 545000000 */ + /* MSI Megasky 580 GL861 533000000 */ + return qt1010_set_params(fe); +} + +static int qt1010_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct qt1010_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int qt1010_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + *frequency = 36125000; + return 0; +} + +static const struct dvb_tuner_ops qt1010_tuner_ops = { + .info = { + .name = "Quantek QT1010", + .frequency_min = QT1010_MIN_FREQ, + .frequency_max = QT1010_MAX_FREQ, + .frequency_step = QT1010_STEP, + }, + + .release = qt1010_release, + .init = qt1010_init, + /* TODO: implement sleep */ + + .set_params = qt1010_set_params, + .get_frequency = qt1010_get_frequency, + .get_if_frequency = qt1010_get_if_frequency, +}; + +struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct qt1010_config *cfg) +{ + struct qt1010_priv *priv = NULL; + u8 id; + + priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + + /* Try to detect tuner chip. Probably this is not correct register. */ + if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) { + kfree(priv); + return NULL; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + printk(KERN_INFO "Quantek QT1010 successfully identified.\n"); + memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + return fe; +} +EXPORT_SYMBOL(qt1010_attach); + +MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver"); +MODULE_AUTHOR("Antti Palosaari "); +MODULE_AUTHOR("Aapo Tahkola "); +MODULE_VERSION("0.1"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/qt1010.h b/drivers/media/tuners/qt1010.h new file mode 100644 index 000000000000..807fb7b6146b --- /dev/null +++ b/drivers/media/tuners/qt1010.h @@ -0,0 +1,53 @@ +/* + * Driver for Quantek QT1010 silicon tuner + * + * Copyright (C) 2006 Antti Palosaari + * Aapo Tahkola + * + * 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 QT1010_H +#define QT1010_H + +#include "dvb_frontend.h" + +struct qt1010_config { + u8 i2c_address; +}; + +/** + * Attach a qt1010 tuner to the supplied frontend structure. + * + * @param fe frontend to attach to + * @param i2c i2c adapter to use + * @param cfg tuner hw based configuration + * @return fe pointer on success, NULL on failure + */ +#if defined(CONFIG_MEDIA_TUNER_QT1010) || (defined(CONFIG_MEDIA_TUNER_QT1010_MODULE) && defined(MODULE)) +extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct qt1010_config *cfg); +#else +static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct qt1010_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_MEDIA_TUNER_QT1010 + +#endif diff --git a/drivers/media/tuners/qt1010_priv.h b/drivers/media/tuners/qt1010_priv.h new file mode 100644 index 000000000000..2c42d3f01636 --- /dev/null +++ b/drivers/media/tuners/qt1010_priv.h @@ -0,0 +1,104 @@ +/* + * Driver for Quantek QT1010 silicon tuner + * + * Copyright (C) 2006 Antti Palosaari + * Aapo Tahkola + * + * 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 QT1010_PRIV_H +#define QT1010_PRIV_H + +/* +reg def meaning +=== === ======= +00 00 ? +01 a0 ? operation start/stop; start=80, stop=00 +02 00 ? +03 19 ? +04 00 ? +05 00 ? maybe band selection +06 00 ? +07 2b set frequency: 32 MHz scale, n*32 MHz +08 0b ? +09 10 ? changes every 8/24 MHz; values 1d/1c +0a 08 set frequency: 4 MHz scale, n*4 MHz +0b 41 ? changes every 2/2 MHz; values 45/45 +0c e1 ? +0d 94 ? +0e b6 ? +0f 2c ? +10 10 ? +11 f1 ? maybe device specified adjustment +12 11 ? maybe device specified adjustment +13 3f ? +14 1f ? +15 3f ? +16 ff ? +17 ff ? +18 f7 ? +19 80 ? +1a d0 set frequency: 125 kHz scale, n*125 kHz +1b 00 ? +1c 89 ? +1d 00 ? +1e 00 ? looks like operation register; write cmd here, read result from 1f-26 +1f 20 ? chip initialization +20 e0 ? chip initialization +21 20 ? +22 d0 ? +23 d0 ? +24 d0 ? +25 40 ? chip initialization +26 08 ? +27 29 ? +28 55 ? +29 39 ? +2a 13 ? +2b 01 ? +2c ea ? +2d 00 ? +2e 00 ? not used? +2f 00 ? not used? +*/ + +#define QT1010_STEP 125000 /* 125 kHz used by Windows drivers, + hw could be more precise but we don't + know how to use */ +#define QT1010_MIN_FREQ 48000000 /* 48 MHz */ +#define QT1010_MAX_FREQ 860000000 /* 860 MHz */ +#define QT1010_OFFSET 1246000000 /* 1246 MHz */ + +#define QT1010_WR 0 +#define QT1010_RD 1 +#define QT1010_M1 3 + +typedef struct { + u8 oper, reg, val; +} qt1010_i2c_oper_t; + +struct qt1010_priv { + struct qt1010_config *cfg; + struct i2c_adapter *i2c; + + u8 reg1f_init_val; + u8 reg20_init_val; + u8 reg25_init_val; + + u32 frequency; +}; + +#endif diff --git a/drivers/media/tuners/tda18212.c b/drivers/media/tuners/tda18212.c new file mode 100644 index 000000000000..5d9f02842501 --- /dev/null +++ b/drivers/media/tuners/tda18212.c @@ -0,0 +1,319 @@ +/* + * NXP TDA18212HN silicon tuner driver + * + * Copyright (C) 2011 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 "tda18212.h" + +struct tda18212_priv { + struct tda18212_config *cfg; + struct i2c_adapter *i2c; + + u32 if_frequency; +}; + +/* write multiple registers */ +static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, + int len) +{ + int ret; + u8 buf[len+1]; + struct i2c_msg msg[1] = { + { + .addr = priv->cfg->i2c_address, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + } + }; + + buf[0] = reg; + memcpy(&buf[1], val, len); + + ret = i2c_transfer(priv->i2c, msg, 1); + if (ret == 1) { + ret = 0; + } else { + dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \ + "len=%d\n", KBUILD_MODNAME, ret, reg, len); + ret = -EREMOTEIO; + } + return ret; +} + +/* read multiple registers */ +static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val, + int len) +{ + int ret; + u8 buf[len]; + struct i2c_msg msg[2] = { + { + .addr = priv->cfg->i2c_address, + .flags = 0, + .len = 1, + .buf = ®, + }, { + .addr = priv->cfg->i2c_address, + .flags = I2C_M_RD, + .len = sizeof(buf), + .buf = buf, + } + }; + + ret = i2c_transfer(priv->i2c, msg, 2); + if (ret == 2) { + memcpy(val, buf, len); + ret = 0; + } else { + dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \ + "len=%d\n", KBUILD_MODNAME, ret, reg, len); + ret = -EREMOTEIO; + } + + return ret; +} + +/* write single register */ +static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val) +{ + return tda18212_wr_regs(priv, reg, &val, 1); +} + +/* read single register */ +static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val) +{ + return tda18212_rd_regs(priv, reg, val, 1); +} + +#if 0 /* keep, useful when developing driver */ +static void tda18212_dump_regs(struct tda18212_priv *priv) +{ + int i; + u8 buf[256]; + + #define TDA18212_RD_LEN 32 + for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN) + tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN); + + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf, + sizeof(buf), true); + + return; +} +#endif + +static int tda18212_set_params(struct dvb_frontend *fe) +{ + struct tda18212_priv *priv = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, i; + u32 if_khz; + u8 buf[9]; + #define DVBT_6 0 + #define DVBT_7 1 + #define DVBT_8 2 + #define DVBT2_6 3 + #define DVBT2_7 4 + #define DVBT2_8 5 + #define DVBC_6 6 + #define DVBC_8 7 + static const u8 bw_params[][3] = { + /* reg: 0f 13 23 */ + [DVBT_6] = { 0xb3, 0x20, 0x03 }, + [DVBT_7] = { 0xb3, 0x31, 0x01 }, + [DVBT_8] = { 0xb3, 0x22, 0x01 }, + [DVBT2_6] = { 0xbc, 0x20, 0x03 }, + [DVBT2_7] = { 0xbc, 0x72, 0x03 }, + [DVBT2_8] = { 0xbc, 0x22, 0x01 }, + [DVBC_6] = { 0x92, 0x50, 0x03 }, + [DVBC_8] = { 0x92, 0x53, 0x03 }, + }; + + dev_dbg(&priv->i2c->dev, + "%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", + __func__, c->delivery_system, c->frequency, + c->bandwidth_hz); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + switch (c->delivery_system) { + case SYS_DVBT: + switch (c->bandwidth_hz) { + case 6000000: + if_khz = priv->cfg->if_dvbt_6; + i = DVBT_6; + break; + case 7000000: + if_khz = priv->cfg->if_dvbt_7; + i = DVBT_7; + break; + case 8000000: + if_khz = priv->cfg->if_dvbt_8; + i = DVBT_8; + break; + default: + ret = -EINVAL; + goto error; + } + break; + case SYS_DVBT2: + switch (c->bandwidth_hz) { + case 6000000: + if_khz = priv->cfg->if_dvbt2_6; + i = DVBT2_6; + break; + case 7000000: + if_khz = priv->cfg->if_dvbt2_7; + i = DVBT2_7; + break; + case 8000000: + if_khz = priv->cfg->if_dvbt2_8; + i = DVBT2_8; + break; + default: + ret = -EINVAL; + goto error; + } + break; + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + if_khz = priv->cfg->if_dvbc; + i = DVBC_8; + break; + default: + ret = -EINVAL; + goto error; + } + + ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]); + if (ret) + goto error; + + ret = tda18212_wr_reg(priv, 0x06, 0x00); + if (ret) + goto error; + + ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]); + if (ret) + goto error; + + buf[0] = 0x02; + buf[1] = bw_params[i][1]; + buf[2] = 0x03; /* default value */ + buf[3] = DIV_ROUND_CLOSEST(if_khz, 50); + buf[4] = ((c->frequency / 1000) >> 16) & 0xff; + buf[5] = ((c->frequency / 1000) >> 8) & 0xff; + buf[6] = ((c->frequency / 1000) >> 0) & 0xff; + buf[7] = 0xc1; + buf[8] = 0x01; + ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf)); + if (ret) + goto error; + + /* actual IF rounded as it is on register */ + priv->if_frequency = buf[3] * 50 * 1000; + +exit: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + return ret; + +error: + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + goto exit; +} + +static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda18212_priv *priv = fe->tuner_priv; + + *frequency = priv->if_frequency; + + return 0; +} + +static int tda18212_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops tda18212_tuner_ops = { + .info = { + .name = "NXP TDA18212", + + .frequency_min = 48000000, + .frequency_max = 864000000, + .frequency_step = 1000, + }, + + .release = tda18212_release, + + .set_params = tda18212_set_params, + .get_if_frequency = tda18212_get_if_frequency, +}; + +struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct tda18212_config *cfg) +{ + struct tda18212_priv *priv = NULL; + int ret; + u8 uninitialized_var(val); + + priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + fe->tuner_priv = priv; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + /* check if the tuner is there */ + ret = tda18212_rd_reg(priv, 0x00, &val); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + dev_dbg(&priv->i2c->dev, "%s: ret=%d chip id=%02x\n", __func__, ret, + val); + if (ret || val != 0xc7) { + kfree(priv); + return NULL; + } + + dev_info(&priv->i2c->dev, + "%s: NXP TDA18212HN successfully identified\n", + KBUILD_MODNAME); + + memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + return fe; +} +EXPORT_SYMBOL(tda18212_attach); + +MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver"); +MODULE_AUTHOR("Antti Palosaari "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/tda18212.h b/drivers/media/tuners/tda18212.h new file mode 100644 index 000000000000..9bd5da4aabb7 --- /dev/null +++ b/drivers/media/tuners/tda18212.h @@ -0,0 +1,52 @@ +/* + * NXP TDA18212HN silicon tuner driver + * + * Copyright (C) 2011 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 TDA18212_H +#define TDA18212_H + +#include "dvb_frontend.h" + +struct tda18212_config { + u8 i2c_address; + + u16 if_dvbt_6; + u16 if_dvbt_7; + u16 if_dvbt_8; + u16 if_dvbt2_5; + u16 if_dvbt2_6; + u16 if_dvbt2_7; + u16 if_dvbt2_8; + u16 if_dvbc; +}; + +#if defined(CONFIG_MEDIA_TUNER_TDA18212) || \ + (defined(CONFIG_MEDIA_TUNER_TDA18212_MODULE) && defined(MODULE)) +extern struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct tda18212_config *cfg); +#else +static inline struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct tda18212_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff --git a/drivers/media/tuners/tda18218.c b/drivers/media/tuners/tda18218.c new file mode 100644 index 000000000000..8a6f9ca788f0 --- /dev/null +++ b/drivers/media/tuners/tda18218.c @@ -0,0 +1,342 @@ +/* + * NXP TDA18218HN silicon tuner driver + * + * Copyright (C) 2010 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 "tda18218.h" +#include "tda18218_priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +/* write multiple registers */ +static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len) +{ + int ret = 0; + u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max; + struct i2c_msg msg[1] = { + { + .addr = priv->cfg->i2c_address, + .flags = 0, + .buf = buf, + } + }; + + msg_len_max = priv->cfg->i2c_wr_max - 1; + quotient = len / msg_len_max; + remainder = len % msg_len_max; + msg_len = msg_len_max; + for (i = 0; (i <= quotient && remainder); i++) { + if (i == quotient) /* set len of the last msg */ + msg_len = remainder; + + msg[0].len = msg_len + 1; + buf[0] = reg + i * msg_len_max; + memcpy(&buf[1], &val[i * msg_len_max], msg_len); + + ret = i2c_transfer(priv->i2c, msg, 1); + if (ret != 1) + break; + } + + if (ret == 1) { + ret = 0; + } else { + warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len); + ret = -EREMOTEIO; + } + + return ret; +} + +/* read multiple registers */ +static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len) +{ + int ret; + u8 buf[reg+len]; /* we must start read always from reg 0x00 */ + struct i2c_msg msg[2] = { + { + .addr = priv->cfg->i2c_address, + .flags = 0, + .len = 1, + .buf = "\x00", + }, { + .addr = priv->cfg->i2c_address, + .flags = I2C_M_RD, + .len = sizeof(buf), + .buf = buf, + } + }; + + ret = i2c_transfer(priv->i2c, msg, 2); + if (ret == 2) { + memcpy(val, &buf[reg], len); + ret = 0; + } else { + warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len); + ret = -EREMOTEIO; + } + + return ret; +} + +/* write single register */ +static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val) +{ + return tda18218_wr_regs(priv, reg, &val, 1); +} + +/* read single register */ + +static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val) +{ + return tda18218_rd_regs(priv, reg, val, 1); +} + +static int tda18218_set_params(struct dvb_frontend *fe) +{ + struct tda18218_priv *priv = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 bw = c->bandwidth_hz; + int ret; + u8 buf[3], i, BP_Filter, LP_Fc; + u32 LO_Frac; + /* TODO: find out correct AGC algorithm */ + u8 agc[][2] = { + { R20_AGC11, 0x60 }, + { R23_AGC21, 0x02 }, + { R20_AGC11, 0xa0 }, + { R23_AGC21, 0x09 }, + { R20_AGC11, 0xe0 }, + { R23_AGC21, 0x0c }, + { R20_AGC11, 0x40 }, + { R23_AGC21, 0x01 }, + { R20_AGC11, 0x80 }, + { R23_AGC21, 0x08 }, + { R20_AGC11, 0xc0 }, + { R23_AGC21, 0x0b }, + { R24_AGC22, 0x1c }, + { R24_AGC22, 0x0c }, + }; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + /* low-pass filter cut-off frequency */ + if (bw <= 6000000) { + LP_Fc = 0; + priv->if_frequency = 3000000; + } else if (bw <= 7000000) { + LP_Fc = 1; + priv->if_frequency = 3500000; + } else { + LP_Fc = 2; + priv->if_frequency = 4000000; + } + + LO_Frac = c->frequency + priv->if_frequency; + + /* band-pass filter */ + if (LO_Frac < 188000000) + BP_Filter = 3; + else if (LO_Frac < 253000000) + BP_Filter = 4; + else if (LO_Frac < 343000000) + BP_Filter = 5; + else + BP_Filter = 6; + + buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */ + buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */ + buf[2] = priv->regs[R1C_AGC2B]; + ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3); + if (ret) + goto error; + + buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */ + buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */ + buf[2] = (LO_Frac / 1000) << 4 | + (priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */ + ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3); + if (ret) + goto error; + + buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */ + ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1); + if (ret) + goto error; + + buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */ + ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1); + if (ret) + goto error; + + /* trigger AGC */ + for (i = 0; i < ARRAY_SIZE(agc); i++) { + ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]); + if (ret) + goto error; + } + +error: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + if (ret) + dbg("%s: failed ret:%d", __func__, ret); + + return ret; +} + +static int tda18218_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda18218_priv *priv = fe->tuner_priv; + *frequency = priv->if_frequency; + dbg("%s: if=%d", __func__, *frequency); + return 0; +} + +static int tda18218_sleep(struct dvb_frontend *fe) +{ + struct tda18218_priv *priv = fe->tuner_priv; + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + /* standby */ + ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0)); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + if (ret) + dbg("%s: failed ret:%d", __func__, ret); + + return ret; +} + +static int tda18218_init(struct dvb_frontend *fe) +{ + struct tda18218_priv *priv = fe->tuner_priv; + int ret; + + /* TODO: calibrations */ + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + if (ret) + dbg("%s: failed ret:%d", __func__, ret); + + return ret; +} + +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 = 174000000, + .frequency_max = 864000000, + .frequency_step = 1000, + }, + + .release = tda18218_release, + .init = tda18218_init, + .sleep = tda18218_sleep, + + .set_params = tda18218_set_params, + + .get_if_frequency = tda18218_get_if_frequency, +}; + +struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct tda18218_config *cfg) +{ + struct tda18218_priv *priv = NULL; + u8 uninitialized_var(val); + int ret; + /* chip default registers values */ + static u8 def_regs[] = { + 0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40, + 0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00, + 0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01, + 0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9, + 0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00, + 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6 + }; + + priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + fe->tuner_priv = priv; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + /* check if the tuner is there */ + ret = tda18218_rd_reg(priv, R00_ID, &val); + dbg("%s: ret:%d chip ID:%02x", __func__, ret, val); + if (ret || val != def_regs[R00_ID]) { + kfree(priv); + return NULL; + } + + info("NXP TDA18218HN successfully identified."); + + memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops, + sizeof(struct dvb_tuner_ops)); + memcpy(priv->regs, def_regs, sizeof(def_regs)); + + /* loop-through enabled chip default register values */ + if (priv->cfg->loop_through) { + priv->regs[R17_PD1] = 0xb0; + priv->regs[R18_PD2] = 0x59; + } + + /* standby */ + ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0)); + if (ret) + dbg("%s: failed ret:%d", __func__, ret); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + return fe; +} +EXPORT_SYMBOL(tda18218_attach); + +MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver"); +MODULE_AUTHOR("Antti Palosaari "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/tda18218.h b/drivers/media/tuners/tda18218.h new file mode 100644 index 000000000000..b4180d180029 --- /dev/null +++ b/drivers/media/tuners/tda18218.h @@ -0,0 +1,45 @@ +/* + * NXP TDA18218HN silicon tuner driver + * + * Copyright (C) 2010 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 TDA18218_H +#define TDA18218_H + +#include "dvb_frontend.h" + +struct tda18218_config { + u8 i2c_address; + u8 i2c_wr_max; + u8 loop_through:1; +}; + +#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 + +#endif diff --git a/drivers/media/tuners/tda18218_priv.h b/drivers/media/tuners/tda18218_priv.h new file mode 100644 index 000000000000..dc52b72e1407 --- /dev/null +++ b/drivers/media/tuners/tda18218_priv.h @@ -0,0 +1,108 @@ +/* + * NXP TDA18218HN silicon tuner driver + * + * Copyright (C) 2010 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 TDA18218_PRIV_H +#define TDA18218_PRIV_H + +#define LOG_PREFIX "tda18218" + +#undef dbg +#define dbg(f, arg...) \ + if (debug) \ + printk(KERN_DEBUG LOG_PREFIX": " f "\n" , ## arg) +#undef err +#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) +#undef info +#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef warn +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) + +#define R00_ID 0x00 /* ID byte */ +#define R01_R1 0x01 /* Read byte 1 */ +#define R02_R2 0x02 /* Read byte 2 */ +#define R03_R3 0x03 /* Read byte 3 */ +#define R04_R4 0x04 /* Read byte 4 */ +#define R05_R5 0x05 /* Read byte 5 */ +#define R06_R6 0x06 /* Read byte 6 */ +#define R07_MD1 0x07 /* Main divider byte 1 */ +#define R08_PSM1 0x08 /* PSM byte 1 */ +#define R09_MD2 0x09 /* Main divider byte 2 */ +#define R0A_MD3 0x0a /* Main divider byte 1 */ +#define R0B_MD4 0x0b /* Main divider byte 4 */ +#define R0C_MD5 0x0c /* Main divider byte 5 */ +#define R0D_MD6 0x0d /* Main divider byte 6 */ +#define R0E_MD7 0x0e /* Main divider byte 7 */ +#define R0F_MD8 0x0f /* Main divider byte 8 */ +#define R10_CD1 0x10 /* Call divider byte 1 */ +#define R11_CD2 0x11 /* Call divider byte 2 */ +#define R12_CD3 0x12 /* Call divider byte 3 */ +#define R13_CD4 0x13 /* Call divider byte 4 */ +#define R14_CD5 0x14 /* Call divider byte 5 */ +#define R15_CD6 0x15 /* Call divider byte 6 */ +#define R16_CD7 0x16 /* Call divider byte 7 */ +#define R17_PD1 0x17 /* Power-down byte 1 */ +#define R18_PD2 0x18 /* Power-down byte 2 */ +#define R19_XTOUT 0x19 /* XTOUT byte */ +#define R1A_IF1 0x1a /* IF byte 1 */ +#define R1B_IF2 0x1b /* IF byte 2 */ +#define R1C_AGC2B 0x1c /* AGC2b byte */ +#define R1D_PSM2 0x1d /* PSM byte 2 */ +#define R1E_PSM3 0x1e /* PSM byte 3 */ +#define R1F_PSM4 0x1f /* PSM byte 4 */ +#define R20_AGC11 0x20 /* AGC1 byte 1 */ +#define R21_AGC12 0x21 /* AGC1 byte 2 */ +#define R22_AGC13 0x22 /* AGC1 byte 3 */ +#define R23_AGC21 0x23 /* AGC2 byte 1 */ +#define R24_AGC22 0x24 /* AGC2 byte 2 */ +#define R25_AAGC 0x25 /* Analog AGC byte */ +#define R26_RC 0x26 /* RC byte */ +#define R27_RSSI 0x27 /* RSSI byte */ +#define R28_IRCAL1 0x28 /* IR CAL byte 1 */ +#define R29_IRCAL2 0x29 /* IR CAL byte 2 */ +#define R2A_IRCAL3 0x2a /* IR CAL byte 3 */ +#define R2B_IRCAL4 0x2b /* IR CAL byte 4 */ +#define R2C_RFCAL1 0x2c /* RF CAL byte 1 */ +#define R2D_RFCAL2 0x2d /* RF CAL byte 2 */ +#define R2E_RFCAL3 0x2e /* RF CAL byte 3 */ +#define R2F_RFCAL4 0x2f /* RF CAL byte 4 */ +#define R30_RFCAL5 0x30 /* RF CAL byte 5 */ +#define R31_RFCAL6 0x31 /* RF CAL byte 6 */ +#define R32_RFCAL7 0x32 /* RF CAL byte 7 */ +#define R33_RFCAL8 0x33 /* RF CAL byte 8 */ +#define R34_RFCAL9 0x34 /* RF CAL byte 9 */ +#define R35_RFCAL10 0x35 /* RF CAL byte 10 */ +#define R36_RFCALRAM1 0x36 /* RF CAL RAM byte 1 */ +#define R37_RFCALRAM2 0x37 /* RF CAL RAM byte 2 */ +#define R38_MARGIN 0x38 /* Margin byte */ +#define R39_FMAX1 0x39 /* Fmax byte 1 */ +#define R3A_FMAX2 0x3a /* Fmax byte 2 */ + +#define TDA18218_NUM_REGS 59 + +struct tda18218_priv { + struct tda18218_config *cfg; + struct i2c_adapter *i2c; + + u32 if_frequency; + + u8 regs[TDA18218_NUM_REGS]; +}; + +#endif diff --git a/drivers/media/tuners/tda18271-common.c b/drivers/media/tuners/tda18271-common.c new file mode 100644 index 000000000000..39c645787b62 --- /dev/null +++ b/drivers/media/tuners/tda18271-common.c @@ -0,0 +1,703 @@ +/* + tda18271-common.c - driver for the Philips / NXP TDA18271 silicon tuner + + Copyright (C) 2007, 2008 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 "tda18271-priv.h" + +static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct tda18271_priv *priv = fe->tuner_priv; + enum tda18271_i2c_gate gate; + int ret = 0; + + switch (priv->gate) { + case TDA18271_GATE_DIGITAL: + case TDA18271_GATE_ANALOG: + gate = priv->gate; + break; + case TDA18271_GATE_AUTO: + default: + switch (priv->mode) { + case TDA18271_DIGITAL: + gate = TDA18271_GATE_DIGITAL; + break; + case TDA18271_ANALOG: + default: + gate = TDA18271_GATE_ANALOG; + break; + } + } + + switch (gate) { + case TDA18271_GATE_ANALOG: + if (fe->ops.analog_ops.i2c_gate_ctrl) + ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable); + break; + case TDA18271_GATE_DIGITAL: + if (fe->ops.i2c_gate_ctrl) + ret = fe->ops.i2c_gate_ctrl(fe, enable); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +}; + +/*---------------------------------------------------------------------*/ + +static void tda18271_dump_regs(struct dvb_frontend *fe, int extended) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + tda_reg("=== TDA18271 REG DUMP ===\n"); + tda_reg("ID_BYTE = 0x%02x\n", 0xff & regs[R_ID]); + tda_reg("THERMO_BYTE = 0x%02x\n", 0xff & regs[R_TM]); + tda_reg("POWER_LEVEL_BYTE = 0x%02x\n", 0xff & regs[R_PL]); + tda_reg("EASY_PROG_BYTE_1 = 0x%02x\n", 0xff & regs[R_EP1]); + tda_reg("EASY_PROG_BYTE_2 = 0x%02x\n", 0xff & regs[R_EP2]); + tda_reg("EASY_PROG_BYTE_3 = 0x%02x\n", 0xff & regs[R_EP3]); + tda_reg("EASY_PROG_BYTE_4 = 0x%02x\n", 0xff & regs[R_EP4]); + tda_reg("EASY_PROG_BYTE_5 = 0x%02x\n", 0xff & regs[R_EP5]); + tda_reg("CAL_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_CPD]); + tda_reg("CAL_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_CD1]); + tda_reg("CAL_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_CD2]); + tda_reg("CAL_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_CD3]); + tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]); + tda_reg("MAIN_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_MD1]); + tda_reg("MAIN_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_MD2]); + tda_reg("MAIN_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_MD3]); + + /* only dump extended regs if DBG_ADV is set */ + if (!(tda18271_debug & DBG_ADV)) + return; + + /* W indicates write-only registers. + * Register dump for write-only registers shows last value written. */ + + tda_reg("EXTENDED_BYTE_1 = 0x%02x\n", 0xff & regs[R_EB1]); + tda_reg("EXTENDED_BYTE_2 = 0x%02x\n", 0xff & regs[R_EB2]); + tda_reg("EXTENDED_BYTE_3 = 0x%02x\n", 0xff & regs[R_EB3]); + tda_reg("EXTENDED_BYTE_4 = 0x%02x\n", 0xff & regs[R_EB4]); + tda_reg("EXTENDED_BYTE_5 = 0x%02x\n", 0xff & regs[R_EB5]); + tda_reg("EXTENDED_BYTE_6 = 0x%02x\n", 0xff & regs[R_EB6]); + tda_reg("EXTENDED_BYTE_7 = 0x%02x\n", 0xff & regs[R_EB7]); + tda_reg("EXTENDED_BYTE_8 = 0x%02x\n", 0xff & regs[R_EB8]); + tda_reg("EXTENDED_BYTE_9 W = 0x%02x\n", 0xff & regs[R_EB9]); + tda_reg("EXTENDED_BYTE_10 = 0x%02x\n", 0xff & regs[R_EB10]); + tda_reg("EXTENDED_BYTE_11 = 0x%02x\n", 0xff & regs[R_EB11]); + tda_reg("EXTENDED_BYTE_12 = 0x%02x\n", 0xff & regs[R_EB12]); + tda_reg("EXTENDED_BYTE_13 = 0x%02x\n", 0xff & regs[R_EB13]); + tda_reg("EXTENDED_BYTE_14 = 0x%02x\n", 0xff & regs[R_EB14]); + tda_reg("EXTENDED_BYTE_15 = 0x%02x\n", 0xff & regs[R_EB15]); + tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]); + tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]); + tda_reg("EXTENDED_BYTE_18 = 0x%02x\n", 0xff & regs[R_EB18]); + tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]); + tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]); + tda_reg("EXTENDED_BYTE_21 = 0x%02x\n", 0xff & regs[R_EB21]); + tda_reg("EXTENDED_BYTE_22 = 0x%02x\n", 0xff & regs[R_EB22]); + tda_reg("EXTENDED_BYTE_23 = 0x%02x\n", 0xff & regs[R_EB23]); +} + +int tda18271_read_regs(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char buf = 0x00; + int ret; + struct i2c_msg msg[] = { + { .addr = priv->i2c_props.addr, .flags = 0, + .buf = &buf, .len = 1 }, + { .addr = priv->i2c_props.addr, .flags = I2C_M_RD, + .buf = regs, .len = 16 } + }; + + tda18271_i2c_gate_ctrl(fe, 1); + + /* read all registers */ + ret = i2c_transfer(priv->i2c_props.adap, msg, 2); + + tda18271_i2c_gate_ctrl(fe, 0); + + if (ret != 2) + tda_err("ERROR: i2c_transfer returned: %d\n", ret); + + if (tda18271_debug & DBG_REG) + tda18271_dump_regs(fe, 0); + + return (ret == 2 ? 0 : ret); +} + +int tda18271_read_extended(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char regdump[TDA18271_NUM_REGS]; + unsigned char buf = 0x00; + int ret, i; + struct i2c_msg msg[] = { + { .addr = priv->i2c_props.addr, .flags = 0, + .buf = &buf, .len = 1 }, + { .addr = priv->i2c_props.addr, .flags = I2C_M_RD, + .buf = regdump, .len = TDA18271_NUM_REGS } + }; + + tda18271_i2c_gate_ctrl(fe, 1); + + /* read all registers */ + ret = i2c_transfer(priv->i2c_props.adap, msg, 2); + + tda18271_i2c_gate_ctrl(fe, 0); + + if (ret != 2) + tda_err("ERROR: i2c_transfer returned: %d\n", ret); + + for (i = 0; i < TDA18271_NUM_REGS; i++) { + /* don't update write-only registers */ + if ((i != R_EB9) && + (i != R_EB16) && + (i != R_EB17) && + (i != R_EB19) && + (i != R_EB20)) + regs[i] = regdump[i]; + } + + if (tda18271_debug & DBG_REG) + tda18271_dump_regs(fe, 1); + + return (ret == 2 ? 0 : ret); +} + +int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char buf[TDA18271_NUM_REGS + 1]; + struct i2c_msg msg = { .addr = priv->i2c_props.addr, .flags = 0, + .buf = buf }; + int i, ret = 1, max; + + BUG_ON((len == 0) || (idx + len > sizeof(buf))); + + + switch (priv->small_i2c) { + case TDA18271_03_BYTE_CHUNK_INIT: + max = 3; + break; + case TDA18271_08_BYTE_CHUNK_INIT: + max = 8; + break; + case TDA18271_16_BYTE_CHUNK_INIT: + max = 16; + break; + case TDA18271_39_BYTE_CHUNK_INIT: + default: + max = 39; + } + + tda18271_i2c_gate_ctrl(fe, 1); + while (len) { + if (max > len) + max = len; + + buf[0] = idx; + for (i = 1; i <= max; i++) + buf[i] = regs[idx - 1 + i]; + + msg.len = max + 1; + + /* write registers */ + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); + if (ret != 1) + break; + + idx += max; + len -= max; + } + tda18271_i2c_gate_ctrl(fe, 0); + + if (ret != 1) + tda_err("ERROR: idx = 0x%x, len = %d, " + "i2c_transfer returned: %d\n", idx, max, ret); + + return (ret == 1 ? 0 : ret); +} + +/*---------------------------------------------------------------------*/ + +int tda18271_charge_pump_source(struct dvb_frontend *fe, + enum tda18271_pll pll, int force) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + int r_cp = (pll == TDA18271_CAL_PLL) ? R_EB7 : R_EB4; + + regs[r_cp] &= ~0x20; + regs[r_cp] |= ((force & 1) << 5); + + return tda18271_write_regs(fe, r_cp, 1); +} + +int tda18271_init_regs(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + tda_dbg("initializing registers for device @ %d-%04x\n", + i2c_adapter_id(priv->i2c_props.adap), + priv->i2c_props.addr); + + /* initialize registers */ + switch (priv->id) { + case TDA18271HDC1: + regs[R_ID] = 0x83; + break; + case TDA18271HDC2: + regs[R_ID] = 0x84; + break; + }; + + regs[R_TM] = 0x08; + regs[R_PL] = 0x80; + regs[R_EP1] = 0xc6; + regs[R_EP2] = 0xdf; + regs[R_EP3] = 0x16; + regs[R_EP4] = 0x60; + regs[R_EP5] = 0x80; + regs[R_CPD] = 0x80; + regs[R_CD1] = 0x00; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0x00; + regs[R_MD1] = 0x00; + regs[R_MD2] = 0x00; + regs[R_MD3] = 0x00; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB1] = 0xff; + break; + case TDA18271HDC2: + regs[R_EB1] = 0xfc; + break; + }; + + regs[R_EB2] = 0x01; + regs[R_EB3] = 0x84; + regs[R_EB4] = 0x41; + regs[R_EB5] = 0x01; + regs[R_EB6] = 0x84; + regs[R_EB7] = 0x40; + regs[R_EB8] = 0x07; + regs[R_EB9] = 0x00; + regs[R_EB10] = 0x00; + regs[R_EB11] = 0x96; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB12] = 0x0f; + break; + case TDA18271HDC2: + regs[R_EB12] = 0x33; + break; + }; + + regs[R_EB13] = 0xc1; + regs[R_EB14] = 0x00; + regs[R_EB15] = 0x8f; + regs[R_EB16] = 0x00; + regs[R_EB17] = 0x00; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB18] = 0x00; + break; + case TDA18271HDC2: + regs[R_EB18] = 0x8c; + break; + }; + + regs[R_EB19] = 0x00; + regs[R_EB20] = 0x20; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB21] = 0x33; + break; + case TDA18271HDC2: + regs[R_EB21] = 0xb3; + break; + }; + + regs[R_EB22] = 0x48; + regs[R_EB23] = 0xb0; + + tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); + + /* setup agc1 gain */ + regs[R_EB17] = 0x00; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x03; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x43; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x4c; + tda18271_write_regs(fe, R_EB17, 1); + + /* setup agc2 gain */ + if ((priv->id) == TDA18271HDC1) { + regs[R_EB20] = 0xa0; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xa7; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xe7; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xec; + tda18271_write_regs(fe, R_EB20, 1); + } + + /* image rejection calibration */ + + /* low-band */ + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x81; + regs[R_CPD] = 0xcc; + regs[R_CD1] = 0x6c; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0xcd; + regs[R_MD1] = 0x77; + regs[R_MD2] = 0x08; + regs[R_MD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 11); + + if ((priv->id) == TDA18271HDC2) { + /* main pll cp source on */ + tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1); + msleep(1); + + /* main pll cp source off */ + tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0); + } + + msleep(5); /* pll locking */ + + /* launch detector */ + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted low measurement */ + + regs[R_EP5] = 0x85; + regs[R_CPD] = 0xcb; + regs[R_CD1] = 0x66; + regs[R_CD2] = 0x70; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + /* launch optimization algorithm */ + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image low optimization completion */ + + /* mid-band */ + regs[R_EP5] = 0x82; + regs[R_CPD] = 0xa8; + regs[R_CD2] = 0x00; + regs[R_MPD] = 0xa9; + regs[R_MD1] = 0x73; + regs[R_MD2] = 0x1a; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* pll locking */ + + /* launch detector */ + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted mid measurement */ + + regs[R_EP5] = 0x86; + regs[R_CPD] = 0xa8; + regs[R_CD1] = 0x66; + regs[R_CD2] = 0xa0; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + /* launch optimization algorithm */ + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image mid optimization completion */ + + /* high-band */ + regs[R_EP5] = 0x83; + regs[R_CPD] = 0x98; + regs[R_CD1] = 0x65; + regs[R_CD2] = 0x00; + regs[R_MPD] = 0x99; + regs[R_MD1] = 0x71; + regs[R_MD2] = 0xcd; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* pll locking */ + + /* launch detector */ + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted high measurement */ + + regs[R_EP5] = 0x87; + regs[R_CD1] = 0x65; + regs[R_CD2] = 0x50; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + /* launch optimization algorithm */ + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image high optimization completion */ + + /* return to normal mode */ + regs[R_EP4] = 0x64; + tda18271_write_regs(fe, R_EP4, 1); + + /* synchronize */ + tda18271_write_regs(fe, R_EP1, 1); + + return 0; +} + +/*---------------------------------------------------------------------*/ + +/* + * Standby modes, EP3 [7:5] + * + * | SM || SM_LT || SM_XT || mode description + * |=====\\=======\\=======\\=================================== + * | 0 || 0 || 0 || normal mode + * |-----||-------||-------||----------------------------------- + * | || || || standby mode w/ slave tuner output + * | 1 || 0 || 0 || & loop thru & xtal oscillator on + * |-----||-------||-------||----------------------------------- + * | 1 || 1 || 0 || standby mode w/ xtal oscillator on + * |-----||-------||-------||----------------------------------- + * | 1 || 1 || 1 || power off + * + */ + +int tda18271_set_standby_mode(struct dvb_frontend *fe, + int sm, int sm_lt, int sm_xt) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + if (tda18271_debug & DBG_ADV) + tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt); + + regs[R_EP3] &= ~0xe0; /* clear sm, sm_lt, sm_xt */ + regs[R_EP3] |= (sm ? (1 << 7) : 0) | + (sm_lt ? (1 << 6) : 0) | + (sm_xt ? (1 << 5) : 0); + + return tda18271_write_regs(fe, R_EP3, 1); +} + +/*---------------------------------------------------------------------*/ + +int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) +{ + /* sets main post divider & divider bytes, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 d, pd; + u32 div; + + int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d); + if (tda_fail(ret)) + goto fail; + + regs[R_MPD] = (0x7f & pd); + + div = ((d * (freq / 1000)) << 7) / 125; + + regs[R_MD1] = 0x7f & (div >> 16); + regs[R_MD2] = 0xff & (div >> 8); + regs[R_MD3] = 0xff & div; +fail: + return ret; +} + +int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq) +{ + /* sets cal post divider & divider bytes, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 d, pd; + u32 div; + + int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d); + if (tda_fail(ret)) + goto fail; + + regs[R_CPD] = pd; + + div = ((d * (freq / 1000)) << 7) / 125; + + regs[R_CD1] = 0x7f & (div >> 16); + regs[R_CD2] = 0xff & (div >> 8); + regs[R_CD3] = 0xff & div; +fail: + return ret; +} + +/*---------------------------------------------------------------------*/ + +int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq) +{ + /* sets bp filter bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val); + if (tda_fail(ret)) + goto fail; + + regs[R_EP1] &= ~0x07; /* clear bp filter bits */ + regs[R_EP1] |= (0x07 & val); +fail: + return ret; +} + +int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq) +{ + /* sets K & M bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val); + if (tda_fail(ret)) + goto fail; + + regs[R_EB13] &= ~0x7c; /* clear k & m bits */ + regs[R_EB13] |= (0x7c & val); +fail: + return ret; +} + +int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq) +{ + /* sets rf band bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val); + if (tda_fail(ret)) + goto fail; + + regs[R_EP2] &= ~0xe0; /* clear rf band bits */ + regs[R_EP2] |= (0xe0 & (val << 5)); +fail: + return ret; +} + +int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq) +{ + /* sets gain taper bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val); + if (tda_fail(ret)) + goto fail; + + regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ + regs[R_EP2] |= (0x1f & val); +fail: + return ret; +} + +int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq) +{ + /* sets IR Meas bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val); + if (tda_fail(ret)) + goto fail; + + regs[R_EP5] &= ~0x07; + regs[R_EP5] |= (0x07 & val); +fail: + return ret; +} + +int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq) +{ + /* sets rf cal byte (RFC_Cprog), but does not write it */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, RF_CAL, freq, &val); + /* The TDA18271HD/C1 rf_cal map lookup is expected to go out of range + * for frequencies above 61.1 MHz. In these cases, the internal RF + * tracking filters calibration mechanism is used. + * + * There is no need to warn the user about this. + */ + if (ret < 0) + goto fail; + + regs[R_EB14] = val; +fail: + return ret; +} + +int _tda_printk(struct tda18271_priv *state, const char *level, + const char *func, const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + int rtn; + + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + if (state) + rtn = printk("%s%s: [%d-%04x|%c] %pV", + level, func, i2c_adapter_id(state->i2c_props.adap), + state->i2c_props.addr, + (state->role == TDA18271_MASTER) ? 'M' : 'S', + &vaf); + else + rtn = printk("%s%s: %pV", level, func, &vaf); + + va_end(args); + + return rtn; +} diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c new file mode 100644 index 000000000000..2e67f4459904 --- /dev/null +++ b/drivers/media/tuners/tda18271-fe.c @@ -0,0 +1,1345 @@ +/* + tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner + + Copyright (C) 2007, 2008 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 +#include +#include "tda18271-priv.h" + +int tda18271_debug; +module_param_named(debug, tda18271_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debug level " + "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))"); + +static int tda18271_cal_on_startup = -1; +module_param_named(cal, tda18271_cal_on_startup, int, 0644); +MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup"); + +static DEFINE_MUTEX(tda18271_list_mutex); +static LIST_HEAD(hybrid_tuner_instance_list); + +/*---------------------------------------------------------------------*/ + +static int tda18271_toggle_output(struct dvb_frontend *fe, int standby) +{ + struct tda18271_priv *priv = fe->tuner_priv; + + int ret = tda18271_set_standby_mode(fe, standby ? 1 : 0, + priv->output_opt & TDA18271_OUTPUT_LT_OFF ? 1 : 0, + priv->output_opt & TDA18271_OUTPUT_XT_OFF ? 1 : 0); + + if (tda_fail(ret)) + goto fail; + + tda_dbg("%s mode: xtal oscillator %s, slave tuner loop thru %s\n", + standby ? "standby" : "active", + priv->output_opt & TDA18271_OUTPUT_XT_OFF ? "off" : "on", + priv->output_opt & TDA18271_OUTPUT_LT_OFF ? "off" : "on"); +fail: + return ret; +} + +/*---------------------------------------------------------------------*/ + +static inline int charge_pump_source(struct dvb_frontend *fe, int force) +{ + struct tda18271_priv *priv = fe->tuner_priv; + return tda18271_charge_pump_source(fe, + (priv->role == TDA18271_SLAVE) ? + TDA18271_CAL_PLL : + TDA18271_MAIN_PLL, force); +} + +static inline void tda18271_set_if_notch(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x80; /* IF notch = 0 */ + break; + case TDA18271_DIGITAL: + regs[R_MPD] |= 0x80; /* IF notch = 1 */ + break; + } +} + +static int tda18271_channel_configuration(struct dvb_frontend *fe, + struct tda18271_std_map_item *map, + u32 freq, u32 bw) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int ret; + u32 N; + + /* update TV broadcast parameters */ + + /* set standard */ + regs[R_EP3] &= ~0x1f; /* clear std bits */ + regs[R_EP3] |= (map->agc_mode << 3) | map->std; + + if (priv->id == TDA18271HDC2) { + /* set rfagc to high speed mode */ + regs[R_EP3] &= ~0x04; + } + + /* set cal mode to normal */ + regs[R_EP4] &= ~0x03; + + /* update IF output level */ + regs[R_EP4] &= ~0x1c; /* clear if level bits */ + regs[R_EP4] |= (map->if_lvl << 2); + + /* update FM_RFn */ + regs[R_EP4] &= ~0x80; + regs[R_EP4] |= map->fm_rfn << 7; + + /* update rf top / if top */ + regs[R_EB22] = 0x00; + regs[R_EB22] |= map->rfagc_top; + ret = tda18271_write_regs(fe, R_EB22, 1); + if (tda_fail(ret)) + goto fail; + + /* --------------------------------------------------------------- */ + + /* disable Power Level Indicator */ + regs[R_EP1] |= 0x40; + + /* make sure thermometer is off */ + regs[R_TM] &= ~0x10; + + /* frequency dependent parameters */ + + tda18271_calc_ir_measure(fe, &freq); + + tda18271_calc_bp_filter(fe, &freq); + + tda18271_calc_rf_band(fe, &freq); + + tda18271_calc_gain_taper(fe, &freq); + + /* --------------------------------------------------------------- */ + + /* dual tuner and agc1 extra configuration */ + + switch (priv->role) { + case TDA18271_MASTER: + regs[R_EB1] |= 0x04; /* main vco */ + break; + case TDA18271_SLAVE: + regs[R_EB1] &= ~0x04; /* cal vco */ + break; + } + + /* agc1 always active */ + regs[R_EB1] &= ~0x02; + + /* agc1 has priority on agc2 */ + regs[R_EB1] &= ~0x01; + + ret = tda18271_write_regs(fe, R_EB1, 1); + if (tda_fail(ret)) + goto fail; + + /* --------------------------------------------------------------- */ + + N = map->if_freq * 1000 + freq; + + switch (priv->role) { + case TDA18271_MASTER: + tda18271_calc_main_pll(fe, N); + tda18271_set_if_notch(fe); + tda18271_write_regs(fe, R_MPD, 4); + break; + case TDA18271_SLAVE: + tda18271_calc_cal_pll(fe, N); + tda18271_write_regs(fe, R_CPD, 4); + + regs[R_MPD] = regs[R_CPD] & 0x7f; + tda18271_set_if_notch(fe); + tda18271_write_regs(fe, R_MPD, 1); + break; + } + + ret = tda18271_write_regs(fe, R_TM, 7); + if (tda_fail(ret)) + goto fail; + + /* force charge pump source */ + charge_pump_source(fe, 1); + + msleep(1); + + /* return pll to normal operation */ + charge_pump_source(fe, 0); + + msleep(20); + + if (priv->id == TDA18271HDC2) { + /* set rfagc to normal speed mode */ + if (map->fm_rfn) + regs[R_EP3] &= ~0x04; + else + regs[R_EP3] |= 0x04; + ret = tda18271_write_regs(fe, R_EP3, 1); + } +fail: + return ret; +} + +static int tda18271_read_thermometer(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int tm; + + /* switch thermometer on */ + regs[R_TM] |= 0x10; + tda18271_write_regs(fe, R_TM, 1); + + /* read thermometer info */ + tda18271_read_regs(fe); + + if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) || + (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) { + + if ((regs[R_TM] & 0x20) == 0x20) + regs[R_TM] &= ~0x20; + else + regs[R_TM] |= 0x20; + + tda18271_write_regs(fe, R_TM, 1); + + msleep(10); /* temperature sensing */ + + /* read thermometer info */ + tda18271_read_regs(fe); + } + + tm = tda18271_lookup_thermometer(fe); + + /* switch thermometer off */ + regs[R_TM] &= ~0x10; + tda18271_write_regs(fe, R_TM, 1); + + /* set CAL mode to normal */ + regs[R_EP4] &= ~0x03; + tda18271_write_regs(fe, R_EP4, 1); + + return tm; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe, + u32 freq) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; + unsigned char *regs = priv->tda18271_regs; + int i, ret; + u8 tm_current, dc_over_dt, rf_tab; + s32 rfcal_comp, approx; + + /* power up */ + ret = tda18271_set_standby_mode(fe, 0, 0, 0); + if (tda_fail(ret)) + goto fail; + + /* read die current temperature */ + tm_current = tda18271_read_thermometer(fe); + + /* frequency dependent parameters */ + + tda18271_calc_rf_cal(fe, &freq); + rf_tab = regs[R_EB14]; + + i = tda18271_lookup_rf_band(fe, &freq, NULL); + if (tda_fail(i)) + return i; + + if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) { + approx = map[i].rf_a1 * (s32)(freq / 1000 - map[i].rf1) + + map[i].rf_b1 + rf_tab; + } else { + approx = map[i].rf_a2 * (s32)(freq / 1000 - map[i].rf2) + + map[i].rf_b2 + rf_tab; + } + + if (approx < 0) + approx = 0; + if (approx > 255) + approx = 255; + + tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt); + + /* calculate temperature compensation */ + rfcal_comp = dc_over_dt * (s32)(tm_current - priv->tm_rfcal) / 1000; + + regs[R_EB14] = (unsigned char)(approx + rfcal_comp); + ret = tda18271_write_regs(fe, R_EB14, 1); +fail: + return ret; +} + +static int tda18271_por(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int ret; + + /* power up detector 1 */ + regs[R_EB12] &= ~0x20; + ret = tda18271_write_regs(fe, R_EB12, 1); + if (tda_fail(ret)) + goto fail; + + regs[R_EB18] &= ~0x80; /* turn agc1 loop on */ + regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ + ret = tda18271_write_regs(fe, R_EB18, 1); + if (tda_fail(ret)) + goto fail; + + regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */ + + /* POR mode */ + ret = tda18271_set_standby_mode(fe, 1, 0, 0); + if (tda_fail(ret)) + goto fail; + + /* disable 1.5 MHz low pass filter */ + regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */ + regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */ + ret = tda18271_write_regs(fe, R_EB21, 3); +fail: + return ret; +} + +static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u32 N; + + /* set CAL mode to normal */ + regs[R_EP4] &= ~0x03; + tda18271_write_regs(fe, R_EP4, 1); + + /* switch off agc1 */ + regs[R_EP3] |= 0x40; /* sm_lt = 1 */ + + regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */ + tda18271_write_regs(fe, R_EB18, 1); + + /* frequency dependent parameters */ + + tda18271_calc_bp_filter(fe, &freq); + tda18271_calc_gain_taper(fe, &freq); + tda18271_calc_rf_band(fe, &freq); + tda18271_calc_km(fe, &freq); + + tda18271_write_regs(fe, R_EP1, 3); + tda18271_write_regs(fe, R_EB13, 1); + + /* main pll charge pump source */ + tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1); + + /* cal pll charge pump source */ + tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 1); + + /* force dcdc converter to 0 V */ + regs[R_EB14] = 0x00; + tda18271_write_regs(fe, R_EB14, 1); + + /* disable plls lock */ + regs[R_EB20] &= ~0x20; + tda18271_write_regs(fe, R_EB20, 1); + + /* set CAL mode to RF tracking filter calibration */ + regs[R_EP4] |= 0x03; + tda18271_write_regs(fe, R_EP4, 2); + + /* --------------------------------------------------------------- */ + + /* set the internal calibration signal */ + N = freq; + + tda18271_calc_cal_pll(fe, N); + tda18271_write_regs(fe, R_CPD, 4); + + /* downconvert internal calibration */ + N += 1000000; + + tda18271_calc_main_pll(fe, N); + tda18271_write_regs(fe, R_MPD, 4); + + msleep(5); + + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + + /* --------------------------------------------------------------- */ + + /* normal operation for the main pll */ + tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0); + + /* normal operation for the cal pll */ + tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 0); + + msleep(10); /* plls locking */ + + /* launch the rf tracking filters calibration */ + regs[R_EB20] |= 0x20; + tda18271_write_regs(fe, R_EB20, 1); + + msleep(60); /* calibration */ + + /* --------------------------------------------------------------- */ + + /* set CAL mode to normal */ + regs[R_EP4] &= ~0x03; + + /* switch on agc1 */ + regs[R_EP3] &= ~0x40; /* sm_lt = 0 */ + + regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ + tda18271_write_regs(fe, R_EB18, 1); + + tda18271_write_regs(fe, R_EP3, 2); + + /* synchronization */ + tda18271_write_regs(fe, R_EP1, 1); + + /* get calibration result */ + tda18271_read_extended(fe); + + return regs[R_EB14]; +} + +static int tda18271_powerscan(struct dvb_frontend *fe, + u32 *freq_in, u32 *freq_out) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int sgn, bcal, count, wait, ret; + u8 cid_target; + u16 count_limit; + u32 freq; + + freq = *freq_in; + + tda18271_calc_rf_band(fe, &freq); + tda18271_calc_rf_cal(fe, &freq); + tda18271_calc_gain_taper(fe, &freq); + tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit); + + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EB14, 1); + + /* downconvert frequency */ + freq += 1000000; + + tda18271_calc_main_pll(fe, freq); + tda18271_write_regs(fe, R_MPD, 4); + + msleep(5); /* pll locking */ + + /* detection mode */ + regs[R_EP4] &= ~0x03; + regs[R_EP4] |= 0x01; + tda18271_write_regs(fe, R_EP4, 1); + + /* launch power detection measurement */ + tda18271_write_regs(fe, R_EP2, 1); + + /* read power detection info, stored in EB10 */ + ret = tda18271_read_extended(fe); + if (tda_fail(ret)) + return ret; + + /* algorithm initialization */ + sgn = 1; + *freq_out = *freq_in; + bcal = 0; + count = 0; + wait = false; + + while ((regs[R_EB10] & 0x3f) < cid_target) { + /* downconvert updated freq to 1 MHz */ + freq = *freq_in + (sgn * count) + 1000000; + + tda18271_calc_main_pll(fe, freq); + tda18271_write_regs(fe, R_MPD, 4); + + if (wait) { + msleep(5); /* pll locking */ + wait = false; + } else + udelay(100); /* pll locking */ + + /* launch power detection measurement */ + tda18271_write_regs(fe, R_EP2, 1); + + /* read power detection info, stored in EB10 */ + ret = tda18271_read_extended(fe); + if (tda_fail(ret)) + return ret; + + count += 200; + + if (count <= count_limit) + continue; + + if (sgn <= 0) + break; + + sgn = -1 * sgn; + count = 200; + wait = true; + } + + if ((regs[R_EB10] & 0x3f) >= cid_target) { + bcal = 1; + *freq_out = freq - 1000000; + } else + bcal = 0; + + tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n", + bcal, *freq_in, *freq_out, freq); + + return bcal; +} + +static int tda18271_powerscan_init(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int ret; + + /* set standard to digital */ + regs[R_EP3] &= ~0x1f; /* clear std bits */ + regs[R_EP3] |= 0x12; + + /* set cal mode to normal */ + regs[R_EP4] &= ~0x03; + + /* update IF output level */ + regs[R_EP4] &= ~0x1c; /* clear if level bits */ + + ret = tda18271_write_regs(fe, R_EP3, 2); + if (tda_fail(ret)) + goto fail; + + regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ + ret = tda18271_write_regs(fe, R_EB18, 1); + if (tda_fail(ret)) + goto fail; + + regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */ + + /* 1.5 MHz low pass filter */ + regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */ + regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */ + + ret = tda18271_write_regs(fe, R_EB21, 3); +fail: + return ret; +} + +static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; + unsigned char *regs = priv->tda18271_regs; + int bcal, rf, i; + s32 divisor, dividend; +#define RF1 0 +#define RF2 1 +#define RF3 2 + u32 rf_default[3]; + u32 rf_freq[3]; + s32 prog_cal[3]; + s32 prog_tab[3]; + + i = tda18271_lookup_rf_band(fe, &freq, NULL); + + if (tda_fail(i)) + return i; + + rf_default[RF1] = 1000 * map[i].rf1_def; + rf_default[RF2] = 1000 * map[i].rf2_def; + rf_default[RF3] = 1000 * map[i].rf3_def; + + for (rf = RF1; rf <= RF3; rf++) { + if (0 == rf_default[rf]) + return 0; + tda_cal("freq = %d, rf = %d\n", freq, rf); + + /* look for optimized calibration frequency */ + bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]); + if (tda_fail(bcal)) + return bcal; + + tda18271_calc_rf_cal(fe, &rf_freq[rf]); + prog_tab[rf] = (s32)regs[R_EB14]; + + if (1 == bcal) + prog_cal[rf] = + (s32)tda18271_calibrate_rf(fe, rf_freq[rf]); + else + prog_cal[rf] = prog_tab[rf]; + + switch (rf) { + case RF1: + map[i].rf_a1 = 0; + map[i].rf_b1 = (prog_cal[RF1] - prog_tab[RF1]); + map[i].rf1 = rf_freq[RF1] / 1000; + break; + case RF2: + dividend = (prog_cal[RF2] - prog_tab[RF2] - + prog_cal[RF1] + prog_tab[RF1]); + divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000; + map[i].rf_a1 = (dividend / divisor); + map[i].rf2 = rf_freq[RF2] / 1000; + break; + case RF3: + dividend = (prog_cal[RF3] - prog_tab[RF3] - + prog_cal[RF2] + prog_tab[RF2]); + divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000; + map[i].rf_a2 = (dividend / divisor); + map[i].rf_b2 = (prog_cal[RF2] - prog_tab[RF2]); + map[i].rf3 = rf_freq[RF3] / 1000; + break; + default: + BUG(); + } + } + + return 0; +} + +static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned int i; + int ret; + + tda_info("tda18271: performing RF tracking filter calibration\n"); + + /* wait for die temperature stabilization */ + msleep(200); + + ret = tda18271_powerscan_init(fe); + if (tda_fail(ret)) + goto fail; + + /* rf band calibration */ + for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++) { + ret = + tda18271_rf_tracking_filters_init(fe, 1000 * + priv->rf_cal_state[i].rfmax); + if (tda_fail(ret)) + goto fail; + } + + priv->tm_rfcal = tda18271_read_thermometer(fe); +fail: + return ret; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271c2_rf_cal_init(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int ret; + + /* test RF_CAL_OK to see if we need init */ + if ((regs[R_EP1] & 0x10) == 0) + priv->cal_initialized = false; + + if (priv->cal_initialized) + return 0; + + ret = tda18271_calc_rf_filter_curve(fe); + if (tda_fail(ret)) + goto fail; + + ret = tda18271_por(fe); + if (tda_fail(ret)) + goto fail; + + tda_info("tda18271: RF tracking filter calibration complete\n"); + + priv->cal_initialized = true; + goto end; +fail: + tda_info("tda18271: RF tracking filter calibration failed!\n"); +end: + return ret; +} + +static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe, + u32 freq, u32 bw) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int ret; + u32 N = 0; + + /* calculate bp filter */ + tda18271_calc_bp_filter(fe, &freq); + tda18271_write_regs(fe, R_EP1, 1); + + regs[R_EB4] &= 0x07; + regs[R_EB4] |= 0x60; + tda18271_write_regs(fe, R_EB4, 1); + + regs[R_EB7] = 0x60; + tda18271_write_regs(fe, R_EB7, 1); + + regs[R_EB14] = 0x00; + tda18271_write_regs(fe, R_EB14, 1); + + regs[R_EB20] = 0xcc; + tda18271_write_regs(fe, R_EB20, 1); + + /* set cal mode to RF tracking filter calibration */ + regs[R_EP4] |= 0x03; + + /* calculate cal pll */ + + switch (priv->mode) { + case TDA18271_ANALOG: + N = freq - 1250000; + break; + case TDA18271_DIGITAL: + N = freq + bw / 2; + break; + } + + tda18271_calc_cal_pll(fe, N); + + /* calculate main pll */ + + switch (priv->mode) { + case TDA18271_ANALOG: + N = freq - 250000; + break; + case TDA18271_DIGITAL: + N = freq + bw / 2 + 1000000; + break; + } + + tda18271_calc_main_pll(fe, N); + + ret = tda18271_write_regs(fe, R_EP3, 11); + if (tda_fail(ret)) + return ret; + + msleep(5); /* RF tracking filter calibration initialization */ + + /* search for K,M,CO for RF calibration */ + tda18271_calc_km(fe, &freq); + tda18271_write_regs(fe, R_EB13, 1); + + /* search for rf band */ + tda18271_calc_rf_band(fe, &freq); + + /* search for gain taper */ + tda18271_calc_gain_taper(fe, &freq); + + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + + regs[R_EB4] &= 0x07; + regs[R_EB4] |= 0x40; + tda18271_write_regs(fe, R_EB4, 1); + + regs[R_EB7] = 0x40; + tda18271_write_regs(fe, R_EB7, 1); + msleep(10); /* pll locking */ + + regs[R_EB20] = 0xec; + tda18271_write_regs(fe, R_EB20, 1); + msleep(60); /* RF tracking filter calibration completion */ + + regs[R_EP4] &= ~0x03; /* set cal mode to normal */ + tda18271_write_regs(fe, R_EP4, 1); + + tda18271_write_regs(fe, R_EP1, 1); + + /* RF tracking filter correction for VHF_Low band */ + if (0 == tda18271_calc_rf_cal(fe, &freq)) + tda18271_write_regs(fe, R_EB14, 1); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271_ir_cal_init(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int ret; + + ret = tda18271_read_regs(fe); + if (tda_fail(ret)) + goto fail; + + /* test IR_CAL_OK to see if we need init */ + if ((regs[R_EP1] & 0x08) == 0) + ret = tda18271_init_regs(fe); +fail: + return ret; +} + +static int tda18271_init(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + int ret; + + mutex_lock(&priv->lock); + + /* full power up */ + ret = tda18271_set_standby_mode(fe, 0, 0, 0); + if (tda_fail(ret)) + goto fail; + + /* initialization */ + ret = tda18271_ir_cal_init(fe); + if (tda_fail(ret)) + goto fail; + + if (priv->id == TDA18271HDC2) + tda18271c2_rf_cal_init(fe); +fail: + mutex_unlock(&priv->lock); + + return ret; +} + +static int tda18271_sleep(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + int ret; + + mutex_lock(&priv->lock); + + /* enter standby mode, with required output features enabled */ + ret = tda18271_toggle_output(fe, 1); + + mutex_unlock(&priv->lock); + + return ret; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271_agc(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + int ret = 0; + + switch (priv->config) { + case 0: + /* no external agc configuration required */ + if (tda18271_debug & DBG_ADV) + tda_dbg("no agc configuration provided\n"); + break; + case 3: + /* switch with GPIO of saa713x */ + tda_dbg("invoking callback\n"); + if (fe->callback) + ret = fe->callback(priv->i2c_props.adap->algo_data, + DVB_FRONTEND_COMPONENT_TUNER, + TDA18271_CALLBACK_CMD_AGC_ENABLE, + priv->mode); + break; + case 1: + case 2: + default: + /* n/a - currently not supported */ + tda_err("unsupported configuration: %d\n", priv->config); + ret = -EINVAL; + break; + } + return ret; +} + +static int tda18271_tune(struct dvb_frontend *fe, + struct tda18271_std_map_item *map, u32 freq, u32 bw) +{ + struct tda18271_priv *priv = fe->tuner_priv; + int ret; + + tda_dbg("freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d\n", + freq, map->if_freq, bw, map->agc_mode, map->std); + + ret = tda18271_agc(fe); + if (tda_fail(ret)) + tda_warn("failed to configure agc\n"); + + ret = tda18271_init(fe); + if (tda_fail(ret)) + goto fail; + + mutex_lock(&priv->lock); + + switch (priv->id) { + case TDA18271HDC1: + tda18271c1_rf_tracking_filter_calibration(fe, freq, bw); + break; + case TDA18271HDC2: + tda18271c2_rf_tracking_filters_correction(fe, freq); + break; + } + ret = tda18271_channel_configuration(fe, map, freq, bw); + + mutex_unlock(&priv->lock); +fail: + return ret; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; + u32 freq = c->frequency; + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_std_map *std_map = &priv->std; + struct tda18271_std_map_item *map; + int ret; + + priv->mode = TDA18271_DIGITAL; + + switch (delsys) { + case SYS_ATSC: + map = &std_map->atsc_6; + bw = 6000000; + break; + case SYS_ISDBT: + case SYS_DVBT: + case SYS_DVBT2: + if (bw <= 6000000) { + map = &std_map->dvbt_6; + } else if (bw <= 7000000) { + map = &std_map->dvbt_7; + } else { + map = &std_map->dvbt_8; + } + break; + case SYS_DVBC_ANNEX_B: + bw = 6000000; + /* falltrough */ + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + if (bw <= 6000000) { + map = &std_map->qam_6; + } else if (bw <= 7000000) { + map = &std_map->qam_7; + } else { + map = &std_map->qam_8; + } + break; + default: + tda_warn("modulation type not supported!\n"); + return -EINVAL; + } + + /* When tuning digital, the analog demod must be tri-stated */ + if (fe->ops.analog_ops.standby) + fe->ops.analog_ops.standby(fe); + + ret = tda18271_tune(fe, map, freq, bw); + + if (tda_fail(ret)) + goto fail; + + priv->if_freq = map->if_freq; + priv->frequency = freq; + priv->bandwidth = bw; +fail: + return ret; +} + +static int tda18271_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_std_map *std_map = &priv->std; + struct tda18271_std_map_item *map; + char *mode; + int ret; + u32 freq = params->frequency * 125 * + ((params->mode == V4L2_TUNER_RADIO) ? 1 : 1000) / 2; + + priv->mode = TDA18271_ANALOG; + + if (params->mode == V4L2_TUNER_RADIO) { + map = &std_map->fm_radio; + mode = "fm"; + } else if (params->std & V4L2_STD_MN) { + map = &std_map->atv_mn; + mode = "MN"; + } else if (params->std & V4L2_STD_B) { + map = &std_map->atv_b; + mode = "B"; + } else if (params->std & V4L2_STD_GH) { + map = &std_map->atv_gh; + mode = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + map = &std_map->atv_i; + mode = "I"; + } else if (params->std & V4L2_STD_DK) { + map = &std_map->atv_dk; + mode = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + map = &std_map->atv_l; + mode = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + map = &std_map->atv_lc; + mode = "L'"; + } else { + map = &std_map->atv_i; + mode = "xx"; + } + + tda_dbg("setting tda18271 to system %s\n", mode); + + ret = tda18271_tune(fe, map, freq, 0); + + if (tda_fail(ret)) + goto fail; + + priv->if_freq = map->if_freq; + priv->frequency = freq; + priv->bandwidth = 0; +fail: + return ret; +} + +static int tda18271_release(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + + mutex_lock(&tda18271_list_mutex); + + if (priv) + hybrid_tuner_release_state(priv); + + mutex_unlock(&tda18271_list_mutex); + + fe->tuner_priv = NULL; + + return 0; +} + +static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda18271_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct tda18271_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static int tda18271_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda18271_priv *priv = fe->tuner_priv; + *frequency = (u32)priv->if_freq * 1000; + return 0; +} + +/* ------------------------------------------------------------------ */ + +#define tda18271_update_std(std_cfg, name) do { \ + if (map->std_cfg.if_freq + \ + map->std_cfg.agc_mode + map->std_cfg.std + \ + map->std_cfg.if_lvl + map->std_cfg.rfagc_top > 0) { \ + tda_dbg("Using custom std config for %s\n", name); \ + memcpy(&std->std_cfg, &map->std_cfg, \ + sizeof(struct tda18271_std_map_item)); \ + } } while (0) + +#define tda18271_dump_std_item(std_cfg, name) do { \ + tda_dbg("(%s) if_freq = %d, agc_mode = %d, std = %d, " \ + "if_lvl = %d, rfagc_top = 0x%02x\n", \ + name, std->std_cfg.if_freq, \ + std->std_cfg.agc_mode, std->std_cfg.std, \ + std->std_cfg.if_lvl, std->std_cfg.rfagc_top); \ + } while (0) + +static int tda18271_dump_std_map(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_std_map *std = &priv->std; + + tda_dbg("========== STANDARD MAP SETTINGS ==========\n"); + tda18271_dump_std_item(fm_radio, " fm "); + tda18271_dump_std_item(atv_b, "atv b "); + tda18271_dump_std_item(atv_dk, "atv dk"); + tda18271_dump_std_item(atv_gh, "atv gh"); + tda18271_dump_std_item(atv_i, "atv i "); + tda18271_dump_std_item(atv_l, "atv l "); + tda18271_dump_std_item(atv_lc, "atv l'"); + tda18271_dump_std_item(atv_mn, "atv mn"); + tda18271_dump_std_item(atsc_6, "atsc 6"); + tda18271_dump_std_item(dvbt_6, "dvbt 6"); + tda18271_dump_std_item(dvbt_7, "dvbt 7"); + tda18271_dump_std_item(dvbt_8, "dvbt 8"); + tda18271_dump_std_item(qam_6, "qam 6 "); + tda18271_dump_std_item(qam_8, "qam 8 "); + + return 0; +} + +static int tda18271_update_std_map(struct dvb_frontend *fe, + struct tda18271_std_map *map) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_std_map *std = &priv->std; + + if (!map) + return -EINVAL; + + tda18271_update_std(fm_radio, "fm"); + tda18271_update_std(atv_b, "atv b"); + tda18271_update_std(atv_dk, "atv dk"); + tda18271_update_std(atv_gh, "atv gh"); + tda18271_update_std(atv_i, "atv i"); + tda18271_update_std(atv_l, "atv l"); + tda18271_update_std(atv_lc, "atv l'"); + tda18271_update_std(atv_mn, "atv mn"); + tda18271_update_std(atsc_6, "atsc 6"); + tda18271_update_std(dvbt_6, "dvbt 6"); + tda18271_update_std(dvbt_7, "dvbt 7"); + tda18271_update_std(dvbt_8, "dvbt 8"); + tda18271_update_std(qam_6, "qam 6"); + tda18271_update_std(qam_8, "qam 8"); + + return 0; +} + +static int tda18271_get_id(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + char *name; + + mutex_lock(&priv->lock); + tda18271_read_regs(fe); + mutex_unlock(&priv->lock); + + switch (regs[R_ID] & 0x7f) { + case 3: + name = "TDA18271HD/C1"; + priv->id = TDA18271HDC1; + break; + case 4: + name = "TDA18271HD/C2"; + priv->id = TDA18271HDC2; + break; + default: + tda_info("Unknown device (%i) detected @ %d-%04x, device not supported.\n", + regs[R_ID], i2c_adapter_id(priv->i2c_props.adap), + priv->i2c_props.addr); + return -EINVAL; + } + + tda_info("%s detected @ %d-%04x\n", name, + i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr); + + return 0; +} + +static int tda18271_setup_configuration(struct dvb_frontend *fe, + struct tda18271_config *cfg) +{ + struct tda18271_priv *priv = fe->tuner_priv; + + priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO; + priv->role = (cfg) ? cfg->role : TDA18271_MASTER; + priv->config = (cfg) ? cfg->config : 0; + priv->small_i2c = (cfg) ? + cfg->small_i2c : TDA18271_39_BYTE_CHUNK_INIT; + priv->output_opt = (cfg) ? + cfg->output_opt : TDA18271_OUTPUT_LT_XT_ON; + + return 0; +} + +static inline int tda18271_need_cal_on_startup(struct tda18271_config *cfg) +{ + /* tda18271_cal_on_startup == -1 when cal module option is unset */ + return ((tda18271_cal_on_startup == -1) ? + /* honor configuration setting */ + ((cfg) && (cfg->rf_cal_on_startup)) : + /* module option overrides configuration setting */ + (tda18271_cal_on_startup)) ? 1 : 0; +} + +static int tda18271_set_config(struct dvb_frontend *fe, void *priv_cfg) +{ + struct tda18271_config *cfg = (struct tda18271_config *) priv_cfg; + + tda18271_setup_configuration(fe, cfg); + + if (tda18271_need_cal_on_startup(cfg)) + tda18271_init(fe); + + /* override default std map with values in config struct */ + if ((cfg) && (cfg->std_map)) + tda18271_update_std_map(fe, cfg->std_map); + + return 0; +} + +static const struct dvb_tuner_ops tda18271_tuner_ops = { + .info = { + .name = "NXP TDA18271HD", + .frequency_min = 45000000, + .frequency_max = 864000000, + .frequency_step = 62500 + }, + .init = tda18271_init, + .sleep = tda18271_sleep, + .set_params = tda18271_set_params, + .set_analog_params = tda18271_set_analog_params, + .release = tda18271_release, + .set_config = tda18271_set_config, + .get_frequency = tda18271_get_frequency, + .get_bandwidth = tda18271_get_bandwidth, + .get_if_frequency = tda18271_get_if_frequency, +}; + +struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, + struct i2c_adapter *i2c, + struct tda18271_config *cfg) +{ + struct tda18271_priv *priv = NULL; + int instance, ret; + + mutex_lock(&tda18271_list_mutex); + + instance = hybrid_tuner_request_state(struct tda18271_priv, priv, + hybrid_tuner_instance_list, + i2c, addr, "tda18271"); + switch (instance) { + case 0: + goto fail; + case 1: + /* new tuner instance */ + fe->tuner_priv = priv; + + tda18271_setup_configuration(fe, cfg); + + priv->cal_initialized = false; + mutex_init(&priv->lock); + + ret = tda18271_get_id(fe); + if (tda_fail(ret)) + goto fail; + + ret = tda18271_assign_map_layout(fe); + if (tda_fail(ret)) + goto fail; + + mutex_lock(&priv->lock); + tda18271_init_regs(fe); + + if ((tda18271_need_cal_on_startup(cfg)) && + (priv->id == TDA18271HDC2)) + tda18271c2_rf_cal_init(fe); + + mutex_unlock(&priv->lock); + break; + default: + /* existing tuner instance */ + fe->tuner_priv = priv; + + /* allow dvb driver to override configuration settings */ + if (cfg) { + if (cfg->gate != TDA18271_GATE_ANALOG) + priv->gate = cfg->gate; + if (cfg->role) + priv->role = cfg->role; + if (cfg->config) + priv->config = cfg->config; + if (cfg->small_i2c) + priv->small_i2c = cfg->small_i2c; + if (cfg->output_opt) + priv->output_opt = cfg->output_opt; + if (cfg->std_map) + tda18271_update_std_map(fe, cfg->std_map); + } + if (tda18271_need_cal_on_startup(cfg)) + tda18271_init(fe); + break; + } + + /* override default std map with values in config struct */ + if ((cfg) && (cfg->std_map)) + tda18271_update_std_map(fe, cfg->std_map); + + mutex_unlock(&tda18271_list_mutex); + + memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + if (tda18271_debug & (DBG_MAP | DBG_ADV)) + tda18271_dump_std_map(fe); + + return fe; +fail: + mutex_unlock(&tda18271_list_mutex); + + tda18271_release(fe); + return NULL; +} +EXPORT_SYMBOL_GPL(tda18271_attach); +MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); +MODULE_AUTHOR("Michael Krufky "); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.4"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/tuners/tda18271-maps.c b/drivers/media/tuners/tda18271-maps.c new file mode 100644 index 000000000000..fb881c667c94 --- /dev/null +++ b/drivers/media/tuners/tda18271-maps.c @@ -0,0 +1,1317 @@ +/* + tda18271-maps.c - driver for the Philips / NXP TDA18271 silicon tuner + + Copyright (C) 2007, 2008 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 "tda18271-priv.h" + +struct tda18271_pll_map { + u32 lomax; + u8 pd; /* post div */ + u8 d; /* div */ +}; + +struct tda18271_map { + u32 rfmax; + u8 val; +}; + +/*---------------------------------------------------------------------*/ + +static struct tda18271_pll_map tda18271c1_main_pll[] = { + { .lomax = 32000, .pd = 0x5f, .d = 0xf0 }, + { .lomax = 35000, .pd = 0x5e, .d = 0xe0 }, + { .lomax = 37000, .pd = 0x5d, .d = 0xd0 }, + { .lomax = 41000, .pd = 0x5c, .d = 0xc0 }, + { .lomax = 44000, .pd = 0x5b, .d = 0xb0 }, + { .lomax = 49000, .pd = 0x5a, .d = 0xa0 }, + { .lomax = 54000, .pd = 0x59, .d = 0x90 }, + { .lomax = 61000, .pd = 0x58, .d = 0x80 }, + { .lomax = 65000, .pd = 0x4f, .d = 0x78 }, + { .lomax = 70000, .pd = 0x4e, .d = 0x70 }, + { .lomax = 75000, .pd = 0x4d, .d = 0x68 }, + { .lomax = 82000, .pd = 0x4c, .d = 0x60 }, + { .lomax = 89000, .pd = 0x4b, .d = 0x58 }, + { .lomax = 98000, .pd = 0x4a, .d = 0x50 }, + { .lomax = 109000, .pd = 0x49, .d = 0x48 }, + { .lomax = 123000, .pd = 0x48, .d = 0x40 }, + { .lomax = 131000, .pd = 0x3f, .d = 0x3c }, + { .lomax = 141000, .pd = 0x3e, .d = 0x38 }, + { .lomax = 151000, .pd = 0x3d, .d = 0x34 }, + { .lomax = 164000, .pd = 0x3c, .d = 0x30 }, + { .lomax = 179000, .pd = 0x3b, .d = 0x2c }, + { .lomax = 197000, .pd = 0x3a, .d = 0x28 }, + { .lomax = 219000, .pd = 0x39, .d = 0x24 }, + { .lomax = 246000, .pd = 0x38, .d = 0x20 }, + { .lomax = 263000, .pd = 0x2f, .d = 0x1e }, + { .lomax = 282000, .pd = 0x2e, .d = 0x1c }, + { .lomax = 303000, .pd = 0x2d, .d = 0x1a }, + { .lomax = 329000, .pd = 0x2c, .d = 0x18 }, + { .lomax = 359000, .pd = 0x2b, .d = 0x16 }, + { .lomax = 395000, .pd = 0x2a, .d = 0x14 }, + { .lomax = 438000, .pd = 0x29, .d = 0x12 }, + { .lomax = 493000, .pd = 0x28, .d = 0x10 }, + { .lomax = 526000, .pd = 0x1f, .d = 0x0f }, + { .lomax = 564000, .pd = 0x1e, .d = 0x0e }, + { .lomax = 607000, .pd = 0x1d, .d = 0x0d }, + { .lomax = 658000, .pd = 0x1c, .d = 0x0c }, + { .lomax = 718000, .pd = 0x1b, .d = 0x0b }, + { .lomax = 790000, .pd = 0x1a, .d = 0x0a }, + { .lomax = 877000, .pd = 0x19, .d = 0x09 }, + { .lomax = 987000, .pd = 0x18, .d = 0x08 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +static struct tda18271_pll_map tda18271c2_main_pll[] = { + { .lomax = 33125, .pd = 0x57, .d = 0xf0 }, + { .lomax = 35500, .pd = 0x56, .d = 0xe0 }, + { .lomax = 38188, .pd = 0x55, .d = 0xd0 }, + { .lomax = 41375, .pd = 0x54, .d = 0xc0 }, + { .lomax = 45125, .pd = 0x53, .d = 0xb0 }, + { .lomax = 49688, .pd = 0x52, .d = 0xa0 }, + { .lomax = 55188, .pd = 0x51, .d = 0x90 }, + { .lomax = 62125, .pd = 0x50, .d = 0x80 }, + { .lomax = 66250, .pd = 0x47, .d = 0x78 }, + { .lomax = 71000, .pd = 0x46, .d = 0x70 }, + { .lomax = 76375, .pd = 0x45, .d = 0x68 }, + { .lomax = 82750, .pd = 0x44, .d = 0x60 }, + { .lomax = 90250, .pd = 0x43, .d = 0x58 }, + { .lomax = 99375, .pd = 0x42, .d = 0x50 }, + { .lomax = 110375, .pd = 0x41, .d = 0x48 }, + { .lomax = 124250, .pd = 0x40, .d = 0x40 }, + { .lomax = 132500, .pd = 0x37, .d = 0x3c }, + { .lomax = 142000, .pd = 0x36, .d = 0x38 }, + { .lomax = 152750, .pd = 0x35, .d = 0x34 }, + { .lomax = 165500, .pd = 0x34, .d = 0x30 }, + { .lomax = 180500, .pd = 0x33, .d = 0x2c }, + { .lomax = 198750, .pd = 0x32, .d = 0x28 }, + { .lomax = 220750, .pd = 0x31, .d = 0x24 }, + { .lomax = 248500, .pd = 0x30, .d = 0x20 }, + { .lomax = 265000, .pd = 0x27, .d = 0x1e }, + { .lomax = 284000, .pd = 0x26, .d = 0x1c }, + { .lomax = 305500, .pd = 0x25, .d = 0x1a }, + { .lomax = 331000, .pd = 0x24, .d = 0x18 }, + { .lomax = 361000, .pd = 0x23, .d = 0x16 }, + { .lomax = 397500, .pd = 0x22, .d = 0x14 }, + { .lomax = 441500, .pd = 0x21, .d = 0x12 }, + { .lomax = 497000, .pd = 0x20, .d = 0x10 }, + { .lomax = 530000, .pd = 0x17, .d = 0x0f }, + { .lomax = 568000, .pd = 0x16, .d = 0x0e }, + { .lomax = 611000, .pd = 0x15, .d = 0x0d }, + { .lomax = 662000, .pd = 0x14, .d = 0x0c }, + { .lomax = 722000, .pd = 0x13, .d = 0x0b }, + { .lomax = 795000, .pd = 0x12, .d = 0x0a }, + { .lomax = 883000, .pd = 0x11, .d = 0x09 }, + { .lomax = 994000, .pd = 0x10, .d = 0x08 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +static struct tda18271_pll_map tda18271c1_cal_pll[] = { + { .lomax = 33000, .pd = 0xdd, .d = 0xd0 }, + { .lomax = 36000, .pd = 0xdc, .d = 0xc0 }, + { .lomax = 40000, .pd = 0xdb, .d = 0xb0 }, + { .lomax = 44000, .pd = 0xda, .d = 0xa0 }, + { .lomax = 49000, .pd = 0xd9, .d = 0x90 }, + { .lomax = 55000, .pd = 0xd8, .d = 0x80 }, + { .lomax = 63000, .pd = 0xd3, .d = 0x70 }, + { .lomax = 67000, .pd = 0xcd, .d = 0x68 }, + { .lomax = 73000, .pd = 0xcc, .d = 0x60 }, + { .lomax = 80000, .pd = 0xcb, .d = 0x58 }, + { .lomax = 88000, .pd = 0xca, .d = 0x50 }, + { .lomax = 98000, .pd = 0xc9, .d = 0x48 }, + { .lomax = 110000, .pd = 0xc8, .d = 0x40 }, + { .lomax = 126000, .pd = 0xc3, .d = 0x38 }, + { .lomax = 135000, .pd = 0xbd, .d = 0x34 }, + { .lomax = 147000, .pd = 0xbc, .d = 0x30 }, + { .lomax = 160000, .pd = 0xbb, .d = 0x2c }, + { .lomax = 176000, .pd = 0xba, .d = 0x28 }, + { .lomax = 196000, .pd = 0xb9, .d = 0x24 }, + { .lomax = 220000, .pd = 0xb8, .d = 0x20 }, + { .lomax = 252000, .pd = 0xb3, .d = 0x1c }, + { .lomax = 271000, .pd = 0xad, .d = 0x1a }, + { .lomax = 294000, .pd = 0xac, .d = 0x18 }, + { .lomax = 321000, .pd = 0xab, .d = 0x16 }, + { .lomax = 353000, .pd = 0xaa, .d = 0x14 }, + { .lomax = 392000, .pd = 0xa9, .d = 0x12 }, + { .lomax = 441000, .pd = 0xa8, .d = 0x10 }, + { .lomax = 505000, .pd = 0xa3, .d = 0x0e }, + { .lomax = 543000, .pd = 0x9d, .d = 0x0d }, + { .lomax = 589000, .pd = 0x9c, .d = 0x0c }, + { .lomax = 642000, .pd = 0x9b, .d = 0x0b }, + { .lomax = 707000, .pd = 0x9a, .d = 0x0a }, + { .lomax = 785000, .pd = 0x99, .d = 0x09 }, + { .lomax = 883000, .pd = 0x98, .d = 0x08 }, + { .lomax = 1010000, .pd = 0x93, .d = 0x07 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +static struct tda18271_pll_map tda18271c2_cal_pll[] = { + { .lomax = 33813, .pd = 0xdd, .d = 0xd0 }, + { .lomax = 36625, .pd = 0xdc, .d = 0xc0 }, + { .lomax = 39938, .pd = 0xdb, .d = 0xb0 }, + { .lomax = 43938, .pd = 0xda, .d = 0xa0 }, + { .lomax = 48813, .pd = 0xd9, .d = 0x90 }, + { .lomax = 54938, .pd = 0xd8, .d = 0x80 }, + { .lomax = 62813, .pd = 0xd3, .d = 0x70 }, + { .lomax = 67625, .pd = 0xcd, .d = 0x68 }, + { .lomax = 73250, .pd = 0xcc, .d = 0x60 }, + { .lomax = 79875, .pd = 0xcb, .d = 0x58 }, + { .lomax = 87875, .pd = 0xca, .d = 0x50 }, + { .lomax = 97625, .pd = 0xc9, .d = 0x48 }, + { .lomax = 109875, .pd = 0xc8, .d = 0x40 }, + { .lomax = 125625, .pd = 0xc3, .d = 0x38 }, + { .lomax = 135250, .pd = 0xbd, .d = 0x34 }, + { .lomax = 146500, .pd = 0xbc, .d = 0x30 }, + { .lomax = 159750, .pd = 0xbb, .d = 0x2c }, + { .lomax = 175750, .pd = 0xba, .d = 0x28 }, + { .lomax = 195250, .pd = 0xb9, .d = 0x24 }, + { .lomax = 219750, .pd = 0xb8, .d = 0x20 }, + { .lomax = 251250, .pd = 0xb3, .d = 0x1c }, + { .lomax = 270500, .pd = 0xad, .d = 0x1a }, + { .lomax = 293000, .pd = 0xac, .d = 0x18 }, + { .lomax = 319500, .pd = 0xab, .d = 0x16 }, + { .lomax = 351500, .pd = 0xaa, .d = 0x14 }, + { .lomax = 390500, .pd = 0xa9, .d = 0x12 }, + { .lomax = 439500, .pd = 0xa8, .d = 0x10 }, + { .lomax = 502500, .pd = 0xa3, .d = 0x0e }, + { .lomax = 541000, .pd = 0x9d, .d = 0x0d }, + { .lomax = 586000, .pd = 0x9c, .d = 0x0c }, + { .lomax = 639000, .pd = 0x9b, .d = 0x0b }, + { .lomax = 703000, .pd = 0x9a, .d = 0x0a }, + { .lomax = 781000, .pd = 0x99, .d = 0x09 }, + { .lomax = 879000, .pd = 0x98, .d = 0x08 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_bp_filter[] = { + { .rfmax = 62000, .val = 0x00 }, + { .rfmax = 84000, .val = 0x01 }, + { .rfmax = 100000, .val = 0x02 }, + { .rfmax = 140000, .val = 0x03 }, + { .rfmax = 170000, .val = 0x04 }, + { .rfmax = 180000, .val = 0x05 }, + { .rfmax = 865000, .val = 0x06 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271c1_km[] = { + { .rfmax = 61100, .val = 0x74 }, + { .rfmax = 350000, .val = 0x40 }, + { .rfmax = 720000, .val = 0x30 }, + { .rfmax = 865000, .val = 0x40 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271c2_km[] = { + { .rfmax = 47900, .val = 0x38 }, + { .rfmax = 61100, .val = 0x44 }, + { .rfmax = 350000, .val = 0x30 }, + { .rfmax = 720000, .val = 0x24 }, + { .rfmax = 865000, .val = 0x3c }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_rf_band[] = { + { .rfmax = 47900, .val = 0x00 }, + { .rfmax = 61100, .val = 0x01 }, + { .rfmax = 152600, .val = 0x02 }, + { .rfmax = 164700, .val = 0x03 }, + { .rfmax = 203500, .val = 0x04 }, + { .rfmax = 457800, .val = 0x05 }, + { .rfmax = 865000, .val = 0x06 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_gain_taper[] = { + { .rfmax = 45400, .val = 0x1f }, + { .rfmax = 45800, .val = 0x1e }, + { .rfmax = 46200, .val = 0x1d }, + { .rfmax = 46700, .val = 0x1c }, + { .rfmax = 47100, .val = 0x1b }, + { .rfmax = 47500, .val = 0x1a }, + { .rfmax = 47900, .val = 0x19 }, + { .rfmax = 49600, .val = 0x17 }, + { .rfmax = 51200, .val = 0x16 }, + { .rfmax = 52900, .val = 0x15 }, + { .rfmax = 54500, .val = 0x14 }, + { .rfmax = 56200, .val = 0x13 }, + { .rfmax = 57800, .val = 0x12 }, + { .rfmax = 59500, .val = 0x11 }, + { .rfmax = 61100, .val = 0x10 }, + { .rfmax = 67600, .val = 0x0d }, + { .rfmax = 74200, .val = 0x0c }, + { .rfmax = 80700, .val = 0x0b }, + { .rfmax = 87200, .val = 0x0a }, + { .rfmax = 93800, .val = 0x09 }, + { .rfmax = 100300, .val = 0x08 }, + { .rfmax = 106900, .val = 0x07 }, + { .rfmax = 113400, .val = 0x06 }, + { .rfmax = 119900, .val = 0x05 }, + { .rfmax = 126500, .val = 0x04 }, + { .rfmax = 133000, .val = 0x03 }, + { .rfmax = 139500, .val = 0x02 }, + { .rfmax = 146100, .val = 0x01 }, + { .rfmax = 152600, .val = 0x00 }, + { .rfmax = 154300, .val = 0x1f }, + { .rfmax = 156100, .val = 0x1e }, + { .rfmax = 157800, .val = 0x1d }, + { .rfmax = 159500, .val = 0x1c }, + { .rfmax = 161200, .val = 0x1b }, + { .rfmax = 163000, .val = 0x1a }, + { .rfmax = 164700, .val = 0x19 }, + { .rfmax = 170200, .val = 0x17 }, + { .rfmax = 175800, .val = 0x16 }, + { .rfmax = 181300, .val = 0x15 }, + { .rfmax = 186900, .val = 0x14 }, + { .rfmax = 192400, .val = 0x13 }, + { .rfmax = 198000, .val = 0x12 }, + { .rfmax = 203500, .val = 0x11 }, + { .rfmax = 216200, .val = 0x14 }, + { .rfmax = 228900, .val = 0x13 }, + { .rfmax = 241600, .val = 0x12 }, + { .rfmax = 254400, .val = 0x11 }, + { .rfmax = 267100, .val = 0x10 }, + { .rfmax = 279800, .val = 0x0f }, + { .rfmax = 292500, .val = 0x0e }, + { .rfmax = 305200, .val = 0x0d }, + { .rfmax = 317900, .val = 0x0c }, + { .rfmax = 330700, .val = 0x0b }, + { .rfmax = 343400, .val = 0x0a }, + { .rfmax = 356100, .val = 0x09 }, + { .rfmax = 368800, .val = 0x08 }, + { .rfmax = 381500, .val = 0x07 }, + { .rfmax = 394200, .val = 0x06 }, + { .rfmax = 406900, .val = 0x05 }, + { .rfmax = 419700, .val = 0x04 }, + { .rfmax = 432400, .val = 0x03 }, + { .rfmax = 445100, .val = 0x02 }, + { .rfmax = 457800, .val = 0x01 }, + { .rfmax = 476300, .val = 0x19 }, + { .rfmax = 494800, .val = 0x18 }, + { .rfmax = 513300, .val = 0x17 }, + { .rfmax = 531800, .val = 0x16 }, + { .rfmax = 550300, .val = 0x15 }, + { .rfmax = 568900, .val = 0x14 }, + { .rfmax = 587400, .val = 0x13 }, + { .rfmax = 605900, .val = 0x12 }, + { .rfmax = 624400, .val = 0x11 }, + { .rfmax = 642900, .val = 0x10 }, + { .rfmax = 661400, .val = 0x0f }, + { .rfmax = 679900, .val = 0x0e }, + { .rfmax = 698400, .val = 0x0d }, + { .rfmax = 716900, .val = 0x0c }, + { .rfmax = 735400, .val = 0x0b }, + { .rfmax = 753900, .val = 0x0a }, + { .rfmax = 772500, .val = 0x09 }, + { .rfmax = 791000, .val = 0x08 }, + { .rfmax = 809500, .val = 0x07 }, + { .rfmax = 828000, .val = 0x06 }, + { .rfmax = 846500, .val = 0x05 }, + { .rfmax = 865000, .val = 0x04 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271c1_rf_cal[] = { + { .rfmax = 41000, .val = 0x1e }, + { .rfmax = 43000, .val = 0x30 }, + { .rfmax = 45000, .val = 0x43 }, + { .rfmax = 46000, .val = 0x4d }, + { .rfmax = 47000, .val = 0x54 }, + { .rfmax = 47900, .val = 0x64 }, + { .rfmax = 49100, .val = 0x20 }, + { .rfmax = 50000, .val = 0x22 }, + { .rfmax = 51000, .val = 0x2a }, + { .rfmax = 53000, .val = 0x32 }, + { .rfmax = 55000, .val = 0x35 }, + { .rfmax = 56000, .val = 0x3c }, + { .rfmax = 57000, .val = 0x3f }, + { .rfmax = 58000, .val = 0x48 }, + { .rfmax = 59000, .val = 0x4d }, + { .rfmax = 60000, .val = 0x58 }, + { .rfmax = 61100, .val = 0x5f }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271c2_rf_cal[] = { + { .rfmax = 41000, .val = 0x0f }, + { .rfmax = 43000, .val = 0x1c }, + { .rfmax = 45000, .val = 0x2f }, + { .rfmax = 46000, .val = 0x39 }, + { .rfmax = 47000, .val = 0x40 }, + { .rfmax = 47900, .val = 0x50 }, + { .rfmax = 49100, .val = 0x16 }, + { .rfmax = 50000, .val = 0x18 }, + { .rfmax = 51000, .val = 0x20 }, + { .rfmax = 53000, .val = 0x28 }, + { .rfmax = 55000, .val = 0x2b }, + { .rfmax = 56000, .val = 0x32 }, + { .rfmax = 57000, .val = 0x35 }, + { .rfmax = 58000, .val = 0x3e }, + { .rfmax = 59000, .val = 0x43 }, + { .rfmax = 60000, .val = 0x4e }, + { .rfmax = 61100, .val = 0x55 }, + { .rfmax = 63000, .val = 0x0f }, + { .rfmax = 64000, .val = 0x11 }, + { .rfmax = 65000, .val = 0x12 }, + { .rfmax = 66000, .val = 0x15 }, + { .rfmax = 67000, .val = 0x16 }, + { .rfmax = 68000, .val = 0x17 }, + { .rfmax = 70000, .val = 0x19 }, + { .rfmax = 71000, .val = 0x1c }, + { .rfmax = 72000, .val = 0x1d }, + { .rfmax = 73000, .val = 0x1f }, + { .rfmax = 74000, .val = 0x20 }, + { .rfmax = 75000, .val = 0x21 }, + { .rfmax = 76000, .val = 0x24 }, + { .rfmax = 77000, .val = 0x25 }, + { .rfmax = 78000, .val = 0x27 }, + { .rfmax = 80000, .val = 0x28 }, + { .rfmax = 81000, .val = 0x29 }, + { .rfmax = 82000, .val = 0x2d }, + { .rfmax = 83000, .val = 0x2e }, + { .rfmax = 84000, .val = 0x2f }, + { .rfmax = 85000, .val = 0x31 }, + { .rfmax = 86000, .val = 0x33 }, + { .rfmax = 87000, .val = 0x34 }, + { .rfmax = 88000, .val = 0x35 }, + { .rfmax = 89000, .val = 0x37 }, + { .rfmax = 90000, .val = 0x38 }, + { .rfmax = 91000, .val = 0x39 }, + { .rfmax = 93000, .val = 0x3c }, + { .rfmax = 94000, .val = 0x3e }, + { .rfmax = 95000, .val = 0x3f }, + { .rfmax = 96000, .val = 0x40 }, + { .rfmax = 97000, .val = 0x42 }, + { .rfmax = 99000, .val = 0x45 }, + { .rfmax = 100000, .val = 0x46 }, + { .rfmax = 102000, .val = 0x48 }, + { .rfmax = 103000, .val = 0x4a }, + { .rfmax = 105000, .val = 0x4d }, + { .rfmax = 106000, .val = 0x4e }, + { .rfmax = 107000, .val = 0x50 }, + { .rfmax = 108000, .val = 0x51 }, + { .rfmax = 110000, .val = 0x54 }, + { .rfmax = 111000, .val = 0x56 }, + { .rfmax = 112000, .val = 0x57 }, + { .rfmax = 113000, .val = 0x58 }, + { .rfmax = 114000, .val = 0x59 }, + { .rfmax = 115000, .val = 0x5c }, + { .rfmax = 116000, .val = 0x5d }, + { .rfmax = 117000, .val = 0x5f }, + { .rfmax = 119000, .val = 0x60 }, + { .rfmax = 120000, .val = 0x64 }, + { .rfmax = 121000, .val = 0x65 }, + { .rfmax = 122000, .val = 0x66 }, + { .rfmax = 123000, .val = 0x68 }, + { .rfmax = 124000, .val = 0x69 }, + { .rfmax = 125000, .val = 0x6c }, + { .rfmax = 126000, .val = 0x6d }, + { .rfmax = 127000, .val = 0x6e }, + { .rfmax = 128000, .val = 0x70 }, + { .rfmax = 129000, .val = 0x71 }, + { .rfmax = 130000, .val = 0x75 }, + { .rfmax = 131000, .val = 0x77 }, + { .rfmax = 132000, .val = 0x78 }, + { .rfmax = 133000, .val = 0x7b }, + { .rfmax = 134000, .val = 0x7e }, + { .rfmax = 135000, .val = 0x81 }, + { .rfmax = 136000, .val = 0x82 }, + { .rfmax = 137000, .val = 0x87 }, + { .rfmax = 138000, .val = 0x88 }, + { .rfmax = 139000, .val = 0x8d }, + { .rfmax = 140000, .val = 0x8e }, + { .rfmax = 141000, .val = 0x91 }, + { .rfmax = 142000, .val = 0x95 }, + { .rfmax = 143000, .val = 0x9a }, + { .rfmax = 144000, .val = 0x9d }, + { .rfmax = 145000, .val = 0xa1 }, + { .rfmax = 146000, .val = 0xa2 }, + { .rfmax = 147000, .val = 0xa4 }, + { .rfmax = 148000, .val = 0xa9 }, + { .rfmax = 149000, .val = 0xae }, + { .rfmax = 150000, .val = 0xb0 }, + { .rfmax = 151000, .val = 0xb1 }, + { .rfmax = 152000, .val = 0xb7 }, + { .rfmax = 152600, .val = 0xbd }, + { .rfmax = 154000, .val = 0x20 }, + { .rfmax = 155000, .val = 0x22 }, + { .rfmax = 156000, .val = 0x24 }, + { .rfmax = 157000, .val = 0x25 }, + { .rfmax = 158000, .val = 0x27 }, + { .rfmax = 159000, .val = 0x29 }, + { .rfmax = 160000, .val = 0x2c }, + { .rfmax = 161000, .val = 0x2d }, + { .rfmax = 163000, .val = 0x2e }, + { .rfmax = 164000, .val = 0x2f }, + { .rfmax = 164700, .val = 0x30 }, + { .rfmax = 166000, .val = 0x11 }, + { .rfmax = 167000, .val = 0x12 }, + { .rfmax = 168000, .val = 0x13 }, + { .rfmax = 169000, .val = 0x14 }, + { .rfmax = 170000, .val = 0x15 }, + { .rfmax = 172000, .val = 0x16 }, + { .rfmax = 173000, .val = 0x17 }, + { .rfmax = 174000, .val = 0x18 }, + { .rfmax = 175000, .val = 0x1a }, + { .rfmax = 176000, .val = 0x1b }, + { .rfmax = 178000, .val = 0x1d }, + { .rfmax = 179000, .val = 0x1e }, + { .rfmax = 180000, .val = 0x1f }, + { .rfmax = 181000, .val = 0x20 }, + { .rfmax = 182000, .val = 0x21 }, + { .rfmax = 183000, .val = 0x22 }, + { .rfmax = 184000, .val = 0x24 }, + { .rfmax = 185000, .val = 0x25 }, + { .rfmax = 186000, .val = 0x26 }, + { .rfmax = 187000, .val = 0x27 }, + { .rfmax = 188000, .val = 0x29 }, + { .rfmax = 189000, .val = 0x2a }, + { .rfmax = 190000, .val = 0x2c }, + { .rfmax = 191000, .val = 0x2d }, + { .rfmax = 192000, .val = 0x2e }, + { .rfmax = 193000, .val = 0x2f }, + { .rfmax = 194000, .val = 0x30 }, + { .rfmax = 195000, .val = 0x33 }, + { .rfmax = 196000, .val = 0x35 }, + { .rfmax = 198000, .val = 0x36 }, + { .rfmax = 200000, .val = 0x38 }, + { .rfmax = 201000, .val = 0x3c }, + { .rfmax = 202000, .val = 0x3d }, + { .rfmax = 203500, .val = 0x3e }, + { .rfmax = 206000, .val = 0x0e }, + { .rfmax = 208000, .val = 0x0f }, + { .rfmax = 212000, .val = 0x10 }, + { .rfmax = 216000, .val = 0x11 }, + { .rfmax = 217000, .val = 0x12 }, + { .rfmax = 218000, .val = 0x13 }, + { .rfmax = 220000, .val = 0x14 }, + { .rfmax = 222000, .val = 0x15 }, + { .rfmax = 225000, .val = 0x16 }, + { .rfmax = 228000, .val = 0x17 }, + { .rfmax = 231000, .val = 0x18 }, + { .rfmax = 234000, .val = 0x19 }, + { .rfmax = 235000, .val = 0x1a }, + { .rfmax = 236000, .val = 0x1b }, + { .rfmax = 237000, .val = 0x1c }, + { .rfmax = 240000, .val = 0x1d }, + { .rfmax = 242000, .val = 0x1e }, + { .rfmax = 244000, .val = 0x1f }, + { .rfmax = 247000, .val = 0x20 }, + { .rfmax = 249000, .val = 0x21 }, + { .rfmax = 252000, .val = 0x22 }, + { .rfmax = 253000, .val = 0x23 }, + { .rfmax = 254000, .val = 0x24 }, + { .rfmax = 256000, .val = 0x25 }, + { .rfmax = 259000, .val = 0x26 }, + { .rfmax = 262000, .val = 0x27 }, + { .rfmax = 264000, .val = 0x28 }, + { .rfmax = 267000, .val = 0x29 }, + { .rfmax = 269000, .val = 0x2a }, + { .rfmax = 271000, .val = 0x2b }, + { .rfmax = 273000, .val = 0x2c }, + { .rfmax = 275000, .val = 0x2d }, + { .rfmax = 277000, .val = 0x2e }, + { .rfmax = 279000, .val = 0x2f }, + { .rfmax = 282000, .val = 0x30 }, + { .rfmax = 284000, .val = 0x31 }, + { .rfmax = 286000, .val = 0x32 }, + { .rfmax = 287000, .val = 0x33 }, + { .rfmax = 290000, .val = 0x34 }, + { .rfmax = 293000, .val = 0x35 }, + { .rfmax = 295000, .val = 0x36 }, + { .rfmax = 297000, .val = 0x37 }, + { .rfmax = 300000, .val = 0x38 }, + { .rfmax = 303000, .val = 0x39 }, + { .rfmax = 305000, .val = 0x3a }, + { .rfmax = 306000, .val = 0x3b }, + { .rfmax = 307000, .val = 0x3c }, + { .rfmax = 310000, .val = 0x3d }, + { .rfmax = 312000, .val = 0x3e }, + { .rfmax = 315000, .val = 0x3f }, + { .rfmax = 318000, .val = 0x40 }, + { .rfmax = 320000, .val = 0x41 }, + { .rfmax = 323000, .val = 0x42 }, + { .rfmax = 324000, .val = 0x43 }, + { .rfmax = 325000, .val = 0x44 }, + { .rfmax = 327000, .val = 0x45 }, + { .rfmax = 331000, .val = 0x46 }, + { .rfmax = 334000, .val = 0x47 }, + { .rfmax = 337000, .val = 0x48 }, + { .rfmax = 339000, .val = 0x49 }, + { .rfmax = 340000, .val = 0x4a }, + { .rfmax = 341000, .val = 0x4b }, + { .rfmax = 343000, .val = 0x4c }, + { .rfmax = 345000, .val = 0x4d }, + { .rfmax = 349000, .val = 0x4e }, + { .rfmax = 352000, .val = 0x4f }, + { .rfmax = 353000, .val = 0x50 }, + { .rfmax = 355000, .val = 0x51 }, + { .rfmax = 357000, .val = 0x52 }, + { .rfmax = 359000, .val = 0x53 }, + { .rfmax = 361000, .val = 0x54 }, + { .rfmax = 362000, .val = 0x55 }, + { .rfmax = 364000, .val = 0x56 }, + { .rfmax = 368000, .val = 0x57 }, + { .rfmax = 370000, .val = 0x58 }, + { .rfmax = 372000, .val = 0x59 }, + { .rfmax = 375000, .val = 0x5a }, + { .rfmax = 376000, .val = 0x5b }, + { .rfmax = 377000, .val = 0x5c }, + { .rfmax = 379000, .val = 0x5d }, + { .rfmax = 382000, .val = 0x5e }, + { .rfmax = 384000, .val = 0x5f }, + { .rfmax = 385000, .val = 0x60 }, + { .rfmax = 386000, .val = 0x61 }, + { .rfmax = 388000, .val = 0x62 }, + { .rfmax = 390000, .val = 0x63 }, + { .rfmax = 393000, .val = 0x64 }, + { .rfmax = 394000, .val = 0x65 }, + { .rfmax = 396000, .val = 0x66 }, + { .rfmax = 397000, .val = 0x67 }, + { .rfmax = 398000, .val = 0x68 }, + { .rfmax = 400000, .val = 0x69 }, + { .rfmax = 402000, .val = 0x6a }, + { .rfmax = 403000, .val = 0x6b }, + { .rfmax = 407000, .val = 0x6c }, + { .rfmax = 408000, .val = 0x6d }, + { .rfmax = 409000, .val = 0x6e }, + { .rfmax = 410000, .val = 0x6f }, + { .rfmax = 411000, .val = 0x70 }, + { .rfmax = 412000, .val = 0x71 }, + { .rfmax = 413000, .val = 0x72 }, + { .rfmax = 414000, .val = 0x73 }, + { .rfmax = 417000, .val = 0x74 }, + { .rfmax = 418000, .val = 0x75 }, + { .rfmax = 420000, .val = 0x76 }, + { .rfmax = 422000, .val = 0x77 }, + { .rfmax = 423000, .val = 0x78 }, + { .rfmax = 424000, .val = 0x79 }, + { .rfmax = 427000, .val = 0x7a }, + { .rfmax = 428000, .val = 0x7b }, + { .rfmax = 429000, .val = 0x7d }, + { .rfmax = 432000, .val = 0x7f }, + { .rfmax = 434000, .val = 0x80 }, + { .rfmax = 435000, .val = 0x81 }, + { .rfmax = 436000, .val = 0x83 }, + { .rfmax = 437000, .val = 0x84 }, + { .rfmax = 438000, .val = 0x85 }, + { .rfmax = 439000, .val = 0x86 }, + { .rfmax = 440000, .val = 0x87 }, + { .rfmax = 441000, .val = 0x88 }, + { .rfmax = 442000, .val = 0x89 }, + { .rfmax = 445000, .val = 0x8a }, + { .rfmax = 446000, .val = 0x8b }, + { .rfmax = 447000, .val = 0x8c }, + { .rfmax = 448000, .val = 0x8e }, + { .rfmax = 449000, .val = 0x8f }, + { .rfmax = 450000, .val = 0x90 }, + { .rfmax = 452000, .val = 0x91 }, + { .rfmax = 453000, .val = 0x93 }, + { .rfmax = 454000, .val = 0x94 }, + { .rfmax = 456000, .val = 0x96 }, + { .rfmax = 457800, .val = 0x98 }, + { .rfmax = 461000, .val = 0x11 }, + { .rfmax = 468000, .val = 0x12 }, + { .rfmax = 472000, .val = 0x13 }, + { .rfmax = 473000, .val = 0x14 }, + { .rfmax = 474000, .val = 0x15 }, + { .rfmax = 481000, .val = 0x16 }, + { .rfmax = 486000, .val = 0x17 }, + { .rfmax = 491000, .val = 0x18 }, + { .rfmax = 498000, .val = 0x19 }, + { .rfmax = 499000, .val = 0x1a }, + { .rfmax = 501000, .val = 0x1b }, + { .rfmax = 506000, .val = 0x1c }, + { .rfmax = 511000, .val = 0x1d }, + { .rfmax = 516000, .val = 0x1e }, + { .rfmax = 520000, .val = 0x1f }, + { .rfmax = 521000, .val = 0x20 }, + { .rfmax = 525000, .val = 0x21 }, + { .rfmax = 529000, .val = 0x22 }, + { .rfmax = 533000, .val = 0x23 }, + { .rfmax = 539000, .val = 0x24 }, + { .rfmax = 541000, .val = 0x25 }, + { .rfmax = 547000, .val = 0x26 }, + { .rfmax = 549000, .val = 0x27 }, + { .rfmax = 551000, .val = 0x28 }, + { .rfmax = 556000, .val = 0x29 }, + { .rfmax = 561000, .val = 0x2a }, + { .rfmax = 563000, .val = 0x2b }, + { .rfmax = 565000, .val = 0x2c }, + { .rfmax = 569000, .val = 0x2d }, + { .rfmax = 571000, .val = 0x2e }, + { .rfmax = 577000, .val = 0x2f }, + { .rfmax = 580000, .val = 0x30 }, + { .rfmax = 582000, .val = 0x31 }, + { .rfmax = 584000, .val = 0x32 }, + { .rfmax = 588000, .val = 0x33 }, + { .rfmax = 591000, .val = 0x34 }, + { .rfmax = 596000, .val = 0x35 }, + { .rfmax = 598000, .val = 0x36 }, + { .rfmax = 603000, .val = 0x37 }, + { .rfmax = 604000, .val = 0x38 }, + { .rfmax = 606000, .val = 0x39 }, + { .rfmax = 612000, .val = 0x3a }, + { .rfmax = 615000, .val = 0x3b }, + { .rfmax = 617000, .val = 0x3c }, + { .rfmax = 621000, .val = 0x3d }, + { .rfmax = 622000, .val = 0x3e }, + { .rfmax = 625000, .val = 0x3f }, + { .rfmax = 632000, .val = 0x40 }, + { .rfmax = 633000, .val = 0x41 }, + { .rfmax = 634000, .val = 0x42 }, + { .rfmax = 642000, .val = 0x43 }, + { .rfmax = 643000, .val = 0x44 }, + { .rfmax = 647000, .val = 0x45 }, + { .rfmax = 650000, .val = 0x46 }, + { .rfmax = 652000, .val = 0x47 }, + { .rfmax = 657000, .val = 0x48 }, + { .rfmax = 661000, .val = 0x49 }, + { .rfmax = 662000, .val = 0x4a }, + { .rfmax = 665000, .val = 0x4b }, + { .rfmax = 667000, .val = 0x4c }, + { .rfmax = 670000, .val = 0x4d }, + { .rfmax = 673000, .val = 0x4e }, + { .rfmax = 676000, .val = 0x4f }, + { .rfmax = 677000, .val = 0x50 }, + { .rfmax = 681000, .val = 0x51 }, + { .rfmax = 683000, .val = 0x52 }, + { .rfmax = 686000, .val = 0x53 }, + { .rfmax = 688000, .val = 0x54 }, + { .rfmax = 689000, .val = 0x55 }, + { .rfmax = 691000, .val = 0x56 }, + { .rfmax = 695000, .val = 0x57 }, + { .rfmax = 698000, .val = 0x58 }, + { .rfmax = 703000, .val = 0x59 }, + { .rfmax = 704000, .val = 0x5a }, + { .rfmax = 705000, .val = 0x5b }, + { .rfmax = 707000, .val = 0x5c }, + { .rfmax = 710000, .val = 0x5d }, + { .rfmax = 712000, .val = 0x5e }, + { .rfmax = 717000, .val = 0x5f }, + { .rfmax = 718000, .val = 0x60 }, + { .rfmax = 721000, .val = 0x61 }, + { .rfmax = 722000, .val = 0x62 }, + { .rfmax = 723000, .val = 0x63 }, + { .rfmax = 725000, .val = 0x64 }, + { .rfmax = 727000, .val = 0x65 }, + { .rfmax = 730000, .val = 0x66 }, + { .rfmax = 732000, .val = 0x67 }, + { .rfmax = 735000, .val = 0x68 }, + { .rfmax = 740000, .val = 0x69 }, + { .rfmax = 741000, .val = 0x6a }, + { .rfmax = 742000, .val = 0x6b }, + { .rfmax = 743000, .val = 0x6c }, + { .rfmax = 745000, .val = 0x6d }, + { .rfmax = 747000, .val = 0x6e }, + { .rfmax = 748000, .val = 0x6f }, + { .rfmax = 750000, .val = 0x70 }, + { .rfmax = 752000, .val = 0x71 }, + { .rfmax = 754000, .val = 0x72 }, + { .rfmax = 757000, .val = 0x73 }, + { .rfmax = 758000, .val = 0x74 }, + { .rfmax = 760000, .val = 0x75 }, + { .rfmax = 763000, .val = 0x76 }, + { .rfmax = 764000, .val = 0x77 }, + { .rfmax = 766000, .val = 0x78 }, + { .rfmax = 767000, .val = 0x79 }, + { .rfmax = 768000, .val = 0x7a }, + { .rfmax = 773000, .val = 0x7b }, + { .rfmax = 774000, .val = 0x7c }, + { .rfmax = 776000, .val = 0x7d }, + { .rfmax = 777000, .val = 0x7e }, + { .rfmax = 778000, .val = 0x7f }, + { .rfmax = 779000, .val = 0x80 }, + { .rfmax = 781000, .val = 0x81 }, + { .rfmax = 783000, .val = 0x82 }, + { .rfmax = 784000, .val = 0x83 }, + { .rfmax = 785000, .val = 0x84 }, + { .rfmax = 786000, .val = 0x85 }, + { .rfmax = 793000, .val = 0x86 }, + { .rfmax = 794000, .val = 0x87 }, + { .rfmax = 795000, .val = 0x88 }, + { .rfmax = 797000, .val = 0x89 }, + { .rfmax = 799000, .val = 0x8a }, + { .rfmax = 801000, .val = 0x8b }, + { .rfmax = 802000, .val = 0x8c }, + { .rfmax = 803000, .val = 0x8d }, + { .rfmax = 804000, .val = 0x8e }, + { .rfmax = 810000, .val = 0x90 }, + { .rfmax = 811000, .val = 0x91 }, + { .rfmax = 812000, .val = 0x92 }, + { .rfmax = 814000, .val = 0x93 }, + { .rfmax = 816000, .val = 0x94 }, + { .rfmax = 817000, .val = 0x96 }, + { .rfmax = 818000, .val = 0x97 }, + { .rfmax = 820000, .val = 0x98 }, + { .rfmax = 821000, .val = 0x99 }, + { .rfmax = 822000, .val = 0x9a }, + { .rfmax = 828000, .val = 0x9b }, + { .rfmax = 829000, .val = 0x9d }, + { .rfmax = 830000, .val = 0x9f }, + { .rfmax = 831000, .val = 0xa0 }, + { .rfmax = 833000, .val = 0xa1 }, + { .rfmax = 835000, .val = 0xa2 }, + { .rfmax = 836000, .val = 0xa3 }, + { .rfmax = 837000, .val = 0xa4 }, + { .rfmax = 838000, .val = 0xa6 }, + { .rfmax = 840000, .val = 0xa8 }, + { .rfmax = 842000, .val = 0xa9 }, + { .rfmax = 845000, .val = 0xaa }, + { .rfmax = 846000, .val = 0xab }, + { .rfmax = 847000, .val = 0xad }, + { .rfmax = 848000, .val = 0xae }, + { .rfmax = 852000, .val = 0xaf }, + { .rfmax = 853000, .val = 0xb0 }, + { .rfmax = 858000, .val = 0xb1 }, + { .rfmax = 860000, .val = 0xb2 }, + { .rfmax = 861000, .val = 0xb3 }, + { .rfmax = 862000, .val = 0xb4 }, + { .rfmax = 863000, .val = 0xb6 }, + { .rfmax = 864000, .val = 0xb8 }, + { .rfmax = 865000, .val = 0xb9 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_ir_measure[] = { + { .rfmax = 30000, .val = 4 }, + { .rfmax = 200000, .val = 5 }, + { .rfmax = 600000, .val = 6 }, + { .rfmax = 865000, .val = 7 }, + { .rfmax = 0, .val = 0 }, /* end */ +}; + +static struct tda18271_map tda18271_rf_cal_dc_over_dt[] = { + { .rfmax = 47900, .val = 0x00 }, + { .rfmax = 55000, .val = 0x00 }, + { .rfmax = 61100, .val = 0x0a }, + { .rfmax = 64000, .val = 0x0a }, + { .rfmax = 82000, .val = 0x14 }, + { .rfmax = 84000, .val = 0x19 }, + { .rfmax = 119000, .val = 0x1c }, + { .rfmax = 124000, .val = 0x20 }, + { .rfmax = 129000, .val = 0x2a }, + { .rfmax = 134000, .val = 0x32 }, + { .rfmax = 139000, .val = 0x39 }, + { .rfmax = 144000, .val = 0x3e }, + { .rfmax = 149000, .val = 0x3f }, + { .rfmax = 152600, .val = 0x40 }, + { .rfmax = 154000, .val = 0x40 }, + { .rfmax = 164700, .val = 0x41 }, + { .rfmax = 203500, .val = 0x32 }, + { .rfmax = 353000, .val = 0x19 }, + { .rfmax = 356000, .val = 0x1a }, + { .rfmax = 359000, .val = 0x1b }, + { .rfmax = 363000, .val = 0x1c }, + { .rfmax = 366000, .val = 0x1d }, + { .rfmax = 369000, .val = 0x1e }, + { .rfmax = 373000, .val = 0x1f }, + { .rfmax = 376000, .val = 0x20 }, + { .rfmax = 379000, .val = 0x21 }, + { .rfmax = 383000, .val = 0x22 }, + { .rfmax = 386000, .val = 0x23 }, + { .rfmax = 389000, .val = 0x24 }, + { .rfmax = 393000, .val = 0x25 }, + { .rfmax = 396000, .val = 0x26 }, + { .rfmax = 399000, .val = 0x27 }, + { .rfmax = 402000, .val = 0x28 }, + { .rfmax = 404000, .val = 0x29 }, + { .rfmax = 407000, .val = 0x2a }, + { .rfmax = 409000, .val = 0x2b }, + { .rfmax = 412000, .val = 0x2c }, + { .rfmax = 414000, .val = 0x2d }, + { .rfmax = 417000, .val = 0x2e }, + { .rfmax = 419000, .val = 0x2f }, + { .rfmax = 422000, .val = 0x30 }, + { .rfmax = 424000, .val = 0x31 }, + { .rfmax = 427000, .val = 0x32 }, + { .rfmax = 429000, .val = 0x33 }, + { .rfmax = 432000, .val = 0x34 }, + { .rfmax = 434000, .val = 0x35 }, + { .rfmax = 437000, .val = 0x36 }, + { .rfmax = 439000, .val = 0x37 }, + { .rfmax = 442000, .val = 0x38 }, + { .rfmax = 444000, .val = 0x39 }, + { .rfmax = 447000, .val = 0x3a }, + { .rfmax = 449000, .val = 0x3b }, + { .rfmax = 457800, .val = 0x3c }, + { .rfmax = 465000, .val = 0x0f }, + { .rfmax = 477000, .val = 0x12 }, + { .rfmax = 483000, .val = 0x14 }, + { .rfmax = 502000, .val = 0x19 }, + { .rfmax = 508000, .val = 0x1b }, + { .rfmax = 519000, .val = 0x1c }, + { .rfmax = 522000, .val = 0x1d }, + { .rfmax = 524000, .val = 0x1e }, + { .rfmax = 534000, .val = 0x1f }, + { .rfmax = 549000, .val = 0x20 }, + { .rfmax = 554000, .val = 0x22 }, + { .rfmax = 584000, .val = 0x24 }, + { .rfmax = 589000, .val = 0x26 }, + { .rfmax = 658000, .val = 0x27 }, + { .rfmax = 664000, .val = 0x2c }, + { .rfmax = 669000, .val = 0x2d }, + { .rfmax = 699000, .val = 0x2e }, + { .rfmax = 704000, .val = 0x30 }, + { .rfmax = 709000, .val = 0x31 }, + { .rfmax = 714000, .val = 0x32 }, + { .rfmax = 724000, .val = 0x33 }, + { .rfmax = 729000, .val = 0x36 }, + { .rfmax = 739000, .val = 0x38 }, + { .rfmax = 744000, .val = 0x39 }, + { .rfmax = 749000, .val = 0x3b }, + { .rfmax = 754000, .val = 0x3c }, + { .rfmax = 759000, .val = 0x3d }, + { .rfmax = 764000, .val = 0x3e }, + { .rfmax = 769000, .val = 0x3f }, + { .rfmax = 774000, .val = 0x40 }, + { .rfmax = 779000, .val = 0x41 }, + { .rfmax = 784000, .val = 0x43 }, + { .rfmax = 789000, .val = 0x46 }, + { .rfmax = 794000, .val = 0x48 }, + { .rfmax = 799000, .val = 0x4b }, + { .rfmax = 804000, .val = 0x4f }, + { .rfmax = 809000, .val = 0x54 }, + { .rfmax = 814000, .val = 0x59 }, + { .rfmax = 819000, .val = 0x5d }, + { .rfmax = 824000, .val = 0x61 }, + { .rfmax = 829000, .val = 0x68 }, + { .rfmax = 834000, .val = 0x6e }, + { .rfmax = 839000, .val = 0x75 }, + { .rfmax = 844000, .val = 0x7e }, + { .rfmax = 849000, .val = 0x82 }, + { .rfmax = 854000, .val = 0x84 }, + { .rfmax = 859000, .val = 0x8f }, + { .rfmax = 865000, .val = 0x9a }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +/*---------------------------------------------------------------------*/ + +struct tda18271_thermo_map { + u8 d; + u8 r0; + u8 r1; +}; + +static struct tda18271_thermo_map tda18271_thermometer[] = { + { .d = 0x00, .r0 = 60, .r1 = 92 }, + { .d = 0x01, .r0 = 62, .r1 = 94 }, + { .d = 0x02, .r0 = 66, .r1 = 98 }, + { .d = 0x03, .r0 = 64, .r1 = 96 }, + { .d = 0x04, .r0 = 74, .r1 = 106 }, + { .d = 0x05, .r0 = 72, .r1 = 104 }, + { .d = 0x06, .r0 = 68, .r1 = 100 }, + { .d = 0x07, .r0 = 70, .r1 = 102 }, + { .d = 0x08, .r0 = 90, .r1 = 122 }, + { .d = 0x09, .r0 = 88, .r1 = 120 }, + { .d = 0x0a, .r0 = 84, .r1 = 116 }, + { .d = 0x0b, .r0 = 86, .r1 = 118 }, + { .d = 0x0c, .r0 = 76, .r1 = 108 }, + { .d = 0x0d, .r0 = 78, .r1 = 110 }, + { .d = 0x0e, .r0 = 82, .r1 = 114 }, + { .d = 0x0f, .r0 = 80, .r1 = 112 }, + { .d = 0x00, .r0 = 0, .r1 = 0 }, /* end */ +}; + +int tda18271_lookup_thermometer(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int val, i = 0; + + while (tda18271_thermometer[i].d < (regs[R_TM] & 0x0f)) { + if (tda18271_thermometer[i + 1].d == 0) + break; + i++; + } + + if ((regs[R_TM] & 0x20) == 0x20) + val = tda18271_thermometer[i].r1; + else + val = tda18271_thermometer[i].r0; + + tda_map("(%d) tm = %d\n", i, val); + + return val; +} + +/*---------------------------------------------------------------------*/ + +struct tda18271_cid_target_map { + u32 rfmax; + u8 target; + u16 limit; +}; + +static struct tda18271_cid_target_map tda18271_cid_target[] = { + { .rfmax = 46000, .target = 0x04, .limit = 1800 }, + { .rfmax = 52200, .target = 0x0a, .limit = 1500 }, + { .rfmax = 70100, .target = 0x01, .limit = 4000 }, + { .rfmax = 136800, .target = 0x18, .limit = 4000 }, + { .rfmax = 156700, .target = 0x18, .limit = 4000 }, + { .rfmax = 186250, .target = 0x0a, .limit = 4000 }, + { .rfmax = 230000, .target = 0x0a, .limit = 4000 }, + { .rfmax = 345000, .target = 0x18, .limit = 4000 }, + { .rfmax = 426000, .target = 0x0e, .limit = 4000 }, + { .rfmax = 489500, .target = 0x1e, .limit = 4000 }, + { .rfmax = 697500, .target = 0x32, .limit = 4000 }, + { .rfmax = 842000, .target = 0x3a, .limit = 4000 }, + { .rfmax = 0, .target = 0x00, .limit = 0 }, /* end */ +}; + +int tda18271_lookup_cid_target(struct dvb_frontend *fe, + u32 *freq, u8 *cid_target, u16 *count_limit) +{ + struct tda18271_priv *priv = fe->tuner_priv; + int i = 0; + + while ((tda18271_cid_target[i].rfmax * 1000) < *freq) { + if (tda18271_cid_target[i + 1].rfmax == 0) + break; + i++; + } + *cid_target = tda18271_cid_target[i].target; + *count_limit = tda18271_cid_target[i].limit; + + tda_map("(%d) cid_target = %02x, count_limit = %d\n", i, + tda18271_cid_target[i].target, tda18271_cid_target[i].limit); + + return 0; +} + +/*---------------------------------------------------------------------*/ + +static struct tda18271_rf_tracking_filter_cal tda18271_rf_band_template[] = { + { .rfmax = 47900, .rfband = 0x00, + .rf1_def = 46000, .rf2_def = 0, .rf3_def = 0 }, + { .rfmax = 61100, .rfband = 0x01, + .rf1_def = 52200, .rf2_def = 0, .rf3_def = 0 }, + { .rfmax = 152600, .rfband = 0x02, + .rf1_def = 70100, .rf2_def = 136800, .rf3_def = 0 }, + { .rfmax = 164700, .rfband = 0x03, + .rf1_def = 156700, .rf2_def = 0, .rf3_def = 0 }, + { .rfmax = 203500, .rfband = 0x04, + .rf1_def = 186250, .rf2_def = 0, .rf3_def = 0 }, + { .rfmax = 457800, .rfband = 0x05, + .rf1_def = 230000, .rf2_def = 345000, .rf3_def = 426000 }, + { .rfmax = 865000, .rfband = 0x06, + .rf1_def = 489500, .rf2_def = 697500, .rf3_def = 842000 }, + { .rfmax = 0, .rfband = 0x00, + .rf1_def = 0, .rf2_def = 0, .rf3_def = 0 }, /* end */ +}; + +int tda18271_lookup_rf_band(struct dvb_frontend *fe, u32 *freq, u8 *rf_band) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; + int i = 0; + + while ((map[i].rfmax * 1000) < *freq) { + if (tda18271_debug & DBG_ADV) + tda_map("(%d) rfmax = %d < freq = %d, " + "rf1_def = %d, rf2_def = %d, rf3_def = %d, " + "rf1 = %d, rf2 = %d, rf3 = %d, " + "rf_a1 = %d, rf_a2 = %d, " + "rf_b1 = %d, rf_b2 = %d\n", + i, map[i].rfmax * 1000, *freq, + map[i].rf1_def, map[i].rf2_def, map[i].rf3_def, + map[i].rf1, map[i].rf2, map[i].rf3, + map[i].rf_a1, map[i].rf_a2, + map[i].rf_b1, map[i].rf_b2); + if (map[i].rfmax == 0) + return -EINVAL; + i++; + } + if (rf_band) + *rf_band = map[i].rfband; + + tda_map("(%d) rf_band = %02x\n", i, map[i].rfband); + + return i; +} + +/*---------------------------------------------------------------------*/ + +struct tda18271_map_layout { + struct tda18271_pll_map *main_pll; + struct tda18271_pll_map *cal_pll; + + struct tda18271_map *rf_cal; + struct tda18271_map *rf_cal_kmco; + struct tda18271_map *rf_cal_dc_over_dt; + + struct tda18271_map *bp_filter; + struct tda18271_map *rf_band; + struct tda18271_map *gain_taper; + struct tda18271_map *ir_measure; +}; + +/*---------------------------------------------------------------------*/ + +int tda18271_lookup_pll_map(struct dvb_frontend *fe, + enum tda18271_map_type map_type, + u32 *freq, u8 *post_div, u8 *div) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_pll_map *map = NULL; + unsigned int i = 0; + char *map_name; + int ret = 0; + + BUG_ON(!priv->maps); + + switch (map_type) { + case MAIN_PLL: + map = priv->maps->main_pll; + map_name = "main_pll"; + break; + case CAL_PLL: + map = priv->maps->cal_pll; + map_name = "cal_pll"; + break; + default: + /* we should never get here */ + map_name = "undefined"; + break; + } + + if (!map) { + tda_warn("%s map is not set!\n", map_name); + ret = -EINVAL; + goto fail; + } + + while ((map[i].lomax * 1000) < *freq) { + if (map[i + 1].lomax == 0) { + tda_map("%s: frequency (%d) out of range\n", + map_name, *freq); + ret = -ERANGE; + break; + } + i++; + } + *post_div = map[i].pd; + *div = map[i].d; + + tda_map("(%d) %s: post div = 0x%02x, div = 0x%02x\n", + i, map_name, *post_div, *div); +fail: + return ret; +} + +int tda18271_lookup_map(struct dvb_frontend *fe, + enum tda18271_map_type map_type, + u32 *freq, u8 *val) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_map *map = NULL; + unsigned int i = 0; + char *map_name; + int ret = 0; + + BUG_ON(!priv->maps); + + switch (map_type) { + case BP_FILTER: + map = priv->maps->bp_filter; + map_name = "bp_filter"; + break; + case RF_CAL_KMCO: + map = priv->maps->rf_cal_kmco; + map_name = "km"; + break; + case RF_BAND: + map = priv->maps->rf_band; + map_name = "rf_band"; + break; + case GAIN_TAPER: + map = priv->maps->gain_taper; + map_name = "gain_taper"; + break; + case RF_CAL: + map = priv->maps->rf_cal; + map_name = "rf_cal"; + break; + case IR_MEASURE: + map = priv->maps->ir_measure; + map_name = "ir_measure"; + break; + case RF_CAL_DC_OVER_DT: + map = priv->maps->rf_cal_dc_over_dt; + map_name = "rf_cal_dc_over_dt"; + break; + default: + /* we should never get here */ + map_name = "undefined"; + break; + } + + if (!map) { + tda_warn("%s map is not set!\n", map_name); + ret = -EINVAL; + goto fail; + } + + while ((map[i].rfmax * 1000) < *freq) { + if (map[i + 1].rfmax == 0) { + tda_map("%s: frequency (%d) out of range\n", + map_name, *freq); + ret = -ERANGE; + break; + } + i++; + } + *val = map[i].val; + + tda_map("(%d) %s: 0x%02x\n", i, map_name, *val); +fail: + return ret; +} + +/*---------------------------------------------------------------------*/ + +static struct tda18271_std_map tda18271c1_std_map = { + .fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */ + .atv_b = { .if_freq = 6750, .fm_rfn = 0, .agc_mode = 1, .std = 6, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ + .atv_dk = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ + .atv_gh = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ + .atv_i = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ + .atv_l = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ + .atv_lc = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 7, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ + .atv_mn = { .if_freq = 5750, .fm_rfn = 0, .agc_mode = 1, .std = 5, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */ + .atsc_6 = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ + .dvbt_6 = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ + .dvbt_7 = { .if_freq = 3800, .fm_rfn = 0, .agc_mode = 3, .std = 5, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ + .dvbt_8 = { .if_freq = 4300, .fm_rfn = 0, .agc_mode = 3, .std = 6, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ + .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ + .qam_7 = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ + .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */ +}; + +static struct tda18271_std_map tda18271c2_std_map = { + .fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */ + .atv_b = { .if_freq = 6000, .fm_rfn = 0, .agc_mode = 1, .std = 5, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */ + .atv_dk = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ + .atv_gh = { .if_freq = 7100, .fm_rfn = 0, .agc_mode = 1, .std = 6, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ + .atv_i = { .if_freq = 7250, .fm_rfn = 0, .agc_mode = 1, .std = 6, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ + .atv_l = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ + .atv_lc = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 6, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ + .atv_mn = { .if_freq = 5400, .fm_rfn = 0, .agc_mode = 1, .std = 4, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0c */ + .atsc_6 = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ + .dvbt_6 = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ + .dvbt_7 = { .if_freq = 3500, .fm_rfn = 0, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ + .dvbt_8 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ + .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ + .qam_7 = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ + .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */ +}; + +/*---------------------------------------------------------------------*/ + +static struct tda18271_map_layout tda18271c1_map_layout = { + .main_pll = tda18271c1_main_pll, + .cal_pll = tda18271c1_cal_pll, + + .rf_cal = tda18271c1_rf_cal, + .rf_cal_kmco = tda18271c1_km, + + .bp_filter = tda18271_bp_filter, + .rf_band = tda18271_rf_band, + .gain_taper = tda18271_gain_taper, + .ir_measure = tda18271_ir_measure, +}; + +static struct tda18271_map_layout tda18271c2_map_layout = { + .main_pll = tda18271c2_main_pll, + .cal_pll = tda18271c2_cal_pll, + + .rf_cal = tda18271c2_rf_cal, + .rf_cal_kmco = tda18271c2_km, + + .rf_cal_dc_over_dt = tda18271_rf_cal_dc_over_dt, + + .bp_filter = tda18271_bp_filter, + .rf_band = tda18271_rf_band, + .gain_taper = tda18271_gain_taper, + .ir_measure = tda18271_ir_measure, +}; + +int tda18271_assign_map_layout(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + int ret = 0; + + switch (priv->id) { + case TDA18271HDC1: + priv->maps = &tda18271c1_map_layout; + memcpy(&priv->std, &tda18271c1_std_map, + sizeof(struct tda18271_std_map)); + break; + case TDA18271HDC2: + priv->maps = &tda18271c2_map_layout; + memcpy(&priv->std, &tda18271c2_std_map, + sizeof(struct tda18271_std_map)); + break; + default: + ret = -EINVAL; + break; + } + memcpy(priv->rf_cal_state, &tda18271_rf_band_template, + sizeof(tda18271_rf_band_template)); + + return ret; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/tuners/tda18271-priv.h b/drivers/media/tuners/tda18271-priv.h new file mode 100644 index 000000000000..454c152ccaa0 --- /dev/null +++ b/drivers/media/tuners/tda18271-priv.h @@ -0,0 +1,236 @@ +/* + tda18271-priv.h - private header for the NXP TDA18271 silicon tuner + + Copyright (C) 2007, 2008 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 __TDA18271_PRIV_H__ +#define __TDA18271_PRIV_H__ + +#include +#include +#include +#include "tuner-i2c.h" +#include "tda18271.h" + +#define R_ID 0x00 /* ID byte */ +#define R_TM 0x01 /* Thermo byte */ +#define R_PL 0x02 /* Power level byte */ +#define R_EP1 0x03 /* Easy Prog byte 1 */ +#define R_EP2 0x04 /* Easy Prog byte 2 */ +#define R_EP3 0x05 /* Easy Prog byte 3 */ +#define R_EP4 0x06 /* Easy Prog byte 4 */ +#define R_EP5 0x07 /* Easy Prog byte 5 */ +#define R_CPD 0x08 /* Cal Post-Divider byte */ +#define R_CD1 0x09 /* Cal Divider byte 1 */ +#define R_CD2 0x0a /* Cal Divider byte 2 */ +#define R_CD3 0x0b /* Cal Divider byte 3 */ +#define R_MPD 0x0c /* Main Post-Divider byte */ +#define R_MD1 0x0d /* Main Divider byte 1 */ +#define R_MD2 0x0e /* Main Divider byte 2 */ +#define R_MD3 0x0f /* Main Divider byte 3 */ +#define R_EB1 0x10 /* Extended byte 1 */ +#define R_EB2 0x11 /* Extended byte 2 */ +#define R_EB3 0x12 /* Extended byte 3 */ +#define R_EB4 0x13 /* Extended byte 4 */ +#define R_EB5 0x14 /* Extended byte 5 */ +#define R_EB6 0x15 /* Extended byte 6 */ +#define R_EB7 0x16 /* Extended byte 7 */ +#define R_EB8 0x17 /* Extended byte 8 */ +#define R_EB9 0x18 /* Extended byte 9 */ +#define R_EB10 0x19 /* Extended byte 10 */ +#define R_EB11 0x1a /* Extended byte 11 */ +#define R_EB12 0x1b /* Extended byte 12 */ +#define R_EB13 0x1c /* Extended byte 13 */ +#define R_EB14 0x1d /* Extended byte 14 */ +#define R_EB15 0x1e /* Extended byte 15 */ +#define R_EB16 0x1f /* Extended byte 16 */ +#define R_EB17 0x20 /* Extended byte 17 */ +#define R_EB18 0x21 /* Extended byte 18 */ +#define R_EB19 0x22 /* Extended byte 19 */ +#define R_EB20 0x23 /* Extended byte 20 */ +#define R_EB21 0x24 /* Extended byte 21 */ +#define R_EB22 0x25 /* Extended byte 22 */ +#define R_EB23 0x26 /* Extended byte 23 */ + +#define TDA18271_NUM_REGS 39 + +/*---------------------------------------------------------------------*/ + +struct tda18271_rf_tracking_filter_cal { + u32 rfmax; + u8 rfband; + u32 rf1_def; + u32 rf2_def; + u32 rf3_def; + u32 rf1; + u32 rf2; + u32 rf3; + s32 rf_a1; + s32 rf_b1; + s32 rf_a2; + s32 rf_b2; +}; + +enum tda18271_pll { + TDA18271_MAIN_PLL, + TDA18271_CAL_PLL, +}; + +struct tda18271_map_layout; + +enum tda18271_ver { + TDA18271HDC1, + TDA18271HDC2, +}; + +struct tda18271_priv { + unsigned char tda18271_regs[TDA18271_NUM_REGS]; + + struct list_head hybrid_tuner_instance_list; + struct tuner_i2c_props i2c_props; + + enum tda18271_mode mode; + enum tda18271_role role; + enum tda18271_i2c_gate gate; + enum tda18271_ver id; + enum tda18271_output_options output_opt; + enum tda18271_small_i2c small_i2c; + + unsigned int config; /* interface to saa713x / tda829x */ + unsigned int cal_initialized:1; + + u8 tm_rfcal; + + struct tda18271_map_layout *maps; + struct tda18271_std_map std; + struct tda18271_rf_tracking_filter_cal rf_cal_state[8]; + + struct mutex lock; + + u16 if_freq; + + u32 frequency; + u32 bandwidth; +}; + +/*---------------------------------------------------------------------*/ + +extern int tda18271_debug; + +#define DBG_INFO 1 +#define DBG_MAP 2 +#define DBG_REG 4 +#define DBG_ADV 8 +#define DBG_CAL 16 + +__attribute__((format(printf, 4, 5))) +int _tda_printk(struct tda18271_priv *state, const char *level, + const char *func, const char *fmt, ...); + +#define tda_printk(st, lvl, fmt, arg...) \ + _tda_printk(st, lvl, __func__, fmt, ##arg) + +#define tda_dprintk(st, lvl, fmt, arg...) \ +do { \ + if (tda18271_debug & lvl) \ + tda_printk(st, KERN_DEBUG, fmt, ##arg); \ +} while (0) + +#define tda_info(fmt, arg...) pr_info(fmt, ##arg) +#define tda_warn(fmt, arg...) tda_printk(priv, KERN_WARNING, fmt, ##arg) +#define tda_err(fmt, arg...) tda_printk(priv, KERN_ERR, fmt, ##arg) +#define tda_dbg(fmt, arg...) tda_dprintk(priv, DBG_INFO, fmt, ##arg) +#define tda_map(fmt, arg...) tda_dprintk(priv, DBG_MAP, fmt, ##arg) +#define tda_reg(fmt, arg...) tda_dprintk(priv, DBG_REG, fmt, ##arg) +#define tda_cal(fmt, arg...) tda_dprintk(priv, DBG_CAL, fmt, ##arg) + +#define tda_fail(ret) \ +({ \ + int __ret; \ + __ret = (ret < 0); \ + if (__ret) \ + tda_printk(priv, KERN_ERR, \ + "error %d on line %d\n", ret, __LINE__); \ + __ret; \ +}) + +/*---------------------------------------------------------------------*/ + +enum tda18271_map_type { + /* tda18271_pll_map */ + MAIN_PLL, + CAL_PLL, + /* tda18271_map */ + RF_CAL, + RF_CAL_KMCO, + RF_CAL_DC_OVER_DT, + BP_FILTER, + RF_BAND, + GAIN_TAPER, + IR_MEASURE, +}; + +extern int tda18271_lookup_pll_map(struct dvb_frontend *fe, + enum tda18271_map_type map_type, + u32 *freq, u8 *post_div, u8 *div); +extern int tda18271_lookup_map(struct dvb_frontend *fe, + enum tda18271_map_type map_type, + u32 *freq, u8 *val); + +extern int tda18271_lookup_thermometer(struct dvb_frontend *fe); + +extern int tda18271_lookup_rf_band(struct dvb_frontend *fe, + u32 *freq, u8 *rf_band); + +extern int tda18271_lookup_cid_target(struct dvb_frontend *fe, + u32 *freq, u8 *cid_target, + u16 *count_limit); + +extern int tda18271_assign_map_layout(struct dvb_frontend *fe); + +/*---------------------------------------------------------------------*/ + +extern int tda18271_read_regs(struct dvb_frontend *fe); +extern int tda18271_read_extended(struct dvb_frontend *fe); +extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len); +extern int tda18271_init_regs(struct dvb_frontend *fe); + +extern int tda18271_charge_pump_source(struct dvb_frontend *fe, + enum tda18271_pll pll, int force); +extern int tda18271_set_standby_mode(struct dvb_frontend *fe, + int sm, int sm_lt, int sm_xt); + +extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq); +extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq); + +extern int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq); + +#endif /* __TDA18271_PRIV_H__ */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/tuners/tda18271.h b/drivers/media/tuners/tda18271.h new file mode 100644 index 000000000000..640bae4e6a5a --- /dev/null +++ b/drivers/media/tuners/tda18271.h @@ -0,0 +1,134 @@ +/* + tda18271.h - header for the Philips / NXP TDA18271 silicon tuner + + Copyright (C) 2007, 2008 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 __TDA18271_H__ +#define __TDA18271_H__ + +#include +#include "dvb_frontend.h" + +struct tda18271_std_map_item { + u16 if_freq; + + /* EP3[4:3] */ + unsigned int agc_mode:2; + /* EP3[2:0] */ + unsigned int std:3; + /* EP4[7] */ + unsigned int fm_rfn:1; + /* EP4[4:2] */ + unsigned int if_lvl:3; + /* EB22[6:0] */ + unsigned int rfagc_top:7; +}; + +struct tda18271_std_map { + struct tda18271_std_map_item fm_radio; + struct tda18271_std_map_item atv_b; + struct tda18271_std_map_item atv_dk; + struct tda18271_std_map_item atv_gh; + struct tda18271_std_map_item atv_i; + struct tda18271_std_map_item atv_l; + struct tda18271_std_map_item atv_lc; + struct tda18271_std_map_item atv_mn; + struct tda18271_std_map_item atsc_6; + struct tda18271_std_map_item dvbt_6; + struct tda18271_std_map_item dvbt_7; + struct tda18271_std_map_item dvbt_8; + struct tda18271_std_map_item qam_6; + struct tda18271_std_map_item qam_7; + struct tda18271_std_map_item qam_8; +}; + +enum tda18271_role { + TDA18271_MASTER = 0, + TDA18271_SLAVE, +}; + +enum tda18271_i2c_gate { + TDA18271_GATE_AUTO = 0, + TDA18271_GATE_ANALOG, + TDA18271_GATE_DIGITAL, +}; + +enum tda18271_output_options { + /* slave tuner output & loop thru & xtal oscillator always on */ + TDA18271_OUTPUT_LT_XT_ON = 0, + + /* slave tuner output loop thru off */ + TDA18271_OUTPUT_LT_OFF = 1, + + /* xtal oscillator off */ + TDA18271_OUTPUT_XT_OFF = 2, +}; + +enum tda18271_small_i2c { + TDA18271_39_BYTE_CHUNK_INIT = 0, + TDA18271_16_BYTE_CHUNK_INIT = 16, + TDA18271_08_BYTE_CHUNK_INIT = 8, + TDA18271_03_BYTE_CHUNK_INIT = 3, +}; + +struct tda18271_config { + /* override default if freq / std settings (optional) */ + struct tda18271_std_map *std_map; + + /* master / slave tuner: master uses main pll, slave uses cal pll */ + enum tda18271_role role; + + /* use i2c gate provided by analog or digital demod */ + enum tda18271_i2c_gate gate; + + /* output options that can be disabled */ + enum tda18271_output_options output_opt; + + /* some i2c providers can't write all 39 registers at once */ + enum tda18271_small_i2c small_i2c; + + /* force rf tracking filter calibration on startup */ + unsigned int rf_cal_on_startup:1; + + /* interface to saa713x / tda829x */ + unsigned int config; +}; + +#define TDA18271_CALLBACK_CMD_AGC_ENABLE 0 + +enum tda18271_mode { + TDA18271_ANALOG = 0, + TDA18271_DIGITAL, +}; + +#if defined(CONFIG_MEDIA_TUNER_TDA18271) || (defined(CONFIG_MEDIA_TUNER_TDA18271_MODULE) && defined(MODULE)) +extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, + struct i2c_adapter *i2c, + struct tda18271_config *cfg); +#else +static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, + u8 addr, + struct i2c_adapter *i2c, + struct tda18271_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __TDA18271_H__ */ diff --git a/drivers/media/tuners/tda827x.c b/drivers/media/tuners/tda827x.c new file mode 100644 index 000000000000..a0d176267470 --- /dev/null +++ b/drivers/media/tuners/tda827x.c @@ -0,0 +1,917 @@ +/* + * + * (c) 2005 Hartmut Hackmann + * (c) 2007 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 +#include +#include +#include +#include + +#include "tda827x.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "tda827x: " args); \ + } while (0) + +struct tda827x_priv { + int i2c_addr; + struct i2c_adapter *i2c_adap; + struct tda827x_config *cfg; + + unsigned int sgIF; + unsigned char lpsel; + + u32 frequency; + u32 bandwidth; +}; + +static void tda827x_set_std(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda827x_priv *priv = fe->tuner_priv; + char *mode; + + priv->lpsel = 0; + if (params->std & V4L2_STD_MN) { + priv->sgIF = 92; + priv->lpsel = 1; + mode = "MN"; + } else if (params->std & V4L2_STD_B) { + priv->sgIF = 108; + mode = "B"; + } else if (params->std & V4L2_STD_GH) { + priv->sgIF = 124; + mode = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + priv->sgIF = 124; + mode = "I"; + } else if (params->std & V4L2_STD_DK) { + priv->sgIF = 124; + mode = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + priv->sgIF = 124; + mode = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + priv->sgIF = 20; + mode = "LC"; + } else { + priv->sgIF = 124; + mode = "xx"; + } + + if (params->mode == V4L2_TUNER_RADIO) { + priv->sgIF = 88; /* if frequency is 5.5 MHz */ + dprintk("setting tda827x to radio FM\n"); + } else + dprintk("setting tda827x to system %s\n", mode); +} + + +/* ------------------------------------------------------------------ */ + +struct tda827x_data { + u32 lomax; + u8 spd; + u8 bs; + u8 bp; + u8 cp; + u8 gc3; + u8 div1p5; +}; + +static const struct tda827x_data tda827x_table[] = { + { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, + { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, + { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, + { .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, + { .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, + { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, + { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} +}; + +static int tuner_transfer(struct dvb_frontend *fe, + struct i2c_msg *msg, + const int size) +{ + int rc; + struct tda827x_priv *priv = fe->tuner_priv; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + rc = i2c_transfer(priv->i2c_adap, msg, size); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (rc >= 0 && rc != size) + return -EIO; + + return rc; +} + +static int tda827xo_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct tda827x_priv *priv = fe->tuner_priv; + u8 buf[14]; + int rc; + + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + int i, tuner_freq, if_freq; + u32 N; + + dprintk("%s:\n", __func__); + if (c->bandwidth_hz == 0) { + if_freq = 5000000; + } else if (c->bandwidth_hz <= 6000000) { + if_freq = 4000000; + } else if (c->bandwidth_hz <= 7000000) { + if_freq = 4500000; + } else { /* 8 MHz */ + if_freq = 5000000; + } + tuner_freq = c->frequency; + + i = 0; + while (tda827x_table[i].lomax < tuner_freq) { + if (tda827x_table[i + 1].lomax == 0) + break; + i++; + } + + tuner_freq += if_freq; + + N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2); + buf[0] = 0; + buf[1] = (N>>8) | 0x40; + buf[2] = N & 0xff; + buf[3] = 0; + buf[4] = 0x52; + buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) + + (tda827x_table[i].bs << 3) + + tda827x_table[i].bp; + buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f; + buf[7] = 0xbf; + buf[8] = 0x2a; + buf[9] = 0x05; + buf[10] = 0xff; + buf[11] = 0x00; + buf[12] = 0x00; + buf[13] = 0x40; + + msg.len = 14; + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + msleep(500); + /* correct CP value */ + buf[0] = 0x30; + buf[1] = 0x50 + tda827x_table[i].cp; + msg.len = 2; + + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + priv->frequency = c->frequency; + priv->bandwidth = c->bandwidth_hz; + + return 0; + +err: + printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n", + __func__, priv->i2c_addr << 1); + return rc; +} + +static int tda827xo_sleep(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + static u8 buf[] = { 0x30, 0xd0 }; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + + dprintk("%s:\n", __func__); + tuner_transfer(fe, &msg, 1); + + if (priv->cfg && priv->cfg->sleep) + priv->cfg->sleep(fe); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int tda827xo_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + unsigned char tuner_reg[8]; + unsigned char reg2[2]; + u32 N; + int i; + struct tda827x_priv *priv = fe->tuner_priv; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 }; + unsigned int freq = params->frequency; + + tda827x_set_std(fe, params); + + if (params->mode == V4L2_TUNER_RADIO) + freq = freq / 1000; + + N = freq + priv->sgIF; + + i = 0; + while (tda827x_table[i].lomax < N * 62500) { + if (tda827x_table[i + 1].lomax == 0) + break; + i++; + } + + N = N << tda827x_table[i].spd; + + tuner_reg[0] = 0; + tuner_reg[1] = (unsigned char)(N>>8); + tuner_reg[2] = (unsigned char) N; + tuner_reg[3] = 0x40; + tuner_reg[4] = 0x52 + (priv->lpsel << 5); + tuner_reg[5] = (tda827x_table[i].spd << 6) + + (tda827x_table[i].div1p5 << 5) + + (tda827x_table[i].bs << 3) + tda827x_table[i].bp; + tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4); + tuner_reg[7] = 0x8f; + + msg.buf = tuner_reg; + msg.len = 8; + tuner_transfer(fe, &msg, 1); + + msg.buf = reg2; + msg.len = 2; + reg2[0] = 0x80; + reg2[1] = 0; + tuner_transfer(fe, &msg, 1); + + reg2[0] = 0x60; + reg2[1] = 0xbf; + tuner_transfer(fe, &msg, 1); + + reg2[0] = 0x30; + reg2[1] = tuner_reg[4] + 0x80; + tuner_transfer(fe, &msg, 1); + + msleep(1); + reg2[0] = 0x30; + reg2[1] = tuner_reg[4] + 4; + tuner_transfer(fe, &msg, 1); + + msleep(1); + reg2[0] = 0x30; + reg2[1] = tuner_reg[4]; + tuner_transfer(fe, &msg, 1); + + msleep(550); + reg2[0] = 0x30; + reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp; + tuner_transfer(fe, &msg, 1); + + reg2[0] = 0x60; + reg2[1] = 0x3f; + tuner_transfer(fe, &msg, 1); + + reg2[0] = 0x80; + reg2[1] = 0x08; /* Vsync en */ + tuner_transfer(fe, &msg, 1); + + priv->frequency = params->frequency; + + return 0; +} + +static void tda827xo_agcf(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + unsigned char data[] = { 0x80, 0x0c }; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = data, .len = 2}; + + tuner_transfer(fe, &msg, 1); +} + +/* ------------------------------------------------------------------ */ + +struct tda827xa_data { + u32 lomax; + u8 svco; + u8 spd; + u8 scr; + u8 sbs; + u8 gc3; +}; + +static struct tda827xa_data tda827xa_dvbt[] = { + { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, + { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, + { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} +}; + +static struct tda827xa_data tda827xa_dvbc[] = { + { .lomax = 50125000, .svco = 2, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3}, + { .lomax = 58500000, .svco = 3, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3}, + { .lomax = 69250000, .svco = 0, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, + { .lomax = 83625000, .svco = 1, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, + { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, + { .lomax = 100250000, .svco = 2, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1}, + { .lomax = 117000000, .svco = 3, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1}, + { .lomax = 138500000, .svco = 0, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, + { .lomax = 167250000, .svco = 1, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, + { .lomax = 187000000, .svco = 2, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, + { .lomax = 200500000, .svco = 2, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 1}, + { .lomax = 234000000, .svco = 3, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 3}, + { .lomax = 277000000, .svco = 0, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 3}, + { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 1}, + { .lomax = 334500000, .svco = 1, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3}, + { .lomax = 401000000, .svco = 2, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3}, + { .lomax = 468000000, .svco = 3, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 1}, + { .lomax = 535000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, + { .lomax = 554000000, .svco = 0, .spd = 0, .scr = 2, .sbs = 3, .gc3 = 1}, + { .lomax = 638000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, + { .lomax = 669000000, .svco = 1, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, + { .lomax = 720000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, + { .lomax = 802000000, .svco = 2, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, + { .lomax = 835000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, + { .lomax = 885000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, + { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, + { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} +}; + +static struct tda827xa_data tda827xa_analog[] = { + { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3}, + { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3}, + { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, + { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, + { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, + { .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, + { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} +}; + +static int tda827xa_sleep(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + static u8 buf[] = { 0x30, 0x90 }; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + + dprintk("%s:\n", __func__); + + tuner_transfer(fe, &msg, 1); + + if (priv->cfg && priv->cfg->sleep) + priv->cfg->sleep(fe); + + return 0; +} + +static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, + struct analog_parameters *params) +{ + struct tda827x_priv *priv = fe->tuner_priv; + unsigned char buf[] = {0x22, 0x01}; + int arg; + int gp_func; + struct i2c_msg msg = { .flags = 0, .buf = buf, .len = sizeof(buf) }; + + if (NULL == priv->cfg) { + dprintk("tda827x_config not defined, cannot set LNA gain!\n"); + return; + } + msg.addr = priv->cfg->switch_addr; + if (priv->cfg->config) { + if (high) + dprintk("setting LNA to high gain\n"); + else + dprintk("setting LNA to low gain\n"); + } + switch (priv->cfg->config) { + case 0: /* no LNA */ + break; + case 1: /* switch is GPIO 0 of tda8290 */ + case 2: + if (params == NULL) { + gp_func = 0; + arg = 0; + } else { + /* turn Vsync on */ + gp_func = 1; + if (params->std & V4L2_STD_MN) + arg = 1; + else + arg = 0; + } + if (fe->callback) + fe->callback(priv->i2c_adap->algo_data, + DVB_FRONTEND_COMPONENT_TUNER, + gp_func, arg); + buf[1] = high ? 0 : 1; + if (priv->cfg->config == 2) + buf[1] = high ? 1 : 0; + tuner_transfer(fe, &msg, 1); + break; + case 3: /* switch with GPIO of saa713x */ + if (fe->callback) + fe->callback(priv->i2c_adap->algo_data, + DVB_FRONTEND_COMPONENT_TUNER, 0, high); + break; + } +} + +static int tda827xa_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct tda827x_priv *priv = fe->tuner_priv; + struct tda827xa_data *frequency_map = tda827xa_dvbt; + u8 buf[11]; + + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + + int i, tuner_freq, if_freq, rc; + u32 N; + + dprintk("%s:\n", __func__); + + tda827xa_lna_gain(fe, 1, NULL); + msleep(20); + + if (c->bandwidth_hz == 0) { + if_freq = 5000000; + } else if (c->bandwidth_hz <= 6000000) { + if_freq = 4000000; + } else if (c->bandwidth_hz <= 7000000) { + if_freq = 4500000; + } else { /* 8 MHz */ + if_freq = 5000000; + } + tuner_freq = c->frequency; + + switch (c->delivery_system) { + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + dprintk("%s select tda827xa_dvbc\n", __func__); + frequency_map = tda827xa_dvbc; + break; + default: + break; + } + + i = 0; + while (frequency_map[i].lomax < tuner_freq) { + if (frequency_map[i + 1].lomax == 0) + break; + i++; + } + + tuner_freq += if_freq; + + N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd; + buf[0] = 0; // subaddress + buf[1] = N >> 8; + buf[2] = N & 0xff; + buf[3] = 0; + buf[4] = 0x16; + buf[5] = (frequency_map[i].spd << 5) + (frequency_map[i].svco << 3) + + frequency_map[i].sbs; + buf[6] = 0x4b + (frequency_map[i].gc3 << 4); + buf[7] = 0x1c; + buf[8] = 0x06; + buf[9] = 0x24; + buf[10] = 0x00; + msg.len = 11; + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + buf[0] = 0x90; + buf[1] = 0xff; + buf[2] = 0x60; + buf[3] = 0x00; + buf[4] = 0x59; // lpsel, for 6MHz + 2 + msg.len = 5; + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + buf[0] = 0xa0; + buf[1] = 0x40; + msg.len = 2; + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + msleep(11); + msg.flags = I2C_M_RD; + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + msg.flags = 0; + + buf[1] >>= 4; + dprintk("tda8275a AGC2 gain is: %d\n", buf[1]); + if ((buf[1]) < 2) { + tda827xa_lna_gain(fe, 0, NULL); + buf[0] = 0x60; + buf[1] = 0x0c; + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + } + + buf[0] = 0xc0; + buf[1] = 0x99; // lpsel, for 6MHz + 2 + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + buf[0] = 0x60; + buf[1] = 0x3c; + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + /* correct CP value */ + buf[0] = 0x30; + buf[1] = 0x10 + frequency_map[i].scr; + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + msleep(163); + buf[0] = 0xc0; + buf[1] = 0x39; // lpsel, for 6MHz + 2 + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + msleep(3); + /* freeze AGC1 */ + buf[0] = 0x50; + buf[1] = 0x4f + (frequency_map[i].gc3 << 4); + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + priv->frequency = c->frequency; + priv->bandwidth = c->bandwidth_hz; + + return 0; + +err: + printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n", + __func__, priv->i2c_addr << 1); + return rc; +} + + +static int tda827xa_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + unsigned char tuner_reg[11]; + u32 N; + int i; + struct tda827x_priv *priv = fe->tuner_priv; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = tuner_reg, .len = sizeof(tuner_reg) }; + unsigned int freq = params->frequency; + + tda827x_set_std(fe, params); + + tda827xa_lna_gain(fe, 1, params); + msleep(10); + + if (params->mode == V4L2_TUNER_RADIO) + freq = freq / 1000; + + N = freq + priv->sgIF; + + i = 0; + while (tda827xa_analog[i].lomax < N * 62500) { + if (tda827xa_analog[i + 1].lomax == 0) + break; + i++; + } + + N = N << tda827xa_analog[i].spd; + + tuner_reg[0] = 0; + tuner_reg[1] = (unsigned char)(N>>8); + tuner_reg[2] = (unsigned char) N; + tuner_reg[3] = 0; + tuner_reg[4] = 0x16; + tuner_reg[5] = (tda827xa_analog[i].spd << 5) + + (tda827xa_analog[i].svco << 3) + + tda827xa_analog[i].sbs; + tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); + tuner_reg[7] = 0x1c; + tuner_reg[8] = 4; + tuner_reg[9] = 0x20; + tuner_reg[10] = 0x00; + msg.len = 11; + tuner_transfer(fe, &msg, 1); + + tuner_reg[0] = 0x90; + tuner_reg[1] = 0xff; + tuner_reg[2] = 0xe0; + tuner_reg[3] = 0; + tuner_reg[4] = 0x99 + (priv->lpsel << 1); + msg.len = 5; + tuner_transfer(fe, &msg, 1); + + tuner_reg[0] = 0xa0; + tuner_reg[1] = 0xc0; + msg.len = 2; + tuner_transfer(fe, &msg, 1); + + tuner_reg[0] = 0x30; + tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; + tuner_transfer(fe, &msg, 1); + + msg.flags = I2C_M_RD; + tuner_transfer(fe, &msg, 1); + msg.flags = 0; + tuner_reg[1] >>= 4; + dprintk("AGC2 gain is: %d\n", tuner_reg[1]); + if (tuner_reg[1] < 1) + tda827xa_lna_gain(fe, 0, params); + + msleep(100); + tuner_reg[0] = 0x60; + tuner_reg[1] = 0x3c; + tuner_transfer(fe, &msg, 1); + + msleep(163); + tuner_reg[0] = 0x50; + tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); + tuner_transfer(fe, &msg, 1); + + tuner_reg[0] = 0x80; + tuner_reg[1] = 0x28; + tuner_transfer(fe, &msg, 1); + + tuner_reg[0] = 0xb0; + tuner_reg[1] = 0x01; + tuner_transfer(fe, &msg, 1); + + tuner_reg[0] = 0xc0; + tuner_reg[1] = 0x19 + (priv->lpsel << 1); + tuner_transfer(fe, &msg, 1); + + priv->frequency = params->frequency; + + return 0; +} + +static void tda827xa_agcf(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + unsigned char data[] = {0x80, 0x2c}; + struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0, + .buf = data, .len = 2}; + tuner_transfer(fe, &msg, 1); +} + +/* ------------------------------------------------------------------ */ + +static int tda827x_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda827x_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct tda827x_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static int tda827x_init(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + dprintk("%s:\n", __func__); + if (priv->cfg && priv->cfg->init) + priv->cfg->init(fe); + + return 0; +} + +static int tda827x_probe_version(struct dvb_frontend *fe); + +static int tda827x_initial_init(struct dvb_frontend *fe) +{ + int ret; + ret = tda827x_probe_version(fe); + if (ret) + return ret; + return fe->ops.tuner_ops.init(fe); +} + +static int tda827x_initial_sleep(struct dvb_frontend *fe) +{ + int ret; + ret = tda827x_probe_version(fe); + if (ret) + return ret; + return fe->ops.tuner_ops.sleep(fe); +} + +static struct dvb_tuner_ops tda827xo_tuner_ops = { + .info = { + .name = "Philips TDA827X", + .frequency_min = 55000000, + .frequency_max = 860000000, + .frequency_step = 250000 + }, + .release = tda827x_release, + .init = tda827x_initial_init, + .sleep = tda827x_initial_sleep, + .set_params = tda827xo_set_params, + .set_analog_params = tda827xo_set_analog_params, + .get_frequency = tda827x_get_frequency, + .get_bandwidth = tda827x_get_bandwidth, +}; + +static struct dvb_tuner_ops tda827xa_tuner_ops = { + .info = { + .name = "Philips TDA827XA", + .frequency_min = 44000000, + .frequency_max = 906000000, + .frequency_step = 62500 + }, + .release = tda827x_release, + .init = tda827x_init, + .sleep = tda827xa_sleep, + .set_params = tda827xa_set_params, + .set_analog_params = tda827xa_set_analog_params, + .get_frequency = tda827x_get_frequency, + .get_bandwidth = tda827x_get_bandwidth, +}; + +static int tda827x_probe_version(struct dvb_frontend *fe) +{ + u8 data; + int rc; + struct tda827x_priv *priv = fe->tuner_priv; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD, + .buf = &data, .len = 1 }; + + rc = tuner_transfer(fe, &msg, 1); + + if (rc < 0) { + printk("%s: could not read from tuner at addr: 0x%02x\n", + __func__, msg.addr << 1); + return rc; + } + if ((data & 0x3c) == 0) { + dprintk("tda827x tuner found\n"); + fe->ops.tuner_ops.init = tda827x_init; + fe->ops.tuner_ops.sleep = tda827xo_sleep; + if (priv->cfg) + priv->cfg->agcf = tda827xo_agcf; + } else { + dprintk("tda827xa tuner found\n"); + memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops)); + if (priv->cfg) + priv->cfg->agcf = tda827xa_agcf; + } + return 0; +} + +struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr, + struct i2c_adapter *i2c, + struct tda827x_config *cfg) +{ + struct tda827x_priv *priv = NULL; + + dprintk("%s:\n", __func__); + priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->i2c_addr = addr; + priv->i2c_adap = i2c; + priv->cfg = cfg; + memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops)); + fe->tuner_priv = priv; + + dprintk("type set to %s\n", fe->ops.tuner_ops.info.name); + + return fe; +} +EXPORT_SYMBOL_GPL(tda827x_attach); + +MODULE_DESCRIPTION("DVB TDA827x driver"); +MODULE_AUTHOR("Hartmut Hackmann "); +MODULE_AUTHOR("Michael Krufky "); +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/tuners/tda827x.h b/drivers/media/tuners/tda827x.h new file mode 100644 index 000000000000..7d72ce0a0c2d --- /dev/null +++ b/drivers/media/tuners/tda827x.h @@ -0,0 +1,68 @@ + /* + DVB Driver for Philips tda827x / tda827xa Silicon tuners + + (c) 2005 Hartmut Hackmann + (c) 2007 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_TDA827X_H__ +#define __DVB_TDA827X_H__ + +#include +#include "dvb_frontend.h" + +struct tda827x_config +{ + /* saa7134 - provided callbacks */ + int (*init) (struct dvb_frontend *fe); + int (*sleep) (struct dvb_frontend *fe); + + /* interface to tda829x driver */ + unsigned int config; + int switch_addr; + + void (*agcf)(struct dvb_frontend *fe); +}; + + +/** + * Attach a tda827x tuner to the supplied frontend structure. + * + * @param fe Frontend to attach to. + * @param addr i2c address of the tuner. + * @param i2c i2c adapter to use. + * @param cfg optional callback function pointers. + * @return FE pointer on success, NULL on failure. + */ +#if defined(CONFIG_MEDIA_TUNER_TDA827X) || (defined(CONFIG_MEDIA_TUNER_TDA827X_MODULE) && defined(MODULE)) +extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr, + struct i2c_adapter *i2c, + struct tda827x_config *cfg); +#else +static inline struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, + int addr, + struct i2c_adapter *i2c, + struct tda827x_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_MEDIA_TUNER_TDA827X + +#endif // __DVB_TDA827X_H__ diff --git a/drivers/media/tuners/tda8290.c b/drivers/media/tuners/tda8290.c new file mode 100644 index 000000000000..8c4852114eeb --- /dev/null +++ b/drivers/media/tuners/tda8290.c @@ -0,0 +1,874 @@ +/* + + i2c tv tuner chip device driver + controls the philips tda8290+75 tuner chip combo. + + 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. + + This "tda8290" module was split apart from the original "tuner" module. +*/ + +#include +#include +#include +#include +#include "tuner-i2c.h" +#include "tda8290.h" +#include "tda827x.h" +#include "tda18271.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +static int deemphasis_50; +module_param(deemphasis_50, int, 0644); +MODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis"); + +/* ---------------------------------------------------------------------- */ + +struct tda8290_priv { + struct tuner_i2c_props i2c_props; + + unsigned char tda8290_easy_mode; + + unsigned char tda827x_addr; + + unsigned char ver; +#define TDA8290 1 +#define TDA8295 2 +#define TDA8275 4 +#define TDA8275A 8 +#define TDA18271 16 + + struct tda827x_config cfg; +}; + +/*---------------------------------------------------------------------*/ + +static int tda8290_i2c_bridge(struct dvb_frontend *fe, int close) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char enable[2] = { 0x21, 0xC0 }; + unsigned char disable[2] = { 0x21, 0x00 }; + unsigned char *msg; + + if (close) { + msg = enable; + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); + /* let the bridge stabilize */ + msleep(20); + } else { + msg = disable; + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); + } + + return 0; +} + +static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char enable[2] = { 0x45, 0xc1 }; + unsigned char disable[2] = { 0x46, 0x00 }; + unsigned char buf[3] = { 0x45, 0x01, 0x00 }; + unsigned char *msg; + + if (close) { + msg = enable; + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); + /* let the bridge stabilize */ + msleep(20); + } else { + msg = disable; + tuner_i2c_xfer_send_recv(&priv->i2c_props, msg, 1, &msg[1], 1); + + buf[2] = msg[1]; + buf[2] &= ~0x04; + tuner_i2c_xfer_send(&priv->i2c_props, buf, 3); + msleep(5); + + msg[1] |= 0x04; + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); + } + + return 0; +} + +/*---------------------------------------------------------------------*/ + +static void set_audio(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + char* mode; + + if (params->std & V4L2_STD_MN) { + priv->tda8290_easy_mode = 0x01; + mode = "MN"; + } else if (params->std & V4L2_STD_B) { + priv->tda8290_easy_mode = 0x02; + mode = "B"; + } else if (params->std & V4L2_STD_GH) { + priv->tda8290_easy_mode = 0x04; + mode = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + priv->tda8290_easy_mode = 0x08; + mode = "I"; + } else if (params->std & V4L2_STD_DK) { + priv->tda8290_easy_mode = 0x10; + mode = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + priv->tda8290_easy_mode = 0x20; + mode = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + priv->tda8290_easy_mode = 0x40; + mode = "LC"; + } else { + priv->tda8290_easy_mode = 0x10; + mode = "xx"; + } + + if (params->mode == V4L2_TUNER_RADIO) { + /* Set TDA8295 to FM radio; Start TDA8290 with MN values */ + priv->tda8290_easy_mode = (priv->ver & TDA8295) ? 0x80 : 0x01; + tuner_dbg("setting to radio FM\n"); + } else { + tuner_dbg("setting tda829x to system %s\n", mode); + } +} + +static struct { + unsigned char seq[2]; +} fm_mode[] = { + { { 0x01, 0x81} }, /* Put device into expert mode */ + { { 0x03, 0x48} }, /* Disable NOTCH and VIDEO filters */ + { { 0x04, 0x04} }, /* Disable color carrier filter (SSIF) */ + { { 0x05, 0x04} }, /* ADC headroom */ + { { 0x06, 0x10} }, /* group delay flat */ + + { { 0x07, 0x00} }, /* use the same radio DTO values as a tda8295 */ + { { 0x08, 0x00} }, + { { 0x09, 0x80} }, + { { 0x0a, 0xda} }, + { { 0x0b, 0x4b} }, + { { 0x0c, 0x68} }, + + { { 0x0d, 0x00} }, /* PLL off, no video carrier detect */ + { { 0x14, 0x00} }, /* disable auto mute if no video */ +}; + +static void tda8290_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char soft_reset[] = { 0x00, 0x00 }; + unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; + unsigned char expert_mode[] = { 0x01, 0x80 }; + unsigned char agc_out_on[] = { 0x02, 0x00 }; + unsigned char gainset_off[] = { 0x28, 0x14 }; + unsigned char if_agc_spd[] = { 0x0f, 0x88 }; + unsigned char adc_head_6[] = { 0x05, 0x04 }; + unsigned char adc_head_9[] = { 0x05, 0x02 }; + unsigned char adc_head_12[] = { 0x05, 0x01 }; + unsigned char pll_bw_nom[] = { 0x0d, 0x47 }; + unsigned char pll_bw_low[] = { 0x0d, 0x27 }; + unsigned char gainset_2[] = { 0x28, 0x64 }; + unsigned char agc_rst_on[] = { 0x0e, 0x0b }; + unsigned char agc_rst_off[] = { 0x0e, 0x09 }; + unsigned char if_agc_set[] = { 0x0f, 0x81 }; + unsigned char addr_adc_sat = 0x1a; + unsigned char addr_agc_stat = 0x1d; + unsigned char addr_pll_stat = 0x1b; + unsigned char adc_sat, agc_stat, + pll_stat; + int i; + + set_audio(fe, params); + + if (priv->cfg.config) + tuner_dbg("tda827xa config is 0x%02x\n", priv->cfg.config); + tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); + tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); + tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); + msleep(1); + + if (params->mode == V4L2_TUNER_RADIO) { + unsigned char deemphasis[] = { 0x13, 1 }; + + /* FIXME: allow using a different deemphasis */ + + if (deemphasis_50) + deemphasis[1] = 2; + + for (i = 0; i < ARRAY_SIZE(fm_mode); i++) + tuner_i2c_xfer_send(&priv->i2c_props, fm_mode[i].seq, 2); + + tuner_i2c_xfer_send(&priv->i2c_props, deemphasis, 2); + } else { + expert_mode[1] = priv->tda8290_easy_mode + 0x80; + tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2); + tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2); + tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2); + if (priv->tda8290_easy_mode & 0x60) + tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2); + else + tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2); + tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); + } + + + tda8290_i2c_bridge(fe, 1); + + if (fe->ops.tuner_ops.set_analog_params) + fe->ops.tuner_ops.set_analog_params(fe, params); + + for (i = 0; i < 3; i++) { + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_pll_stat, 1, &pll_stat, 1); + if (pll_stat & 0x80) { + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_adc_sat, 1, + &adc_sat, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_agc_stat, 1, + &agc_stat, 1); + tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat); + break; + } else { + tuner_dbg("tda8290 not locked, no signal?\n"); + msleep(100); + } + } + /* adjust headroom resp. gain */ + if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) { + tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n", + agc_stat, adc_sat, pll_stat & 0x80); + tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2); + msleep(100); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_agc_stat, 1, &agc_stat, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_pll_stat, 1, &pll_stat, 1); + if ((agc_stat > 115) || !(pll_stat & 0x80)) { + tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", + agc_stat, pll_stat & 0x80); + if (priv->cfg.agcf) + priv->cfg.agcf(fe); + msleep(100); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_agc_stat, 1, + &agc_stat, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_pll_stat, 1, + &pll_stat, 1); + if((agc_stat > 115) || !(pll_stat & 0x80)) { + tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat); + tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2); + tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_low, 2); + msleep(100); + } + } + } + + /* l/ l' deadlock? */ + if(priv->tda8290_easy_mode & 0x60) { + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_adc_sat, 1, + &adc_sat, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_pll_stat, 1, + &pll_stat, 1); + if ((adc_sat > 20) || !(pll_stat & 0x80)) { + tuner_dbg("trying to resolve SECAM L deadlock\n"); + tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2); + msleep(40); + tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_off, 2); + } + } + + tda8290_i2c_bridge(fe, 0); + tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); +} + +/*---------------------------------------------------------------------*/ + +static void tda8295_power(struct dvb_frontend *fe, int enable) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */ + + tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); + + if (enable) + buf[1] = 0x01; + else + buf[1] = 0x03; + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); +} + +static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char buf[] = { 0x01, 0x00 }; + + tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); + + if (enable) + buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */ + else + buf[1] = 0x00; /* reset active bit */ + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); +} + +static void tda8295_set_video_std(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char buf[] = { 0x00, priv->tda8290_easy_mode }; + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); + + tda8295_set_easy_mode(fe, 1); + msleep(20); + tda8295_set_easy_mode(fe, 0); +} + +/*---------------------------------------------------------------------*/ + +static void tda8295_agc1_out(struct dvb_frontend *fe, int enable) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */ + + tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); + + if (enable) + buf[1] &= ~0x40; + else + buf[1] |= 0x40; + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); +} + +static void tda8295_agc2_out(struct dvb_frontend *fe, int enable) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char set_gpio_cf[] = { 0x44, 0x00 }; + unsigned char set_gpio_val[] = { 0x46, 0x00 }; + + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &set_gpio_cf[0], 1, &set_gpio_cf[1], 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &set_gpio_val[0], 1, &set_gpio_val[1], 1); + + set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */ + + if (enable) { + set_gpio_cf[1] |= 0x01; /* config GPIO_0 as Open Drain Out */ + set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */ + } + tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2); +} + +static int tda8295_has_signal(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char hvpll_stat = 0x26; + unsigned char ret; + + tuner_i2c_xfer_send_recv(&priv->i2c_props, &hvpll_stat, 1, &ret, 1); + return (ret & 0x01) ? 65535 : 0; +} + +/*---------------------------------------------------------------------*/ + +static void tda8295_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char blanking_mode[] = { 0x1d, 0x00 }; + + set_audio(fe, params); + + tuner_dbg("%s: freq = %d\n", __func__, params->frequency); + + tda8295_power(fe, 1); + tda8295_agc1_out(fe, 1); + + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &blanking_mode[0], 1, &blanking_mode[1], 1); + + tda8295_set_video_std(fe); + + blanking_mode[1] = 0x03; + tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2); + msleep(20); + + tda8295_i2c_bridge(fe, 1); + + if (fe->ops.tuner_ops.set_analog_params) + fe->ops.tuner_ops.set_analog_params(fe, params); + + if (priv->cfg.agcf) + priv->cfg.agcf(fe); + + if (tda8295_has_signal(fe)) + tuner_dbg("tda8295 is locked\n"); + else + tuner_dbg("tda8295 not locked, no signal?\n"); + + tda8295_i2c_bridge(fe, 0); +} + +/*---------------------------------------------------------------------*/ + +static int tda8290_has_signal(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char i2c_get_afc[1] = { 0x1B }; + unsigned char afc = 0; + + tuner_i2c_xfer_send_recv(&priv->i2c_props, + i2c_get_afc, ARRAY_SIZE(i2c_get_afc), &afc, 1); + return (afc & 0x80)? 65535:0; +} + +/*---------------------------------------------------------------------*/ + +static void tda8290_standby(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char cb1[] = { 0x30, 0xD0 }; + unsigned char tda8290_standby[] = { 0x00, 0x02 }; + unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; + struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; + + tda8290_i2c_bridge(fe, 1); + if (priv->ver & TDA8275A) + cb1[1] = 0x90; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + tda8290_i2c_bridge(fe, 0); + tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); + tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); +} + +static void tda8295_standby(struct dvb_frontend *fe) +{ + tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */ + + tda8295_power(fe, 0); +} + +static void tda8290_init_if(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char set_VS[] = { 0x30, 0x6F }; + unsigned char set_GP00_CF[] = { 0x20, 0x01 }; + unsigned char set_GP01_CF[] = { 0x20, 0x0B }; + + if ((priv->cfg.config == 1) || (priv->cfg.config == 2)) + tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); + else + tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); +} + +static void tda8295_init_if(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + static unsigned char set_adc_ctl[] = { 0x33, 0x14 }; + static unsigned char set_adc_ctl2[] = { 0x34, 0x00 }; + static unsigned char set_pll_reg6[] = { 0x3e, 0x63 }; + static unsigned char set_pll_reg0[] = { 0x38, 0x23 }; + static unsigned char set_pll_reg7[] = { 0x3f, 0x01 }; + static unsigned char set_pll_reg10[] = { 0x42, 0x61 }; + static unsigned char set_gpio_reg0[] = { 0x44, 0x0b }; + + tda8295_power(fe, 1); + + tda8295_set_easy_mode(fe, 0); + tda8295_set_video_std(fe); + + tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2); + + tda8295_agc1_out(fe, 0); + tda8295_agc2_out(fe, 0); +} + +static void tda8290_init_tuner(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, + 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; + unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, + 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b }; + struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, + .buf=tda8275_init, .len = 14}; + if (priv->ver & TDA8275A) + msg.buf = tda8275a_init; + + tda8290_i2c_bridge(fe, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); + tda8290_i2c_bridge(fe, 0); +} + +/*---------------------------------------------------------------------*/ + +static void tda829x_release(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + /* only try to release the tuner if we've + * attached it from within this module */ + if (priv->ver & (TDA18271 | TDA8275 | TDA8275A)) + if (fe->ops.tuner_ops.release) + fe->ops.tuner_ops.release(fe); + + kfree(fe->analog_demod_priv); + fe->analog_demod_priv = NULL; +} + +static struct tda18271_config tda829x_tda18271_config = { + .gate = TDA18271_GATE_ANALOG, +}; + +static int tda829x_find_tuner(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + struct analog_demod_ops *analog_ops = &fe->ops.analog_ops; + int i, ret, tuners_found; + u32 tuner_addrs; + u8 data; + struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; + + if (!analog_ops->i2c_gate_ctrl) { + printk(KERN_ERR "tda8290: no gate control were provided!\n"); + + return -EINVAL; + } + + analog_ops->i2c_gate_ctrl(fe, 1); + + /* probe for tuner chip */ + tuners_found = 0; + tuner_addrs = 0; + for (i = 0x60; i <= 0x63; i++) { + msg.addr = i; + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); + if (ret == 1) { + tuners_found++; + tuner_addrs = (tuner_addrs << 8) + i; + } + } + /* if there is more than one tuner, we expect the right one is + behind the bridge and we choose the highest address that doesn't + give a response now + */ + + analog_ops->i2c_gate_ctrl(fe, 0); + + if (tuners_found > 1) + for (i = 0; i < tuners_found; i++) { + msg.addr = tuner_addrs & 0xff; + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); + if (ret == 1) + tuner_addrs = tuner_addrs >> 8; + else + break; + } + + if (tuner_addrs == 0) { + tuner_addrs = 0x60; + tuner_info("could not clearly identify tuner address, " + "defaulting to %x\n", tuner_addrs); + } else { + tuner_addrs = tuner_addrs & 0xff; + tuner_info("setting tuner address to %x\n", tuner_addrs); + } + priv->tda827x_addr = tuner_addrs; + msg.addr = tuner_addrs; + + analog_ops->i2c_gate_ctrl(fe, 1); + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); + + if (ret != 1) { + tuner_warn("tuner access failed!\n"); + analog_ops->i2c_gate_ctrl(fe, 0); + return -EREMOTEIO; + } + + if ((data == 0x83) || (data == 0x84)) { + priv->ver |= TDA18271; + tda829x_tda18271_config.config = priv->cfg.config; + dvb_attach(tda18271_attach, fe, priv->tda827x_addr, + priv->i2c_props.adap, &tda829x_tda18271_config); + } else { + if ((data & 0x3c) == 0) + priv->ver |= TDA8275; + else + priv->ver |= TDA8275A; + + dvb_attach(tda827x_attach, fe, priv->tda827x_addr, + priv->i2c_props.adap, &priv->cfg); + priv->cfg.switch_addr = priv->i2c_props.addr; + } + if (fe->ops.tuner_ops.init) + fe->ops.tuner_ops.init(fe); + + if (fe->ops.tuner_ops.sleep) + fe->ops.tuner_ops.sleep(fe); + + analog_ops->i2c_gate_ctrl(fe, 0); + + return 0; +} + +static int tda8290_probe(struct tuner_i2c_props *i2c_props) +{ +#define TDA8290_ID 0x89 + u8 reg = 0x1f, id; + struct i2c_msg msg_read[] = { + { .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = ® }, + { .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id }, + }; + + /* detect tda8290 */ + if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) { + printk(KERN_WARNING "%s: couldn't read register 0x%02x\n", + __func__, reg); + return -ENODEV; + } + + if (id == TDA8290_ID) { + if (debug) + printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n", + __func__, i2c_adapter_id(i2c_props->adap), + i2c_props->addr); + return 0; + } + return -ENODEV; +} + +static int tda8295_probe(struct tuner_i2c_props *i2c_props) +{ +#define TDA8295_ID 0x8a +#define TDA8295C2_ID 0x8b + u8 reg = 0x2f, id; + struct i2c_msg msg_read[] = { + { .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = ® }, + { .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id }, + }; + + /* detect tda8295 */ + if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) { + printk(KERN_WARNING "%s: couldn't read register 0x%02x\n", + __func__, reg); + return -ENODEV; + } + + if ((id & 0xfe) == TDA8295_ID) { + if (debug) + printk(KERN_DEBUG "%s: %s detected @ %d-%04x\n", + __func__, (id == TDA8295_ID) ? + "tda8295c1" : "tda8295c2", + i2c_adapter_id(i2c_props->adap), + i2c_props->addr); + return 0; + } + + return -ENODEV; +} + +static struct analog_demod_ops tda8290_ops = { + .set_params = tda8290_set_params, + .has_signal = tda8290_has_signal, + .standby = tda8290_standby, + .release = tda829x_release, + .i2c_gate_ctrl = tda8290_i2c_bridge, +}; + +static struct analog_demod_ops tda8295_ops = { + .set_params = tda8295_set_params, + .has_signal = tda8295_has_signal, + .standby = tda8295_standby, + .release = tda829x_release, + .i2c_gate_ctrl = tda8295_i2c_bridge, +}; + +struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, u8 i2c_addr, + struct tda829x_config *cfg) +{ + struct tda8290_priv *priv = NULL; + char *name; + + priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + fe->analog_demod_priv = priv; + + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + priv->i2c_props.name = "tda829x"; + if (cfg) + priv->cfg.config = cfg->lna_cfg; + + if (tda8290_probe(&priv->i2c_props) == 0) { + priv->ver = TDA8290; + memcpy(&fe->ops.analog_ops, &tda8290_ops, + sizeof(struct analog_demod_ops)); + } + + if (tda8295_probe(&priv->i2c_props) == 0) { + priv->ver = TDA8295; + memcpy(&fe->ops.analog_ops, &tda8295_ops, + sizeof(struct analog_demod_ops)); + } + + if (!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) { + tda8295_power(fe, 1); + if (tda829x_find_tuner(fe) < 0) + goto fail; + } + + switch (priv->ver) { + case TDA8290: + name = "tda8290"; + break; + case TDA8295: + name = "tda8295"; + break; + case TDA8290 | TDA8275: + name = "tda8290+75"; + break; + case TDA8295 | TDA8275: + name = "tda8295+75"; + break; + case TDA8290 | TDA8275A: + name = "tda8290+75a"; + break; + case TDA8295 | TDA8275A: + name = "tda8295+75a"; + break; + case TDA8290 | TDA18271: + name = "tda8290+18271"; + break; + case TDA8295 | TDA18271: + name = "tda8295+18271"; + break; + default: + goto fail; + } + tuner_info("type set to %s\n", name); + + fe->ops.analog_ops.info.name = name; + + if (priv->ver & TDA8290) { + if (priv->ver & (TDA8275 | TDA8275A)) + tda8290_init_tuner(fe); + tda8290_init_if(fe); + } else if (priv->ver & TDA8295) + tda8295_init_if(fe); + + return fe; + +fail: + memset(&fe->ops.analog_ops, 0, sizeof(struct analog_demod_ops)); + + tda829x_release(fe); + return NULL; +} +EXPORT_SYMBOL_GPL(tda829x_attach); + +int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) +{ + struct tuner_i2c_props i2c_props = { + .adap = i2c_adap, + .addr = i2c_addr, + }; + + unsigned char soft_reset[] = { 0x00, 0x00 }; + unsigned char easy_mode_b[] = { 0x01, 0x02 }; + unsigned char easy_mode_g[] = { 0x01, 0x04 }; + unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 }; + unsigned char addr_dto_lsb = 0x07; + unsigned char data; +#define PROBE_BUFFER_SIZE 8 + unsigned char buf[PROBE_BUFFER_SIZE]; + int i; + + /* rule out tda9887, which would return the same byte repeatedly */ + tuner_i2c_xfer_send_recv(&i2c_props, + soft_reset, 1, buf, PROBE_BUFFER_SIZE); + for (i = 1; i < PROBE_BUFFER_SIZE; i++) { + if (buf[i] != buf[0]) + break; + } + + /* all bytes are equal, not a tda829x - probably a tda9887 */ + if (i == PROBE_BUFFER_SIZE) + return -ENODEV; + + if ((tda8290_probe(&i2c_props) == 0) || + (tda8295_probe(&i2c_props) == 0)) + return 0; + + /* fall back to old probing method */ + tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2); + tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); + tuner_i2c_xfer_send_recv(&i2c_props, &addr_dto_lsb, 1, &data, 1); + if (data == 0) { + tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2); + tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); + tuner_i2c_xfer_send_recv(&i2c_props, + &addr_dto_lsb, 1, &data, 1); + if (data == 0x7b) { + return 0; + } + } + tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); + return -ENODEV; +} +EXPORT_SYMBOL_GPL(tda829x_probe); + +MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver"); +MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/tuners/tda8290.h b/drivers/media/tuners/tda8290.h new file mode 100644 index 000000000000..7e288b26fcc3 --- /dev/null +++ b/drivers/media/tuners/tda8290.h @@ -0,0 +1,56 @@ +/* + 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 __TDA8290_H__ +#define __TDA8290_H__ + +#include +#include "dvb_frontend.h" + +struct tda829x_config { + unsigned int lna_cfg; + + unsigned int probe_tuner:1; +#define TDA829X_PROBE_TUNER 0 +#define TDA829X_DONT_PROBE 1 +}; + +#if defined(CONFIG_MEDIA_TUNER_TDA8290) || (defined(CONFIG_MEDIA_TUNER_TDA8290_MODULE) && defined(MODULE)) +extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr); + +extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + struct tda829x_config *cfg); +#else +static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -EINVAL; +} + +static inline struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + struct tda829x_config *cfg) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __func__); + return NULL; +} +#endif + +#endif /* __TDA8290_H__ */ diff --git a/drivers/media/tuners/tda9887.c b/drivers/media/tuners/tda9887.c new file mode 100644 index 000000000000..cdb645d57438 --- /dev/null +++ b/drivers/media/tuners/tda9887.c @@ -0,0 +1,717 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tuner-i2c.h" +#include "tda9887.h" + + +/* Chips: + TDA9885 (PAL, NTSC) + TDA9886 (PAL, SECAM, NTSC) + TDA9887 (PAL, SECAM, NTSC, FM Radio) + + Used as part of several tuners +*/ + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +static DEFINE_MUTEX(tda9887_list_mutex); +static LIST_HEAD(hybrid_tuner_instance_list); + +struct tda9887_priv { + struct tuner_i2c_props i2c_props; + struct list_head hybrid_tuner_instance_list; + + unsigned char data[4]; + unsigned int config; + unsigned int mode; + unsigned int audmode; + v4l2_std_id std; + + bool standby; +}; + +/* ---------------------------------------------------------------------- */ + +#define UNSET (-1U) + +struct tvnorm { + v4l2_std_id std; + char *name; + unsigned char b; + unsigned char c; + unsigned char e; +}; + +/* ---------------------------------------------------------------------- */ + +// +// TDA defines +// + +//// first reg (b) +#define cVideoTrapBypassOFF 0x00 // bit b0 +#define cVideoTrapBypassON 0x01 // bit b0 + +#define cAutoMuteFmInactive 0x00 // bit b1 +#define cAutoMuteFmActive 0x02 // bit b1 + +#define cIntercarrier 0x00 // bit b2 +#define cQSS 0x04 // bit b2 + +#define cPositiveAmTV 0x00 // bit b3:4 +#define cFmRadio 0x08 // bit b3:4 +#define cNegativeFmTV 0x10 // bit b3:4 + + +#define cForcedMuteAudioON 0x20 // bit b5 +#define cForcedMuteAudioOFF 0x00 // bit b5 + +#define cOutputPort1Active 0x00 // bit b6 +#define cOutputPort1Inactive 0x40 // bit b6 + +#define cOutputPort2Active 0x00 // bit b7 +#define cOutputPort2Inactive 0x80 // bit b7 + + +//// second reg (c) +#define cDeemphasisOFF 0x00 // bit c5 +#define cDeemphasisON 0x20 // bit c5 + +#define cDeemphasis75 0x00 // bit c6 +#define cDeemphasis50 0x40 // bit c6 + +#define cAudioGain0 0x00 // bit c7 +#define cAudioGain6 0x80 // bit c7 + +#define cTopMask 0x1f // bit c0:4 +#define cTopDefault 0x10 // bit c0:4 + +//// third reg (e) +#define cAudioIF_4_5 0x00 // bit e0:1 +#define cAudioIF_5_5 0x01 // bit e0:1 +#define cAudioIF_6_0 0x02 // bit e0:1 +#define cAudioIF_6_5 0x03 // bit e0:1 + + +#define cVideoIFMask 0x1c // bit e2:4 +/* Video IF selection in TV Mode (bit B3=0) */ +#define cVideoIF_58_75 0x00 // bit e2:4 +#define cVideoIF_45_75 0x04 // bit e2:4 +#define cVideoIF_38_90 0x08 // bit e2:4 +#define cVideoIF_38_00 0x0C // bit e2:4 +#define cVideoIF_33_90 0x10 // bit e2:4 +#define cVideoIF_33_40 0x14 // bit e2:4 +#define cRadioIF_45_75 0x18 // bit e2:4 +#define cRadioIF_38_90 0x1C // bit e2:4 + +/* IF1 selection in Radio Mode (bit B3=1) */ +#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14) +#define cRadioIF_41_30 0x04 // bit e2,4 + +/* Output of AFC pin in radio mode when bit E7=1 */ +#define cRadioAGC_SIF 0x00 // bit e3 +#define cRadioAGC_FM 0x08 // bit e3 + +#define cTunerGainNormal 0x00 // bit e5 +#define cTunerGainLow 0x20 // bit e5 + +#define cGating_18 0x00 // bit e6 +#define cGating_36 0x40 // bit e6 + +#define cAgcOutON 0x80 // bit e7 +#define cAgcOutOFF 0x00 // bit e7 + +/* ---------------------------------------------------------------------- */ + +static struct tvnorm tvnorms[] = { + { + .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N, + .name = "PAL-BGHN", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis50 | + cTopDefault), + .e = ( cGating_36 | + cAudioIF_5_5 | + cVideoIF_38_90 ), + },{ + .std = V4L2_STD_PAL_I, + .name = "PAL-I", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis50 | + cTopDefault), + .e = ( cGating_36 | + cAudioIF_6_0 | + cVideoIF_38_90 ), + },{ + .std = V4L2_STD_PAL_DK, + .name = "PAL-DK", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis50 | + cTopDefault), + .e = ( cGating_36 | + cAudioIF_6_5 | + cVideoIF_38_90 ), + },{ + .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc, + .name = "PAL-M/Nc", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis75 | + cTopDefault), + .e = ( cGating_36 | + cAudioIF_4_5 | + cVideoIF_45_75 ), + },{ + .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, + .name = "SECAM-BGH", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cTopDefault), + .e = ( cAudioIF_5_5 | + cVideoIF_38_90 ), + },{ + .std = V4L2_STD_SECAM_L, + .name = "SECAM-L", + .b = ( cPositiveAmTV | + cQSS ), + .c = ( cTopDefault), + .e = ( cGating_36 | + cAudioIF_6_5 | + cVideoIF_38_90 ), + },{ + .std = V4L2_STD_SECAM_LC, + .name = "SECAM-L'", + .b = ( cOutputPort2Inactive | + cPositiveAmTV | + cQSS ), + .c = ( cTopDefault), + .e = ( cGating_36 | + cAudioIF_6_5 | + cVideoIF_33_90 ), + },{ + .std = V4L2_STD_SECAM_DK, + .name = "SECAM-DK", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis50 | + cTopDefault), + .e = ( cGating_36 | + cAudioIF_6_5 | + cVideoIF_38_90 ), + },{ + .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR, + .name = "NTSC-M", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis75 | + cTopDefault), + .e = ( cGating_36 | + cAudioIF_4_5 | + cVideoIF_45_75 ), + },{ + .std = V4L2_STD_NTSC_M_JP, + .name = "NTSC-M-JP", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis50 | + cTopDefault), + .e = ( cGating_36 | + cAudioIF_4_5 | + cVideoIF_58_75 ), + } +}; + +static struct tvnorm radio_stereo = { + .name = "Radio Stereo", + .b = ( cFmRadio | + cQSS ), + .c = ( cDeemphasisOFF | + cAudioGain6 | + cTopDefault), + .e = ( cTunerGainLow | + cAudioIF_5_5 | + cRadioIF_38_90 ), +}; + +static struct tvnorm radio_mono = { + .name = "Radio Mono", + .b = ( cFmRadio | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis75 | + cTopDefault), + .e = ( cTunerGainLow | + cAudioIF_5_5 | + cRadioIF_38_90 ), +}; + +/* ---------------------------------------------------------------------- */ + +static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + + static char *afc[16] = { + "- 12.5 kHz", + "- 37.5 kHz", + "- 62.5 kHz", + "- 87.5 kHz", + "-112.5 kHz", + "-137.5 kHz", + "-162.5 kHz", + "-187.5 kHz [min]", + "+187.5 kHz [max]", + "+162.5 kHz", + "+137.5 kHz", + "+112.5 kHz", + "+ 87.5 kHz", + "+ 62.5 kHz", + "+ 37.5 kHz", + "+ 12.5 kHz", + }; + tuner_info("read: 0x%2x\n", buf[0]); + tuner_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no"); + tuner_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]); + tuner_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low"); + tuner_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out"); + tuner_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); +} + +static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + + static char *sound[4] = { + "AM/TV", + "FM/radio", + "FM/TV", + "FM/radio" + }; + static char *adjust[32] = { + "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9", + "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1", + "0", "+1", "+2", "+3", "+4", "+5", "+6", "+7", + "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15" + }; + static char *deemph[4] = { + "no", "no", "75", "50" + }; + static char *carrier[4] = { + "4.5 MHz", + "5.5 MHz", + "6.0 MHz", + "6.5 MHz / AM" + }; + static char *vif[8] = { + "58.75 MHz", + "45.75 MHz", + "38.9 MHz", + "38.0 MHz", + "33.9 MHz", + "33.4 MHz", + "45.75 MHz + pin13", + "38.9 MHz + pin13", + }; + static char *rif[4] = { + "44 MHz", + "52 MHz", + "52 MHz", + "44 MHz", + }; + + tuner_info("write: byte B 0x%02x\n", buf[1]); + tuner_info(" B0 video mode : %s\n", + (buf[1] & 0x01) ? "video trap" : "sound trap"); + tuner_info(" B1 auto mute fm : %s\n", + (buf[1] & 0x02) ? "yes" : "no"); + tuner_info(" B2 carrier mode : %s\n", + (buf[1] & 0x04) ? "QSS" : "Intercarrier"); + tuner_info(" B3-4 tv sound/radio : %s\n", + sound[(buf[1] & 0x18) >> 3]); + tuner_info(" B5 force mute audio: %s\n", + (buf[1] & 0x20) ? "yes" : "no"); + tuner_info(" B6 output port 1 : %s\n", + (buf[1] & 0x40) ? "high (inactive)" : "low (active)"); + tuner_info(" B7 output port 2 : %s\n", + (buf[1] & 0x80) ? "high (inactive)" : "low (active)"); + + tuner_info("write: byte C 0x%02x\n", buf[2]); + tuner_info(" C0-4 top adjustment : %s dB\n", + adjust[buf[2] & 0x1f]); + tuner_info(" C5-6 de-emphasis : %s\n", + deemph[(buf[2] & 0x60) >> 5]); + tuner_info(" C7 audio gain : %s\n", + (buf[2] & 0x80) ? "-6" : "0"); + + tuner_info("write: byte E 0x%02x\n", buf[3]); + tuner_info(" E0-1 sound carrier : %s\n", + carrier[(buf[3] & 0x03)]); + tuner_info(" E6 l pll gating : %s\n", + (buf[3] & 0x40) ? "36" : "13"); + + if (buf[1] & 0x08) { + /* radio */ + tuner_info(" E2-4 video if : %s\n", + rif[(buf[3] & 0x0c) >> 2]); + tuner_info(" E7 vif agc output : %s\n", + (buf[3] & 0x80) + ? ((buf[3] & 0x10) ? "fm-agc radio" : + "sif-agc radio") + : "fm radio carrier afc"); + } else { + /* video */ + tuner_info(" E2-4 video if : %s\n", + vif[(buf[3] & 0x1c) >> 2]); + tuner_info(" E5 tuner gain : %s\n", + (buf[3] & 0x80) + ? ((buf[3] & 0x20) ? "external" : "normal") + : ((buf[3] & 0x20) ? "minimum" : "normal")); + tuner_info(" E7 vif agc output : %s\n", + (buf[3] & 0x80) ? ((buf[3] & 0x20) + ? "pin3 port, pin22 vif agc out" + : "pin22 port, pin3 vif acg ext in") + : "pin3+pin22 port"); + } + tuner_info("--\n"); +} + +/* ---------------------------------------------------------------------- */ + +static int tda9887_set_tvnorm(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + struct tvnorm *norm = NULL; + char *buf = priv->data; + int i; + + if (priv->mode == V4L2_TUNER_RADIO) { + if (priv->audmode == V4L2_TUNER_MODE_MONO) + norm = &radio_mono; + else + norm = &radio_stereo; + } else { + for (i = 0; i < ARRAY_SIZE(tvnorms); i++) { + if (tvnorms[i].std & priv->std) { + norm = tvnorms+i; + break; + } + } + } + if (NULL == norm) { + tuner_dbg("Unsupported tvnorm entry - audio muted\n"); + return -1; + } + + tuner_dbg("configure for: %s\n", norm->name); + buf[1] = norm->b; + buf[2] = norm->c; + buf[3] = norm->e; + return 0; +} + +static unsigned int port1 = UNSET; +static unsigned int port2 = UNSET; +static unsigned int qss = UNSET; +static unsigned int adjust = UNSET; + +module_param(port1, int, 0644); +module_param(port2, int, 0644); +module_param(qss, int, 0644); +module_param(adjust, int, 0644); + +static int tda9887_set_insmod(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + char *buf = priv->data; + + if (UNSET != port1) { + if (port1) + buf[1] |= cOutputPort1Inactive; + else + buf[1] &= ~cOutputPort1Inactive; + } + if (UNSET != port2) { + if (port2) + buf[1] |= cOutputPort2Inactive; + else + buf[1] &= ~cOutputPort2Inactive; + } + + if (UNSET != qss) { + if (qss) + buf[1] |= cQSS; + else + buf[1] &= ~cQSS; + } + + if (adjust < 0x20) { + buf[2] &= ~cTopMask; + buf[2] |= adjust; + } + return 0; +} + +static int tda9887_do_config(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + char *buf = priv->data; + + if (priv->config & TDA9887_PORT1_ACTIVE) + buf[1] &= ~cOutputPort1Inactive; + if (priv->config & TDA9887_PORT1_INACTIVE) + buf[1] |= cOutputPort1Inactive; + if (priv->config & TDA9887_PORT2_ACTIVE) + buf[1] &= ~cOutputPort2Inactive; + if (priv->config & TDA9887_PORT2_INACTIVE) + buf[1] |= cOutputPort2Inactive; + + if (priv->config & TDA9887_QSS) + buf[1] |= cQSS; + if (priv->config & TDA9887_INTERCARRIER) + buf[1] &= ~cQSS; + + if (priv->config & TDA9887_AUTOMUTE) + buf[1] |= cAutoMuteFmActive; + if (priv->config & TDA9887_DEEMPHASIS_MASK) { + buf[2] &= ~0x60; + switch (priv->config & TDA9887_DEEMPHASIS_MASK) { + case TDA9887_DEEMPHASIS_NONE: + buf[2] |= cDeemphasisOFF; + break; + case TDA9887_DEEMPHASIS_50: + buf[2] |= cDeemphasisON | cDeemphasis50; + break; + case TDA9887_DEEMPHASIS_75: + buf[2] |= cDeemphasisON | cDeemphasis75; + break; + } + } + if (priv->config & TDA9887_TOP_SET) { + buf[2] &= ~cTopMask; + buf[2] |= (priv->config >> 8) & cTopMask; + } + if ((priv->config & TDA9887_INTERCARRIER_NTSC) && + (priv->std & V4L2_STD_NTSC)) + buf[1] &= ~cQSS; + if (priv->config & TDA9887_GATING_18) + buf[3] &= ~cGating_36; + + if (priv->mode == V4L2_TUNER_RADIO) { + if (priv->config & TDA9887_RIF_41_3) { + buf[3] &= ~cVideoIFMask; + buf[3] |= cRadioIF_41_30; + } + if (priv->config & TDA9887_GAIN_NORMAL) + buf[3] &= ~cTunerGainLow; + } + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int tda9887_status(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + unsigned char buf[1]; + int rc; + + memset(buf,0,sizeof(buf)); + if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1))) + tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc); + dump_read_message(fe, buf); + return 0; +} + +static void tda9887_configure(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + int rc; + + memset(priv->data,0,sizeof(priv->data)); + tda9887_set_tvnorm(fe); + + /* A note on the port settings: + These settings tend to depend on the specifics of the board. + By default they are set to inactive (bit value 1) by this driver, + overwriting any changes made by the tvnorm. This means that it + is the responsibility of the module using the tda9887 to set + these values in case of changes in the tvnorm. + In many cases port 2 should be made active (0) when selecting + SECAM-L, and port 2 should remain inactive (1) for SECAM-L'. + + For the other standards the tda9887 application note says that + the ports should be set to active (0), but, again, that may + differ depending on the precise hardware configuration. + */ + priv->data[1] |= cOutputPort1Inactive; + priv->data[1] |= cOutputPort2Inactive; + + tda9887_do_config(fe); + tda9887_set_insmod(fe); + + if (priv->standby) + priv->data[1] |= cForcedMuteAudioON; + + tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", + priv->data[1], priv->data[2], priv->data[3]); + if (debug > 1) + dump_write_message(fe, priv->data); + + if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4))) + tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc); + + if (debug > 2) { + msleep_interruptible(1000); + tda9887_status(fe); + } +} + +/* ---------------------------------------------------------------------- */ + +static void tda9887_tuner_status(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", + priv->data[1], priv->data[2], priv->data[3]); +} + +static int tda9887_get_afc(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + static int AFC_BITS_2_kHz[] = { + -12500, -37500, -62500, -97500, + -112500, -137500, -162500, -187500, + 187500, 162500, 137500, 112500, + 97500 , 62500, 37500 , 12500 + }; + int afc=0; + __u8 reg = 0; + + if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,®,1)) + afc = AFC_BITS_2_kHz[(reg>>1)&0x0f]; + + return afc; +} + +static void tda9887_standby(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + + priv->standby = true; + + tda9887_configure(fe); +} + +static void tda9887_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + + priv->standby = false; + priv->mode = params->mode; + priv->audmode = params->audmode; + priv->std = params->std; + tda9887_configure(fe); +} + +static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + + priv->config = *(unsigned int *)priv_cfg; + tda9887_configure(fe); + + return 0; +} + +static void tda9887_release(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + + mutex_lock(&tda9887_list_mutex); + + if (priv) + hybrid_tuner_release_state(priv); + + mutex_unlock(&tda9887_list_mutex); + + fe->analog_demod_priv = NULL; +} + +static struct analog_demod_ops tda9887_ops = { + .info = { + .name = "tda9887", + }, + .set_params = tda9887_set_params, + .standby = tda9887_standby, + .tuner_status = tda9887_tuner_status, + .get_afc = tda9887_get_afc, + .release = tda9887_release, + .set_config = tda9887_set_config, +}; + +struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr) +{ + struct tda9887_priv *priv = NULL; + int instance; + + mutex_lock(&tda9887_list_mutex); + + instance = hybrid_tuner_request_state(struct tda9887_priv, priv, + hybrid_tuner_instance_list, + i2c_adap, i2c_addr, "tda9887"); + switch (instance) { + case 0: + mutex_unlock(&tda9887_list_mutex); + return NULL; + case 1: + fe->analog_demod_priv = priv; + priv->standby = true; + tuner_info("tda988[5/6/7] found\n"); + break; + default: + fe->analog_demod_priv = priv; + break; + } + + mutex_unlock(&tda9887_list_mutex); + + memcpy(&fe->ops.analog_ops, &tda9887_ops, + sizeof(struct analog_demod_ops)); + + return fe; +} +EXPORT_SYMBOL_GPL(tda9887_attach); + +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/tuners/tda9887.h b/drivers/media/tuners/tda9887.h new file mode 100644 index 000000000000..acc419e8c4fc --- /dev/null +++ b/drivers/media/tuners/tda9887.h @@ -0,0 +1,38 @@ +/* + 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 __TDA9887_H__ +#define __TDA9887_H__ + +#include +#include "dvb_frontend.h" + +/* ------------------------------------------------------------------------ */ +#if defined(CONFIG_MEDIA_TUNER_TDA9887) || (defined(CONFIG_MEDIA_TUNER_TDA9887_MODULE) && defined(MODULE)) +extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr); +#else +static inline struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __TDA9887_H__ */ diff --git a/drivers/media/tuners/tea5761.c b/drivers/media/tuners/tea5761.c new file mode 100644 index 000000000000..bf78cb9fc52c --- /dev/null +++ b/drivers/media/tuners/tea5761.c @@ -0,0 +1,348 @@ +/* + * For Philips TEA5761 FM Chip + * I2C address is allways 0x20 (0x10 at 7-bit mode). + * + * Copyright (c) 2005-2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNUv2 General Public License + * + */ + +#include +#include +#include +#include +#include +#include "tuner-i2c.h" +#include "tea5761.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +struct tea5761_priv { + struct tuner_i2c_props i2c_props; + + u32 frequency; + bool standby; +}; + +/*****************************************************************************/ + +/*************************** + * TEA5761HN I2C registers * + ***************************/ + +/* INTREG - Read: bytes 0 and 1 / Write: byte 0 */ + + /* first byte for reading */ +#define TEA5761_INTREG_IFFLAG 0x10 +#define TEA5761_INTREG_LEVFLAG 0x8 +#define TEA5761_INTREG_FRRFLAG 0x2 +#define TEA5761_INTREG_BLFLAG 0x1 + + /* second byte for reading / byte for writing */ +#define TEA5761_INTREG_IFMSK 0x10 +#define TEA5761_INTREG_LEVMSK 0x8 +#define TEA5761_INTREG_FRMSK 0x2 +#define TEA5761_INTREG_BLMSK 0x1 + +/* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */ + + /* First byte */ +#define TEA5761_FRQSET_SEARCH_UP 0x80 /* 1=Station search from botton to up */ +#define TEA5761_FRQSET_SEARCH_MODE 0x40 /* 1=Search mode */ + + /* Bits 0-5 for divider MSB */ + + /* Second byte */ + /* Bits 0-7 for divider LSB */ + +/* TNCTRL - Read: bytes 4 and 5 / Write: Bytes 3 and 4 */ + + /* first byte */ + +#define TEA5761_TNCTRL_PUPD_0 0x40 /* Power UP/Power Down MSB */ +#define TEA5761_TNCTRL_BLIM 0X20 /* 1= Japan Frequencies, 0= European frequencies */ +#define TEA5761_TNCTRL_SWPM 0x10 /* 1= software port is FRRFLAG */ +#define TEA5761_TNCTRL_IFCTC 0x08 /* 1= IF count time 15.02 ms, 0= IF count time 2.02 ms */ +#define TEA5761_TNCTRL_AFM 0x04 +#define TEA5761_TNCTRL_SMUTE 0x02 /* 1= Soft mute */ +#define TEA5761_TNCTRL_SNC 0x01 + + /* second byte */ + +#define TEA5761_TNCTRL_MU 0x80 /* 1=Hard mute */ +#define TEA5761_TNCTRL_SSL_1 0x40 +#define TEA5761_TNCTRL_SSL_0 0x20 +#define TEA5761_TNCTRL_HLSI 0x10 +#define TEA5761_TNCTRL_MST 0x08 /* 1 = mono */ +#define TEA5761_TNCTRL_SWP 0x04 +#define TEA5761_TNCTRL_DTC 0x02 /* 1 = deemphasis 50 us, 0 = deemphasis 75 us */ +#define TEA5761_TNCTRL_AHLSI 0x01 + +/* FRQCHECK - Read: bytes 6 and 7 */ + /* First byte */ + + /* Bits 0-5 for divider MSB */ + + /* Second byte */ + /* Bits 0-7 for divider LSB */ + +/* TUNCHECK - Read: bytes 8 and 9 */ + + /* First byte */ +#define TEA5761_TUNCHECK_IF_MASK 0x7e /* IF count */ +#define TEA5761_TUNCHECK_TUNTO 0x01 + + /* Second byte */ +#define TEA5761_TUNCHECK_LEV_MASK 0xf0 /* Level Count */ +#define TEA5761_TUNCHECK_LD 0x08 +#define TEA5761_TUNCHECK_STEREO 0x04 + +/* TESTREG - Read: bytes 10 and 11 / Write: bytes 5 and 6 */ + + /* All zero = no test mode */ + +/* MANID - Read: bytes 12 and 13 */ + + /* First byte - should be 0x10 */ +#define TEA5767_MANID_VERSION_MASK 0xf0 /* Version = 1 */ +#define TEA5767_MANID_ID_MSB_MASK 0x0f /* Manufacurer ID - should be 0 */ + + /* Second byte - Should be 0x2b */ + +#define TEA5767_MANID_ID_LSB_MASK 0xfe /* Manufacturer ID - should be 0x15 */ +#define TEA5767_MANID_IDAV 0x01 /* 1 = Chip has ID, 0 = Chip has no ID */ + +/* Chip ID - Read: bytes 14 and 15 */ + + /* First byte - should be 0x57 */ + + /* Second byte - should be 0x61 */ + +/*****************************************************************************/ + +#define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */ +static void tea5761_status_dump(unsigned char *buffer) +{ + unsigned int div, frq; + + div = ((buffer[2] & 0x3f) << 8) | buffer[3]; + + frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4; /* Freq in KHz */ + + printk(KERN_INFO "tea5761: Frequency %d.%03d KHz (divider = 0x%04x)\n", + frq / 1000, frq % 1000, div); +} + +/* Freq should be specifyed at 62.5 Hz */ +static int __set_radio_freq(struct dvb_frontend *fe, + unsigned int freq, + bool mono) +{ + struct tea5761_priv *priv = fe->tuner_priv; + unsigned int frq = freq; + unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 }; + unsigned div; + int rc; + + tuner_dbg("radio freq counter %d\n", frq); + + if (priv->standby) { + tuner_dbg("TEA5761 set to standby mode\n"); + buffer[5] |= TEA5761_TNCTRL_MU; + } else { + buffer[4] |= TEA5761_TNCTRL_PUPD_0; + } + + + if (mono) { + tuner_dbg("TEA5761 set to mono\n"); + buffer[5] |= TEA5761_TNCTRL_MST; + } else { + tuner_dbg("TEA5761 set to stereo\n"); + } + + div = (1000 * (frq * 4 / 16 + 700 + 225) ) >> 15; + buffer[1] = (div >> 8) & 0x3f; + buffer[2] = div & 0xff; + + if (debug) + tea5761_status_dump(buffer); + + if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + + priv->frequency = frq * 125 / 2; + + return 0; +} + +static int set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tea5761_priv *priv = fe->analog_demod_priv; + + priv->standby = false; + + return __set_radio_freq(fe, params->frequency, + params->audmode == V4L2_TUNER_MODE_MONO); +} + +static int set_radio_sleep(struct dvb_frontend *fe) +{ + struct tea5761_priv *priv = fe->analog_demod_priv; + + priv->standby = true; + + return __set_radio_freq(fe, priv->frequency, false); +} + +static int tea5761_read_status(struct dvb_frontend *fe, char *buffer) +{ + struct tea5761_priv *priv = fe->tuner_priv; + int rc; + + memset(buffer, 0, 16); + if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) { + tuner_warn("i2c i/o error: rc == %d (should be 16)\n", rc); + return -EREMOTEIO; + } + + return 0; +} + +static inline int tea5761_signal(struct dvb_frontend *fe, const char *buffer) +{ + struct tea5761_priv *priv = fe->tuner_priv; + + int signal = ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); + + tuner_dbg("Signal strength: %d\n", signal); + + return signal; +} + +static inline int tea5761_stereo(struct dvb_frontend *fe, const char *buffer) +{ + struct tea5761_priv *priv = fe->tuner_priv; + + int stereo = buffer[9] & TEA5761_TUNCHECK_STEREO; + + tuner_dbg("Radio ST GET = %02x\n", stereo); + + return (stereo ? V4L2_TUNER_SUB_STEREO : 0); +} + +static int tea5761_get_status(struct dvb_frontend *fe, u32 *status) +{ + unsigned char buffer[16]; + + *status = 0; + + if (0 == tea5761_read_status(fe, buffer)) { + if (tea5761_signal(fe, buffer)) + *status = TUNER_STATUS_LOCKED; + if (tea5761_stereo(fe, buffer)) + *status |= TUNER_STATUS_STEREO; + } + + return 0; +} + +static int tea5761_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + unsigned char buffer[16]; + + *strength = 0; + + if (0 == tea5761_read_status(fe, buffer)) + *strength = tea5761_signal(fe, buffer); + + return 0; +} + +int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) +{ + unsigned char buffer[16]; + int rc; + struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; + + if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) { + printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc); + return -EINVAL; + } + + if ((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061)) { + printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x." + " It is not a TEA5761\n", + buffer[13], buffer[14], buffer[15]); + return -EINVAL; + } + printk(KERN_WARNING "tea5761: TEA%02x%02x detected. " + "Manufacturer ID= 0x%02x\n", + buffer[14], buffer[15], buffer[13]); + + return 0; +} + +static int tea5761_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; +} + +static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tea5761_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static struct dvb_tuner_ops tea5761_tuner_ops = { + .info = { + .name = "tea5761", // Philips TEA5761HN FM Radio + }, + .set_analog_params = set_radio_freq, + .sleep = set_radio_sleep, + .release = tea5761_release, + .get_frequency = tea5761_get_frequency, + .get_status = tea5761_get_status, + .get_rf_strength = tea5761_get_rf_strength, +}; + +struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + struct tea5761_priv *priv = NULL; + + if (tea5761_autodetection(i2c_adap, i2c_addr) != 0) + return NULL; + + priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + fe->tuner_priv = priv; + + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + priv->i2c_props.name = "tea5761"; + + memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + tuner_info("type set to %s\n", "Philips TEA5761HN FM Radio"); + + return fe; +} + + +EXPORT_SYMBOL_GPL(tea5761_attach); +EXPORT_SYMBOL_GPL(tea5761_autodetection); + +MODULE_DESCRIPTION("Philips TEA5761 FM tuner driver"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/tea5761.h b/drivers/media/tuners/tea5761.h new file mode 100644 index 000000000000..2e2ff82c95a4 --- /dev/null +++ b/drivers/media/tuners/tea5761.h @@ -0,0 +1,47 @@ +/* + 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 __TEA5761_H__ +#define __TEA5761_H__ + +#include +#include "dvb_frontend.h" + +#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE)) +extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); + +extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr); +#else +static inline int tea5761_autodetection(struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __func__); + return -EINVAL; +} + +static inline struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __TEA5761_H__ */ diff --git a/drivers/media/tuners/tea5767.c b/drivers/media/tuners/tea5767.c new file mode 100644 index 000000000000..36e85d81acb2 --- /dev/null +++ b/drivers/media/tuners/tea5767.c @@ -0,0 +1,475 @@ +/* + * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview + * I2C address is allways 0xC0. + * + * + * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License + * + * tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa + * from their contributions on DScaler. + */ + +#include +#include +#include +#include +#include "tuner-i2c.h" +#include "tea5767.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +/*****************************************************************************/ + +struct tea5767_priv { + struct tuner_i2c_props i2c_props; + u32 frequency; + struct tea5767_ctrl ctrl; +}; + +/*****************************************************************************/ + +/****************************** + * Write mode register values * + ******************************/ + +/* First register */ +#define TEA5767_MUTE 0x80 /* Mutes output */ +#define TEA5767_SEARCH 0x40 /* Activates station search */ +/* Bits 0-5 for divider MSB */ + +/* Second register */ +/* Bits 0-7 for divider LSB */ + +/* Third register */ + +/* Station search from botton to up */ +#define TEA5767_SEARCH_UP 0x80 + +/* Searches with ADC output = 10 */ +#define TEA5767_SRCH_HIGH_LVL 0x60 + +/* Searches with ADC output = 10 */ +#define TEA5767_SRCH_MID_LVL 0x40 + +/* Searches with ADC output = 5 */ +#define TEA5767_SRCH_LOW_LVL 0x20 + +/* if on, div=4*(Frf+Fif)/Fref otherwise, div=4*(Frf-Fif)/Freq) */ +#define TEA5767_HIGH_LO_INJECT 0x10 + +/* Disable stereo */ +#define TEA5767_MONO 0x08 + +/* Disable right channel and turns to mono */ +#define TEA5767_MUTE_RIGHT 0x04 + +/* Disable left channel and turns to mono */ +#define TEA5767_MUTE_LEFT 0x02 + +#define TEA5767_PORT1_HIGH 0x01 + +/* Fourth register */ +#define TEA5767_PORT2_HIGH 0x80 +/* Chips stops working. Only I2C bus remains on */ +#define TEA5767_STDBY 0x40 + +/* Japan freq (76-108 MHz. If disabled, 87.5-108 MHz */ +#define TEA5767_JAPAN_BAND 0x20 + +/* Unselected means 32.768 KHz freq as reference. Otherwise Xtal at 13 MHz */ +#define TEA5767_XTAL_32768 0x10 + +/* Cuts weak signals */ +#define TEA5767_SOFT_MUTE 0x08 + +/* Activates high cut control */ +#define TEA5767_HIGH_CUT_CTRL 0x04 + +/* Activates stereo noise control */ +#define TEA5767_ST_NOISE_CTL 0x02 + +/* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */ +#define TEA5767_SRCH_IND 0x01 + +/* Fifth register */ + +/* By activating, it will use Xtal at 13 MHz as reference for divider */ +#define TEA5767_PLLREF_ENABLE 0x80 + +/* By activating, deemphasis=50, or else, deemphasis of 50us */ +#define TEA5767_DEEMPH_75 0X40 + +/***************************** + * Read mode register values * + *****************************/ + +/* First register */ +#define TEA5767_READY_FLAG_MASK 0x80 +#define TEA5767_BAND_LIMIT_MASK 0X40 +/* Bits 0-5 for divider MSB after search or preset */ + +/* Second register */ +/* Bits 0-7 for divider LSB after search or preset */ + +/* Third register */ +#define TEA5767_STEREO_MASK 0x80 +#define TEA5767_IF_CNTR_MASK 0x7f + +/* Fourth register */ +#define TEA5767_ADC_LEVEL_MASK 0xf0 + +/* should be 0 */ +#define TEA5767_CHIP_ID_MASK 0x0f + +/* Fifth register */ +/* Reserved for future extensions */ +#define TEA5767_RESERVED_MASK 0xff + +/*****************************************************************************/ + +static void tea5767_status_dump(struct tea5767_priv *priv, + unsigned char *buffer) +{ + unsigned int div, frq; + + if (TEA5767_READY_FLAG_MASK & buffer[0]) + tuner_info("Ready Flag ON\n"); + else + tuner_info("Ready Flag OFF\n"); + + if (TEA5767_BAND_LIMIT_MASK & buffer[0]) + tuner_info("Tuner at band limit\n"); + else + tuner_info("Tuner not at band limit\n"); + + div = ((buffer[0] & 0x3f) << 8) | buffer[1]; + + switch (priv->ctrl.xtal_freq) { + case TEA5767_HIGH_LO_13MHz: + frq = (div * 50000 - 700000 - 225000) / 4; /* Freq in KHz */ + break; + case TEA5767_LOW_LO_13MHz: + frq = (div * 50000 + 700000 + 225000) / 4; /* Freq in KHz */ + break; + case TEA5767_LOW_LO_32768: + frq = (div * 32768 + 700000 + 225000) / 4; /* Freq in KHz */ + break; + case TEA5767_HIGH_LO_32768: + default: + frq = (div * 32768 - 700000 - 225000) / 4; /* Freq in KHz */ + break; + } + buffer[0] = (div >> 8) & 0x3f; + buffer[1] = div & 0xff; + + tuner_info("Frequency %d.%03d KHz (divider = 0x%04x)\n", + frq / 1000, frq % 1000, div); + + if (TEA5767_STEREO_MASK & buffer[2]) + tuner_info("Stereo\n"); + else + tuner_info("Mono\n"); + + tuner_info("IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK); + + tuner_info("ADC Level = %d\n", + (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4); + + tuner_info("Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK)); + + tuner_info("Reserved = 0x%02x\n", + (buffer[4] & TEA5767_RESERVED_MASK)); +} + +/* Freq should be specifyed at 62.5 Hz */ +static int set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tea5767_priv *priv = fe->tuner_priv; + unsigned int frq = params->frequency; + unsigned char buffer[5]; + unsigned div; + int rc; + + tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000); + + buffer[2] = 0; + + if (priv->ctrl.port1) + buffer[2] |= TEA5767_PORT1_HIGH; + + if (params->audmode == V4L2_TUNER_MODE_MONO) { + tuner_dbg("TEA5767 set to mono\n"); + buffer[2] |= TEA5767_MONO; + } else { + tuner_dbg("TEA5767 set to stereo\n"); + } + + + buffer[3] = 0; + + if (priv->ctrl.port2) + buffer[3] |= TEA5767_PORT2_HIGH; + + if (priv->ctrl.high_cut) + buffer[3] |= TEA5767_HIGH_CUT_CTRL; + + if (priv->ctrl.st_noise) + buffer[3] |= TEA5767_ST_NOISE_CTL; + + if (priv->ctrl.soft_mute) + buffer[3] |= TEA5767_SOFT_MUTE; + + if (priv->ctrl.japan_band) + buffer[3] |= TEA5767_JAPAN_BAND; + + buffer[4] = 0; + + if (priv->ctrl.deemph_75) + buffer[4] |= TEA5767_DEEMPH_75; + + if (priv->ctrl.pllref) + buffer[4] |= TEA5767_PLLREF_ENABLE; + + + /* Rounds freq to next decimal value - for 62.5 KHz step */ + /* frq = 20*(frq/16)+radio_frq[frq%16]; */ + + switch (priv->ctrl.xtal_freq) { + case TEA5767_HIGH_LO_13MHz: + tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n"); + buffer[2] |= TEA5767_HIGH_LO_INJECT; + div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000; + break; + case TEA5767_LOW_LO_13MHz: + tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n"); + + div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000; + break; + case TEA5767_LOW_LO_32768: + tuner_dbg("radio LOW LO inject xtal @ 32,768 MHz\n"); + buffer[3] |= TEA5767_XTAL_32768; + /* const 700=4000*175 Khz - to adjust freq to right value */ + div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15; + break; + case TEA5767_HIGH_LO_32768: + default: + tuner_dbg("radio HIGH LO inject xtal @ 32,768 MHz\n"); + + buffer[2] |= TEA5767_HIGH_LO_INJECT; + buffer[3] |= TEA5767_XTAL_32768; + div = ((frq * (4000 / 16) + 700000 + 225000) + 16384) >> 15; + break; + } + buffer[0] = (div >> 8) & 0x3f; + buffer[1] = div & 0xff; + + if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + + if (debug) { + if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + else + tea5767_status_dump(priv, buffer); + } + + priv->frequency = frq * 125 / 2; + + return 0; +} + +static int tea5767_read_status(struct dvb_frontend *fe, char *buffer) +{ + struct tea5767_priv *priv = fe->tuner_priv; + int rc; + + memset(buffer, 0, 5); + if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) { + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + return -EREMOTEIO; + } + + return 0; +} + +static inline int tea5767_signal(struct dvb_frontend *fe, const char *buffer) +{ + struct tea5767_priv *priv = fe->tuner_priv; + + int signal = ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); + + tuner_dbg("Signal strength: %d\n", signal); + + return signal; +} + +static inline int tea5767_stereo(struct dvb_frontend *fe, const char *buffer) +{ + struct tea5767_priv *priv = fe->tuner_priv; + + int stereo = buffer[2] & TEA5767_STEREO_MASK; + + tuner_dbg("Radio ST GET = %02x\n", stereo); + + return (stereo ? V4L2_TUNER_SUB_STEREO : 0); +} + +static int tea5767_get_status(struct dvb_frontend *fe, u32 *status) +{ + unsigned char buffer[5]; + + *status = 0; + + if (0 == tea5767_read_status(fe, buffer)) { + if (tea5767_signal(fe, buffer)) + *status = TUNER_STATUS_LOCKED; + if (tea5767_stereo(fe, buffer)) + *status |= TUNER_STATUS_STEREO; + } + + return 0; +} + +static int tea5767_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + unsigned char buffer[5]; + + *strength = 0; + + if (0 == tea5767_read_status(fe, buffer)) + *strength = tea5767_signal(fe, buffer); + + return 0; +} + +static int tea5767_standby(struct dvb_frontend *fe) +{ + unsigned char buffer[5]; + struct tea5767_priv *priv = fe->tuner_priv; + unsigned div, rc; + + div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */ + buffer[0] = (div >> 8) & 0x3f; + buffer[1] = div & 0xff; + buffer[2] = TEA5767_PORT1_HIGH; + buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | + TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY; + buffer[4] = 0; + + if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + + return 0; +} + +int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) +{ + struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; + unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + int rc; + + if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) { + printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc); + return -EINVAL; + } + + /* If all bytes are the same then it's a TV tuner and not a tea5767 */ + if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && + buffer[0] == buffer[3] && buffer[0] == buffer[4]) { + printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n"); + return -EINVAL; + } + + /* Status bytes: + * Byte 4: bit 3:1 : CI (Chip Identification) == 0 + * bit 0 : internally set to 0 + * Byte 5: bit 7:0 : == 0 + */ + if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) { + printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n"); + return -EINVAL; + } + + + return 0; +} + +static int tea5767_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; +} + +static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tea5767_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + + return 0; +} + +static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg) +{ + struct tea5767_priv *priv = fe->tuner_priv; + + memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl)); + + return 0; +} + +static struct dvb_tuner_ops tea5767_tuner_ops = { + .info = { + .name = "tea5767", // Philips TEA5767HN FM Radio + }, + + .set_analog_params = set_radio_freq, + .set_config = tea5767_set_config, + .sleep = tea5767_standby, + .release = tea5767_release, + .get_frequency = tea5767_get_frequency, + .get_status = tea5767_get_status, + .get_rf_strength = tea5767_get_rf_strength, +}; + +struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + struct tea5767_priv *priv = NULL; + + priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + fe->tuner_priv = priv; + + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + priv->i2c_props.name = "tea5767"; + + priv->ctrl.xtal_freq = TEA5767_HIGH_LO_32768; + priv->ctrl.port1 = 1; + priv->ctrl.port2 = 1; + priv->ctrl.high_cut = 1; + priv->ctrl.st_noise = 1; + priv->ctrl.japan_band = 1; + + memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + tuner_info("type set to %s\n", "Philips TEA5767HN FM Radio"); + + return fe; +} + +EXPORT_SYMBOL_GPL(tea5767_attach); +EXPORT_SYMBOL_GPL(tea5767_autodetection); + +MODULE_DESCRIPTION("Philips TEA5767 FM tuner driver"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/tea5767.h b/drivers/media/tuners/tea5767.h new file mode 100644 index 000000000000..d30ab1b483de --- /dev/null +++ b/drivers/media/tuners/tea5767.h @@ -0,0 +1,66 @@ +/* + 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 __TEA5767_H__ +#define __TEA5767_H__ + +#include +#include "dvb_frontend.h" + +enum tea5767_xtal { + TEA5767_LOW_LO_32768 = 0, + TEA5767_HIGH_LO_32768 = 1, + TEA5767_LOW_LO_13MHz = 2, + TEA5767_HIGH_LO_13MHz = 3, +}; + +struct tea5767_ctrl { + unsigned int port1:1; + unsigned int port2:1; + unsigned int high_cut:1; + unsigned int st_noise:1; + unsigned int soft_mute:1; + unsigned int japan_band:1; + unsigned int deemph_75:1; + unsigned int pllref:1; + enum tea5767_xtal xtal_freq; +}; + +#if defined(CONFIG_MEDIA_TUNER_TEA5767) || (defined(CONFIG_MEDIA_TUNER_TEA5767_MODULE) && defined(MODULE)) +extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); + +extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr); +#else +static inline int tea5767_autodetection(struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __func__); + return -EINVAL; +} + +static inline struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __TEA5767_H__ */ diff --git a/drivers/media/tuners/tua9001.c b/drivers/media/tuners/tua9001.c new file mode 100644 index 000000000000..de2607084672 --- /dev/null +++ b/drivers/media/tuners/tua9001.c @@ -0,0 +1,215 @@ +/* + * Infineon TUA 9001 silicon tuner 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "tua9001.h" +#include "tua9001_priv.h" + +/* write register */ +static int tua9001_wr_reg(struct tua9001_priv *priv, u8 reg, u16 val) +{ + int ret; + u8 buf[3] = { reg, (val >> 8) & 0xff, (val >> 0) & 0xff }; + struct i2c_msg msg[1] = { + { + .addr = priv->cfg->i2c_addr, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + } + }; + + ret = i2c_transfer(priv->i2c, msg, 1); + if (ret == 1) { + ret = 0; + } else { + printk(KERN_WARNING "%s: I2C wr failed=%d reg=%02x\n", + __func__, ret, reg); + ret = -EREMOTEIO; + } + + return ret; +} + +static int tua9001_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; +} + +static int tua9001_init(struct dvb_frontend *fe) +{ + struct tua9001_priv *priv = fe->tuner_priv; + int ret = 0; + u8 i; + struct reg_val data[] = { + { 0x1e, 0x6512 }, + { 0x25, 0xb888 }, + { 0x39, 0x5460 }, + { 0x3b, 0x00c0 }, + { 0x3a, 0xf000 }, + { 0x08, 0x0000 }, + { 0x32, 0x0030 }, + { 0x41, 0x703a }, + { 0x40, 0x1c78 }, + { 0x2c, 0x1c00 }, + { 0x36, 0xc013 }, + { 0x37, 0x6f18 }, + { 0x27, 0x0008 }, + { 0x2a, 0x0001 }, + { 0x34, 0x0a40 }, + }; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */ + + for (i = 0; i < ARRAY_SIZE(data); i++) { + ret = tua9001_wr_reg(priv, data[i].reg, data[i].val); + if (ret) + break; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */ + + if (ret < 0) + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int tua9001_set_params(struct dvb_frontend *fe) +{ + struct tua9001_priv *priv = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, i; + u16 val; + u32 frequency; + struct reg_val data[2]; + + pr_debug("%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", + __func__, c->delivery_system, c->frequency, + c->bandwidth_hz); + + switch (c->delivery_system) { + case SYS_DVBT: + switch (c->bandwidth_hz) { + case 8000000: + val = 0x0000; + break; + case 7000000: + val = 0x1000; + break; + case 6000000: + val = 0x2000; + break; + case 5000000: + val = 0x3000; + break; + default: + ret = -EINVAL; + goto err; + } + break; + default: + ret = -EINVAL; + goto err; + } + + data[0].reg = 0x04; + data[0].val = val; + + frequency = (c->frequency - 150000000); + frequency /= 100; + frequency *= 48; + frequency /= 10000; + + data[1].reg = 0x1f; + data[1].val = frequency; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */ + + for (i = 0; i < ARRAY_SIZE(data); i++) { + ret = tua9001_wr_reg(priv, data[i].reg, data[i].val); + if (ret < 0) + break; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */ + +err: + if (ret < 0) + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + *frequency = 0; /* Zero-IF */ + + return 0; +} + +static const struct dvb_tuner_ops tua9001_tuner_ops = { + .info = { + .name = "Infineon TUA 9001", + + .frequency_min = 170000000, + .frequency_max = 862000000, + .frequency_step = 0, + }, + + .release = tua9001_release, + + .init = tua9001_init, + .set_params = tua9001_set_params, + + .get_if_frequency = tua9001_get_if_frequency, +}; + +struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct tua9001_config *cfg) +{ + struct tua9001_priv *priv = NULL; + + priv = kzalloc(sizeof(struct tua9001_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + + printk(KERN_INFO "Infineon TUA 9001 successfully attached."); + + memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + return fe; +} +EXPORT_SYMBOL(tua9001_attach); + +MODULE_DESCRIPTION("Infineon TUA 9001 silicon tuner driver"); +MODULE_AUTHOR("Antti Palosaari "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/tua9001.h b/drivers/media/tuners/tua9001.h new file mode 100644 index 000000000000..38d6ae76b1d6 --- /dev/null +++ b/drivers/media/tuners/tua9001.h @@ -0,0 +1,46 @@ +/* + * Infineon TUA 9001 silicon tuner 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef TUA9001_H +#define TUA9001_H + +#include "dvb_frontend.h" + +struct tua9001_config { + /* + * I2C address + */ + u8 i2c_addr; +}; + +#if defined(CONFIG_MEDIA_TUNER_TUA9001) || \ + (defined(CONFIG_MEDIA_TUNER_TUA9001_MODULE) && defined(MODULE)) +extern struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct tua9001_config *cfg); +#else +static inline struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct tua9001_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff --git a/drivers/media/tuners/tua9001_priv.h b/drivers/media/tuners/tua9001_priv.h new file mode 100644 index 000000000000..73cc1ce0575c --- /dev/null +++ b/drivers/media/tuners/tua9001_priv.h @@ -0,0 +1,34 @@ +/* + * Infineon TUA 9001 silicon tuner 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef TUA9001_PRIV_H +#define TUA9001_PRIV_H + +struct reg_val { + u8 reg; + u16 val; +}; + +struct tua9001_priv { + struct tua9001_config *cfg; + struct i2c_adapter *i2c; +}; + +#endif diff --git a/drivers/media/tuners/tuner-i2c.h b/drivers/media/tuners/tuner-i2c.h new file mode 100644 index 000000000000..18f005634c67 --- /dev/null +++ b/drivers/media/tuners/tuner-i2c.h @@ -0,0 +1,182 @@ +/* + tuner-i2c.h - i2c interface for different tuners + + Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) + + 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 __TUNER_I2C_H__ +#define __TUNER_I2C_H__ + +#include +#include + +struct tuner_i2c_props { + u8 addr; + struct i2c_adapter *adap; + + /* used for tuner instance management */ + int count; + char *name; +}; + +static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len) +{ + struct i2c_msg msg = { .addr = props->addr, .flags = 0, + .buf = buf, .len = len }; + int ret = i2c_transfer(props->adap, &msg, 1); + + return (ret == 1) ? len : ret; +} + +static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, int len) +{ + struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD, + .buf = buf, .len = len }; + int ret = i2c_transfer(props->adap, &msg, 1); + + return (ret == 1) ? len : ret; +} + +static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props, + char *obuf, int olen, + char *ibuf, int ilen) +{ + struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0, + .buf = obuf, .len = olen }, + { .addr = props->addr, .flags = I2C_M_RD, + .buf = ibuf, .len = ilen } }; + int ret = i2c_transfer(props->adap, msg, 2); + + return (ret == 2) ? ilen : ret; +} + +/* Callers must declare as a global for the module: + * + * static LIST_HEAD(hybrid_tuner_instance_list); + * + * hybrid_tuner_instance_list should be the third argument + * passed into hybrid_tuner_request_state(). + * + * state structure must contain the following: + * + * struct list_head hybrid_tuner_instance_list; + * struct tuner_i2c_props i2c_props; + * + * hybrid_tuner_instance_list (both within state structure and globally) + * is only required if the driver is using hybrid_tuner_request_state + * and hybrid_tuner_release_state to manage state sharing between + * multiple instances of hybrid tuners. + */ + +#define tuner_printk(kernlvl, i2cprops, fmt, arg...) do { \ + printk(kernlvl "%s %d-%04x: " fmt, i2cprops.name, \ + i2cprops.adap ? \ + i2c_adapter_id(i2cprops.adap) : -1, \ + i2cprops.addr, ##arg); \ + } while (0) + +/* TO DO: convert all callers of these macros to pass in + * struct tuner_i2c_props, then remove the macro wrappers */ + +#define __tuner_warn(i2cprops, fmt, arg...) do { \ + tuner_printk(KERN_WARNING, i2cprops, fmt, ##arg); \ + } while (0) + +#define __tuner_info(i2cprops, fmt, arg...) do { \ + tuner_printk(KERN_INFO, i2cprops, fmt, ##arg); \ + } while (0) + +#define __tuner_err(i2cprops, fmt, arg...) do { \ + tuner_printk(KERN_ERR, i2cprops, fmt, ##arg); \ + } while (0) + +#define __tuner_dbg(i2cprops, fmt, arg...) do { \ + if ((debug)) \ + tuner_printk(KERN_DEBUG, i2cprops, fmt, ##arg); \ + } while (0) + +#define tuner_warn(fmt, arg...) __tuner_warn(priv->i2c_props, fmt, ##arg) +#define tuner_info(fmt, arg...) __tuner_info(priv->i2c_props, fmt, ##arg) +#define tuner_err(fmt, arg...) __tuner_err(priv->i2c_props, fmt, ##arg) +#define tuner_dbg(fmt, arg...) __tuner_dbg(priv->i2c_props, fmt, ##arg) + +/****************************************************************************/ + +/* The return value of hybrid_tuner_request_state indicates the number of + * instances using this tuner object. + * + * 0 - no instances, indicates an error - kzalloc must have failed + * + * 1 - one instance, indicates that the tuner object was created successfully + * + * 2 (or more) instances, indicates that an existing tuner object was found + */ + +#define hybrid_tuner_request_state(type, state, list, i2cadap, i2caddr, devname)\ +({ \ + int __ret = 0; \ + list_for_each_entry(state, &list, hybrid_tuner_instance_list) { \ + if (((i2cadap) && (state->i2c_props.adap)) && \ + ((i2c_adapter_id(state->i2c_props.adap) == \ + i2c_adapter_id(i2cadap)) && \ + (i2caddr == state->i2c_props.addr))) { \ + __tuner_info(state->i2c_props, \ + "attaching existing instance\n"); \ + state->i2c_props.count++; \ + __ret = state->i2c_props.count; \ + break; \ + } \ + } \ + if (0 == __ret) { \ + state = kzalloc(sizeof(type), GFP_KERNEL); \ + if (NULL == state) \ + goto __fail; \ + state->i2c_props.addr = i2caddr; \ + state->i2c_props.adap = i2cadap; \ + state->i2c_props.name = devname; \ + __tuner_info(state->i2c_props, \ + "creating new instance\n"); \ + list_add_tail(&state->hybrid_tuner_instance_list, &list);\ + state->i2c_props.count++; \ + __ret = state->i2c_props.count; \ + } \ +__fail: \ + __ret; \ +}) + +#define hybrid_tuner_release_state(state) \ +({ \ + int __ret; \ + state->i2c_props.count--; \ + __ret = state->i2c_props.count; \ + if (!state->i2c_props.count) { \ + __tuner_info(state->i2c_props, "destroying instance\n");\ + list_del(&state->hybrid_tuner_instance_list); \ + kfree(state); \ + } \ + __ret; \ +}) + +#define hybrid_tuner_report_instance_count(state) \ +({ \ + int __ret = 0; \ + if (state) \ + __ret = state->i2c_props.count; \ + __ret; \ +}) + +#endif /* __TUNER_I2C_H__ */ diff --git a/drivers/media/tuners/tuner-simple.c b/drivers/media/tuners/tuner-simple.c new file mode 100644 index 000000000000..39e7e583c8c0 --- /dev/null +++ b/drivers/media/tuners/tuner-simple.c @@ -0,0 +1,1155 @@ +/* + * i2c tv tuner chip device driver + * controls all those simple 4-control-bytes style tuners. + * + * This "tuner-simple" module was split apart from the original "tuner" module. + */ +#include +#include +#include +#include +#include +#include +#include "tuner-i2c.h" +#include "tuner-simple.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +#define TUNER_SIMPLE_MAX 64 +static unsigned int simple_devcount; + +static int offset; +module_param(offset, int, 0664); +MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner"); + +static unsigned int atv_input[TUNER_SIMPLE_MAX] = \ + { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 }; +static unsigned int dtv_input[TUNER_SIMPLE_MAX] = \ + { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 }; +module_param_array(atv_input, int, NULL, 0644); +module_param_array(dtv_input, int, NULL, 0644); +MODULE_PARM_DESC(atv_input, "specify atv rf input, 0 for autoselect"); +MODULE_PARM_DESC(dtv_input, "specify dtv rf input, 0 for autoselect"); + +/* ---------------------------------------------------------------------- */ + +/* tv standard selection for Temic 4046 FM5 + this value takes the low bits of control byte 2 + from datasheet Rev.01, Feb.00 + standard BG I L L2 D + picture IF 38.9 38.9 38.9 33.95 38.9 + sound 1 33.4 32.9 32.4 40.45 32.4 + sound 2 33.16 + NICAM 33.05 32.348 33.05 33.05 + */ +#define TEMIC_SET_PAL_I 0x05 +#define TEMIC_SET_PAL_DK 0x09 +#define TEMIC_SET_PAL_L 0x0a /* SECAM ? */ +#define TEMIC_SET_PAL_L2 0x0b /* change IF ! */ +#define TEMIC_SET_PAL_BG 0x0c + +/* tv tuner system standard selection for Philips FQ1216ME + this value takes the low bits of control byte 2 + from datasheet "1999 Nov 16" (supersedes "1999 Mar 23") + standard BG DK I L L` + picture carrier 38.90 38.90 38.90 38.90 33.95 + colour 34.47 34.47 34.47 34.47 38.38 + sound 1 33.40 32.40 32.90 32.40 40.45 + sound 2 33.16 - - - - + NICAM 33.05 33.05 32.35 33.05 39.80 + */ +#define PHILIPS_SET_PAL_I 0x01 /* Bit 2 always zero !*/ +#define PHILIPS_SET_PAL_BGDK 0x09 +#define PHILIPS_SET_PAL_L2 0x0a +#define PHILIPS_SET_PAL_L 0x0b + +/* system switching for Philips FI1216MF MK2 + from datasheet "1996 Jul 09", + standard BG L L' + picture carrier 38.90 38.90 33.95 + colour 34.47 34.37 38.38 + sound 1 33.40 32.40 40.45 + sound 2 33.16 - - + NICAM 33.05 33.05 39.80 + */ +#define PHILIPS_MF_SET_STD_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */ +#define PHILIPS_MF_SET_STD_L 0x03 /* Used on Secam France */ +#define PHILIPS_MF_SET_STD_LC 0x02 /* Used on SECAM L' */ + +/* Control byte */ + +#define TUNER_RATIO_MASK 0x06 /* Bit cb1:cb2 */ +#define TUNER_RATIO_SELECT_50 0x00 +#define TUNER_RATIO_SELECT_32 0x02 +#define TUNER_RATIO_SELECT_166 0x04 +#define TUNER_RATIO_SELECT_62 0x06 + +#define TUNER_CHARGE_PUMP 0x40 /* Bit cb6 */ + +/* Status byte */ + +#define TUNER_POR 0x80 +#define TUNER_FL 0x40 +#define TUNER_MODE 0x38 +#define TUNER_AFC 0x07 +#define TUNER_SIGNAL 0x07 +#define TUNER_STEREO 0x10 + +#define TUNER_PLL_LOCKED 0x40 +#define TUNER_STEREO_MK3 0x04 + +static DEFINE_MUTEX(tuner_simple_list_mutex); +static LIST_HEAD(hybrid_tuner_instance_list); + +struct tuner_simple_priv { + unsigned int nr; + u16 last_div; + + struct tuner_i2c_props i2c_props; + struct list_head hybrid_tuner_instance_list; + + unsigned int type; + struct tunertype *tun; + + u32 frequency; + u32 bandwidth; +}; + +/* ---------------------------------------------------------------------- */ + +static int tuner_read_status(struct dvb_frontend *fe) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + unsigned char byte; + + if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1)) + return 0; + + return byte; +} + +static inline int tuner_signal(const int status) +{ + return (status & TUNER_SIGNAL) << 13; +} + +static inline int tuner_stereo(const int type, const int status) +{ + switch (type) { + case TUNER_PHILIPS_FM1216ME_MK3: + case TUNER_PHILIPS_FM1236_MK3: + case TUNER_PHILIPS_FM1256_IH3: + case TUNER_LG_NTSC_TAPE: + case TUNER_TCL_MF02GIP_5N: + return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3); + case TUNER_PHILIPS_FM1216MK5: + return status | TUNER_STEREO; + default: + return status & TUNER_STEREO; + } +} + +static inline int tuner_islocked(const int status) +{ + return (status & TUNER_FL); +} + +static inline int tuner_afcstatus(const int status) +{ + return (status & TUNER_AFC) - 2; +} + + +static int simple_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int tuner_status; + + if (priv->i2c_props.adap == NULL) + return -EINVAL; + + tuner_status = tuner_read_status(fe); + + *status = 0; + + if (tuner_islocked(tuner_status)) + *status = TUNER_STATUS_LOCKED; + if (tuner_stereo(priv->type, tuner_status)) + *status |= TUNER_STATUS_STEREO; + + tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status)); + + return 0; +} + +static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int signal; + + if (priv->i2c_props.adap == NULL) + return -EINVAL; + + signal = tuner_signal(tuner_read_status(fe)); + + *strength = signal; + + tuner_dbg("Signal strength: %d\n", signal); + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static inline char *tuner_param_name(enum param_type type) +{ + char *name; + + switch (type) { + case TUNER_PARAM_TYPE_RADIO: + name = "radio"; + break; + case TUNER_PARAM_TYPE_PAL: + name = "pal"; + break; + case TUNER_PARAM_TYPE_SECAM: + name = "secam"; + break; + case TUNER_PARAM_TYPE_NTSC: + name = "ntsc"; + break; + case TUNER_PARAM_TYPE_DIGITAL: + name = "digital"; + break; + default: + name = "unknown"; + break; + } + return name; +} + +static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe, + enum param_type desired_type) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + struct tunertype *tun = priv->tun; + int i; + + for (i = 0; i < tun->count; i++) + if (desired_type == tun->params[i].type) + break; + + /* use default tuner params if desired_type not available */ + if (i == tun->count) { + tuner_dbg("desired params (%s) undefined for tuner %d\n", + tuner_param_name(desired_type), priv->type); + i = 0; + } + + tuner_dbg("using tuner params #%d (%s)\n", i, + tuner_param_name(tun->params[i].type)); + + return &tun->params[i]; +} + +static int simple_config_lookup(struct dvb_frontend *fe, + struct tuner_params *t_params, + unsigned *frequency, u8 *config, u8 *cb) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int i; + + for (i = 0; i < t_params->count; i++) { + if (*frequency > t_params->ranges[i].limit) + continue; + break; + } + if (i == t_params->count) { + tuner_dbg("frequency out of range (%d > %d)\n", + *frequency, t_params->ranges[i - 1].limit); + *frequency = t_params->ranges[--i].limit; + } + *config = t_params->ranges[i].config; + *cb = t_params->ranges[i].cb; + + tuner_dbg("freq = %d.%02d (%d), range = %d, " + "config = 0x%02x, cb = 0x%02x\n", + *frequency / 16, *frequency % 16 * 100 / 16, *frequency, + i, *config, *cb); + + return i; +} + +/* ---------------------------------------------------------------------- */ + +static void simple_set_rf_input(struct dvb_frontend *fe, + u8 *config, u8 *cb, unsigned int rf) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + + switch (priv->type) { + case TUNER_PHILIPS_TUV1236D: + switch (rf) { + case 1: + *cb |= 0x08; + break; + default: + *cb &= ~0x08; + break; + } + break; + case TUNER_PHILIPS_FCV1236D: + switch (rf) { + case 1: + *cb |= 0x01; + break; + default: + *cb &= ~0x01; + break; + } + break; + default: + break; + } +} + +static int simple_std_setup(struct dvb_frontend *fe, + struct analog_parameters *params, + u8 *config, u8 *cb) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int rc; + + /* tv norm specific stuff for multi-norm tuners */ + switch (priv->type) { + case TUNER_PHILIPS_SECAM: /* FI1216MF */ + /* 0x01 -> ??? no change ??? */ + /* 0x02 -> PAL BDGHI / SECAM L */ + /* 0x04 -> ??? PAL others / SECAM others ??? */ + *cb &= ~0x03; + if (params->std & V4L2_STD_SECAM_L) + /* also valid for V4L2_STD_SECAM */ + *cb |= PHILIPS_MF_SET_STD_L; + else if (params->std & V4L2_STD_SECAM_LC) + *cb |= PHILIPS_MF_SET_STD_LC; + else /* V4L2_STD_B|V4L2_STD_GH */ + *cb |= PHILIPS_MF_SET_STD_BG; + break; + + case TUNER_TEMIC_4046FM5: + *cb &= ~0x0f; + + if (params->std & V4L2_STD_PAL_BG) { + *cb |= TEMIC_SET_PAL_BG; + + } else if (params->std & V4L2_STD_PAL_I) { + *cb |= TEMIC_SET_PAL_I; + + } else if (params->std & V4L2_STD_PAL_DK) { + *cb |= TEMIC_SET_PAL_DK; + + } else if (params->std & V4L2_STD_SECAM_L) { + *cb |= TEMIC_SET_PAL_L; + + } + break; + + case TUNER_PHILIPS_FQ1216ME: + *cb &= ~0x0f; + + if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { + *cb |= PHILIPS_SET_PAL_BGDK; + + } else if (params->std & V4L2_STD_PAL_I) { + *cb |= PHILIPS_SET_PAL_I; + + } else if (params->std & V4L2_STD_SECAM_L) { + *cb |= PHILIPS_SET_PAL_L; + + } + break; + + case TUNER_PHILIPS_FCV1236D: + /* 0x00 -> ATSC antenna input 1 */ + /* 0x01 -> ATSC antenna input 2 */ + /* 0x02 -> NTSC antenna input 1 */ + /* 0x03 -> NTSC antenna input 2 */ + *cb &= ~0x03; + if (!(params->std & V4L2_STD_ATSC)) + *cb |= 2; + break; + + case TUNER_MICROTUNE_4042FI5: + /* Set the charge pump for fast tuning */ + *config |= TUNER_CHARGE_PUMP; + break; + + case TUNER_PHILIPS_TUV1236D: + { + struct tuner_i2c_props i2c = priv->i2c_props; + /* 0x40 -> ATSC antenna input 1 */ + /* 0x48 -> ATSC antenna input 2 */ + /* 0x00 -> NTSC antenna input 1 */ + /* 0x08 -> NTSC antenna input 2 */ + u8 buffer[4] = { 0x14, 0x00, 0x17, 0x00}; + *cb &= ~0x40; + if (params->std & V4L2_STD_ATSC) { + *cb |= 0x40; + buffer[1] = 0x04; + } + /* set to the correct mode (analog or digital) */ + i2c.addr = 0x0a; + rc = tuner_i2c_xfer_send(&i2c, &buffer[0], 2); + if (2 != rc) + tuner_warn("i2c i/o error: rc == %d " + "(should be 2)\n", rc); + rc = tuner_i2c_xfer_send(&i2c, &buffer[2], 2); + if (2 != rc) + tuner_warn("i2c i/o error: rc == %d " + "(should be 2)\n", rc); + break; + } + } + if (atv_input[priv->nr]) + simple_set_rf_input(fe, config, cb, atv_input[priv->nr]); + + return 0; +} + +static int simple_set_aux_byte(struct dvb_frontend *fe, u8 config, u8 aux) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int rc; + u8 buffer[2]; + + buffer[0] = (config & ~0x38) | 0x18; + buffer[1] = aux; + + tuner_dbg("setting aux byte: 0x%02x 0x%02x\n", buffer[0], buffer[1]); + + rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2); + if (2 != rc) + tuner_warn("i2c i/o error: rc == %d (should be 2)\n", rc); + + return rc == 2 ? 0 : rc; +} + +static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer, + u16 div, u8 config, u8 cb) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int rc; + + switch (priv->type) { + case TUNER_LG_TDVS_H06XF: + simple_set_aux_byte(fe, config, 0x20); + break; + case TUNER_PHILIPS_FQ1216LME_MK3: + simple_set_aux_byte(fe, config, 0x60); /* External AGC */ + break; + case TUNER_MICROTUNE_4042FI5: + { + /* FIXME - this may also work for other tuners */ + unsigned long timeout = jiffies + msecs_to_jiffies(1); + u8 status_byte = 0; + + /* Wait until the PLL locks */ + for (;;) { + if (time_after(jiffies, timeout)) + return 0; + rc = tuner_i2c_xfer_recv(&priv->i2c_props, + &status_byte, 1); + if (1 != rc) { + tuner_warn("i2c i/o read error: rc == %d " + "(should be 1)\n", rc); + break; + } + if (status_byte & TUNER_PLL_LOCKED) + break; + udelay(10); + } + + /* Set the charge pump for optimized phase noise figure */ + config &= ~TUNER_CHARGE_PUMP; + buffer[0] = (div>>8) & 0x7f; + buffer[1] = div & 0xff; + buffer[2] = config; + buffer[3] = cb; + tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", + buffer[0], buffer[1], buffer[2], buffer[3]); + + rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); + if (4 != rc) + tuner_warn("i2c i/o error: rc == %d " + "(should be 4)\n", rc); + break; + } + } + + return 0; +} + +static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + + switch (priv->type) { + case TUNER_TENA_9533_DI: + case TUNER_YMEC_TVF_5533MF: + tuner_dbg("This tuner doesn't have FM. " + "Most cards have a TEA5767 for FM\n"); + return 0; + case TUNER_PHILIPS_FM1216ME_MK3: + case TUNER_PHILIPS_FM1236_MK3: + case TUNER_PHILIPS_FMD1216ME_MK3: + case TUNER_PHILIPS_FMD1216MEX_MK3: + case TUNER_LG_NTSC_TAPE: + case TUNER_PHILIPS_FM1256_IH3: + case TUNER_TCL_MF02GIP_5N: + buffer[3] = 0x19; + break; + case TUNER_PHILIPS_FM1216MK5: + buffer[2] = 0x88; + buffer[3] = 0x09; + break; + case TUNER_TNF_5335MF: + buffer[3] = 0x11; + break; + case TUNER_LG_PAL_FM: + buffer[3] = 0xa5; + break; + case TUNER_THOMSON_DTT761X: + buffer[3] = 0x39; + break; + case TUNER_PHILIPS_FQ1216LME_MK3: + case TUNER_PHILIPS_FQ1236_MK5: + tuner_err("This tuner doesn't have FM\n"); + /* Set the low band for sanity, since it covers 88-108 MHz */ + buffer[3] = 0x01; + break; + case TUNER_MICROTUNE_4049FM5: + default: + buffer[3] = 0xa4; + break; + } + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int simple_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + u8 config, cb; + u16 div; + u8 buffer[4]; + int rc, IFPCoff, i; + enum param_type desired_type; + struct tuner_params *t_params; + + /* IFPCoff = Video Intermediate Frequency - Vif: + 940 =16*58.75 NTSC/J (Japan) + 732 =16*45.75 M/N STD + 704 =16*44 ATSC (at DVB code) + 632 =16*39.50 I U.K. + 622.4=16*38.90 B/G D/K I, L STD + 592 =16*37.00 D China + 590 =16.36.875 B Australia + 543.2=16*33.95 L' STD + 171.2=16*10.70 FM Radio (at set_radio_freq) + */ + + if (params->std == V4L2_STD_NTSC_M_JP) { + IFPCoff = 940; + desired_type = TUNER_PARAM_TYPE_NTSC; + } else if ((params->std & V4L2_STD_MN) && + !(params->std & ~V4L2_STD_MN)) { + IFPCoff = 732; + desired_type = TUNER_PARAM_TYPE_NTSC; + } else if (params->std == V4L2_STD_SECAM_LC) { + IFPCoff = 543; + desired_type = TUNER_PARAM_TYPE_SECAM; + } else { + IFPCoff = 623; + desired_type = TUNER_PARAM_TYPE_PAL; + } + + t_params = simple_tuner_params(fe, desired_type); + + i = simple_config_lookup(fe, t_params, ¶ms->frequency, + &config, &cb); + + div = params->frequency + IFPCoff + offset; + + tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, " + "Offset=%d.%02d MHz, div=%0d\n", + params->frequency / 16, params->frequency % 16 * 100 / 16, + IFPCoff / 16, IFPCoff % 16 * 100 / 16, + offset / 16, offset % 16 * 100 / 16, div); + + /* tv norm specific stuff for multi-norm tuners */ + simple_std_setup(fe, params, &config, &cb); + + if (t_params->cb_first_if_lower_freq && div < priv->last_div) { + buffer[0] = config; + buffer[1] = cb; + buffer[2] = (div>>8) & 0x7f; + buffer[3] = div & 0xff; + } else { + buffer[0] = (div>>8) & 0x7f; + buffer[1] = div & 0xff; + buffer[2] = config; + buffer[3] = cb; + } + priv->last_div = div; + if (t_params->has_tda9887) { + struct v4l2_priv_tun_config tda9887_cfg; + int tda_config = 0; + int is_secam_l = (params->std & (V4L2_STD_SECAM_L | + V4L2_STD_SECAM_LC)) && + !(params->std & ~(V4L2_STD_SECAM_L | + V4L2_STD_SECAM_LC)); + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &tda_config; + + if (params->std == V4L2_STD_SECAM_LC) { + if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc) + tda_config |= TDA9887_PORT1_ACTIVE; + if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc) + tda_config |= TDA9887_PORT2_ACTIVE; + } else { + if (t_params->port1_active) + tda_config |= TDA9887_PORT1_ACTIVE; + if (t_params->port2_active) + tda_config |= TDA9887_PORT2_ACTIVE; + } + if (t_params->intercarrier_mode) + tda_config |= TDA9887_INTERCARRIER; + if (is_secam_l) { + if (i == 0 && t_params->default_top_secam_low) + tda_config |= TDA9887_TOP(t_params->default_top_secam_low); + else if (i == 1 && t_params->default_top_secam_mid) + tda_config |= TDA9887_TOP(t_params->default_top_secam_mid); + else if (t_params->default_top_secam_high) + tda_config |= TDA9887_TOP(t_params->default_top_secam_high); + } else { + if (i == 0 && t_params->default_top_low) + tda_config |= TDA9887_TOP(t_params->default_top_low); + else if (i == 1 && t_params->default_top_mid) + tda_config |= TDA9887_TOP(t_params->default_top_mid); + else if (t_params->default_top_high) + tda_config |= TDA9887_TOP(t_params->default_top_high); + } + if (t_params->default_pll_gating_18) + tda_config |= TDA9887_GATING_18; + i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, + &tda9887_cfg); + } + tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", + buffer[0], buffer[1], buffer[2], buffer[3]); + + rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); + if (4 != rc) + tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); + + simple_post_tune(fe, &buffer[0], div, config, cb); + + return 0; +} + +static int simple_set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tunertype *tun; + struct tuner_simple_priv *priv = fe->tuner_priv; + u8 buffer[4]; + u16 div; + int rc, j; + struct tuner_params *t_params; + unsigned int freq = params->frequency; + + tun = priv->tun; + + for (j = tun->count-1; j > 0; j--) + if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO) + break; + /* default t_params (j=0) will be used if desired type wasn't found */ + t_params = &tun->params[j]; + + /* Select Radio 1st IF used */ + switch (t_params->radio_if) { + case 0: /* 10.7 MHz */ + freq += (unsigned int)(10.7*16000); + break; + case 1: /* 33.3 MHz */ + freq += (unsigned int)(33.3*16000); + break; + case 2: /* 41.3 MHz */ + freq += (unsigned int)(41.3*16000); + break; + default: + tuner_warn("Unsupported radio_if value %d\n", + t_params->radio_if); + return 0; + } + + buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) | + TUNER_RATIO_SELECT_50; /* 50 kHz step */ + + /* Bandswitch byte */ + simple_radio_bandswitch(fe, &buffer[0]); + + /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps + freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) = + freq * (1/800) */ + div = (freq + 400) / 800; + + if (t_params->cb_first_if_lower_freq && div < priv->last_div) { + buffer[0] = buffer[2]; + buffer[1] = buffer[3]; + buffer[2] = (div>>8) & 0x7f; + buffer[3] = div & 0xff; + } else { + buffer[0] = (div>>8) & 0x7f; + buffer[1] = div & 0xff; + } + + tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n", + buffer[0], buffer[1], buffer[2], buffer[3]); + priv->last_div = div; + + if (t_params->has_tda9887) { + int config = 0; + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &config; + + if (t_params->port1_active && + !t_params->port1_fm_high_sensitivity) + config |= TDA9887_PORT1_ACTIVE; + if (t_params->port2_active && + !t_params->port2_fm_high_sensitivity) + config |= TDA9887_PORT2_ACTIVE; + if (t_params->intercarrier_mode) + config |= TDA9887_INTERCARRIER; +/* if (t_params->port1_set_for_fm_mono) + config &= ~TDA9887_PORT1_ACTIVE;*/ + if (t_params->fm_gain_normal) + config |= TDA9887_GAIN_NORMAL; + if (t_params->radio_if == 2) + config |= TDA9887_RIF_41_3; + i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, + &tda9887_cfg); + } + rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); + if (4 != rc) + tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); + + /* Write AUX byte */ + switch (priv->type) { + case TUNER_PHILIPS_FM1216ME_MK3: + buffer[2] = 0x98; + buffer[3] = 0x20; /* set TOP AGC */ + rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); + if (4 != rc) + tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); + break; + } + + return 0; +} + +static int simple_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + if (priv->i2c_props.adap == NULL) + return -EINVAL; + + switch (params->mode) { + case V4L2_TUNER_RADIO: + ret = simple_set_radio_freq(fe, params); + priv->frequency = params->frequency * 125 / 2; + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + ret = simple_set_tv_freq(fe, params); + priv->frequency = params->frequency * 62500; + break; + } + priv->bandwidth = 0; + + return ret; +} + +static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf, + const u32 delsys, + const u32 frequency, + const u32 bandwidth) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + + switch (priv->type) { + case TUNER_PHILIPS_FMD1216ME_MK3: + case TUNER_PHILIPS_FMD1216MEX_MK3: + if (bandwidth == 8000000 && + frequency >= 158870000) + buf[3] |= 0x08; + break; + case TUNER_PHILIPS_TD1316: + /* determine band */ + buf[3] |= (frequency < 161000000) ? 1 : + (frequency < 444000000) ? 2 : 4; + + /* setup PLL filter */ + if (bandwidth == 8000000) + buf[3] |= 1 << 3; + break; + case TUNER_PHILIPS_TUV1236D: + case TUNER_PHILIPS_FCV1236D: + { + unsigned int new_rf; + + if (dtv_input[priv->nr]) + new_rf = dtv_input[priv->nr]; + else + switch (delsys) { + case SYS_DVBC_ANNEX_B: + new_rf = 1; + break; + case SYS_ATSC: + default: + new_rf = 0; + break; + } + simple_set_rf_input(fe, &buf[2], &buf[3], new_rf); + break; + } + default: + break; + } +} + +static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, + const u32 delsys, + const u32 freq, + const u32 bw) +{ + /* This function returns the tuned frequency on success, 0 on error */ + struct tuner_simple_priv *priv = fe->tuner_priv; + struct tunertype *tun = priv->tun; + static struct tuner_params *t_params; + u8 config, cb; + u32 div; + int ret; + u32 frequency = freq / 62500; + + if (!tun->stepsize) { + /* tuner-core was loaded before the digital tuner was + * configured and somehow picked the wrong tuner type */ + tuner_err("attempt to treat tuner %d (%s) as digital tuner " + "without stepsize defined.\n", + priv->type, priv->tun->name); + return 0; /* failure */ + } + + t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL); + ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb); + if (ret < 0) + return 0; /* failure */ + + div = ((frequency + t_params->iffreq) * 62500 + offset + + tun->stepsize/2) / tun->stepsize; + + buf[0] = div >> 8; + buf[1] = div & 0xff; + buf[2] = config; + buf[3] = cb; + + simple_set_dvb(fe, buf, delsys, freq, bw); + + tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", + tun->name, div, buf[0], buf[1], buf[2], buf[3]); + + /* calculate the frequency we set it to */ + return (div * tun->stepsize) - t_params->iffreq; +} + +static int simple_dvb_calc_regs(struct dvb_frontend *fe, + u8 *buf, int buf_len) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; + struct tuner_simple_priv *priv = fe->tuner_priv; + u32 frequency; + + if (buf_len < 5) + return -EINVAL; + + frequency = simple_dvb_configure(fe, buf+1, delsys, c->frequency, bw); + if (frequency == 0) + return -EINVAL; + + buf[0] = priv->i2c_props.addr; + + priv->frequency = frequency; + priv->bandwidth = c->bandwidth_hz; + + return 5; +} + +static int simple_dvb_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; + u32 freq = c->frequency; + struct tuner_simple_priv *priv = fe->tuner_priv; + u32 frequency; + u32 prev_freq, prev_bw; + int ret; + u8 buf[5]; + + if (priv->i2c_props.adap == NULL) + return -EINVAL; + + prev_freq = priv->frequency; + prev_bw = priv->bandwidth; + + frequency = simple_dvb_configure(fe, buf+1, delsys, freq, bw); + if (frequency == 0) + return -EINVAL; + + buf[0] = priv->i2c_props.addr; + + priv->frequency = frequency; + priv->bandwidth = bw; + + /* put analog demod in standby when tuning digital */ + if (fe->ops.analog_ops.standby) + fe->ops.analog_ops.standby(fe); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + /* buf[0] contains the i2c address, but * + * we already have it in i2c_props.addr */ + ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4); + if (ret != 4) + goto fail; + + return 0; +fail: + /* calc_regs sets frequency and bandwidth. if we failed, unset them */ + priv->frequency = prev_freq; + priv->bandwidth = prev_bw; + + return ret; +} + +static int simple_init(struct dvb_frontend *fe) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + + if (priv->i2c_props.adap == NULL) + return -EINVAL; + + if (priv->tun->initdata) { + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = tuner_i2c_xfer_send(&priv->i2c_props, + priv->tun->initdata + 1, + priv->tun->initdata[0]); + if (ret != priv->tun->initdata[0]) + return ret; + } + + return 0; +} + +static int simple_sleep(struct dvb_frontend *fe) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + + if (priv->i2c_props.adap == NULL) + return -EINVAL; + + if (priv->tun->sleepdata) { + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = tuner_i2c_xfer_send(&priv->i2c_props, + priv->tun->sleepdata + 1, + priv->tun->sleepdata[0]); + if (ret != priv->tun->sleepdata[0]) + return ret; + } + + return 0; +} + +static int simple_release(struct dvb_frontend *fe) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + + mutex_lock(&tuner_simple_list_mutex); + + if (priv) + hybrid_tuner_release_state(priv); + + mutex_unlock(&tuner_simple_list_mutex); + + fe->tuner_priv = NULL; + + return 0; +} + +static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static struct dvb_tuner_ops simple_tuner_ops = { + .init = simple_init, + .sleep = simple_sleep, + .set_analog_params = simple_set_params, + .set_params = simple_dvb_set_params, + .calc_regs = simple_dvb_calc_regs, + .release = simple_release, + .get_frequency = simple_get_frequency, + .get_bandwidth = simple_get_bandwidth, + .get_status = simple_get_status, + .get_rf_strength = simple_get_rf_strength, +}; + +struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + unsigned int type) +{ + struct tuner_simple_priv *priv = NULL; + int instance; + + if (type >= tuner_count) { + printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n", + __func__, type, tuner_count-1); + return NULL; + } + + /* If i2c_adap is set, check that the tuner is at the correct address. + * Otherwise, if i2c_adap is NULL, the tuner will be programmed directly + * by the digital demod via calc_regs. + */ + if (i2c_adap != NULL) { + u8 b[1]; + struct i2c_msg msg = { + .addr = i2c_addr, .flags = I2C_M_RD, + .buf = b, .len = 1, + }; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (1 != i2c_transfer(i2c_adap, &msg, 1)) + printk(KERN_WARNING "tuner-simple %d-%04x: " + "unable to probe %s, proceeding anyway.", + i2c_adapter_id(i2c_adap), i2c_addr, + tuners[type].name); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + mutex_lock(&tuner_simple_list_mutex); + + instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv, + hybrid_tuner_instance_list, + i2c_adap, i2c_addr, + "tuner-simple"); + switch (instance) { + case 0: + mutex_unlock(&tuner_simple_list_mutex); + return NULL; + case 1: + fe->tuner_priv = priv; + + priv->type = type; + priv->tun = &tuners[type]; + priv->nr = simple_devcount++; + break; + default: + fe->tuner_priv = priv; + break; + } + + mutex_unlock(&tuner_simple_list_mutex); + + memcpy(&fe->ops.tuner_ops, &simple_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + if (type != priv->type) + tuner_warn("couldn't set type to %d. Using %d (%s) instead\n", + type, priv->type, priv->tun->name); + else + tuner_info("type set to %d (%s)\n", + priv->type, priv->tun->name); + + if ((debug) || ((atv_input[priv->nr] > 0) || + (dtv_input[priv->nr] > 0))) { + if (0 == atv_input[priv->nr]) + tuner_info("tuner %d atv rf input will be " + "autoselected\n", priv->nr); + else + tuner_info("tuner %d atv rf input will be " + "set to input %d (insmod option)\n", + priv->nr, atv_input[priv->nr]); + if (0 == dtv_input[priv->nr]) + tuner_info("tuner %d dtv rf input will be " + "autoselected\n", priv->nr); + else + tuner_info("tuner %d dtv rf input will be " + "set to input %d (insmod option)\n", + priv->nr, dtv_input[priv->nr]); + } + + strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name, + sizeof(fe->ops.tuner_ops.info.name)); + + return fe; +} +EXPORT_SYMBOL_GPL(simple_tuner_attach); + +MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver"); +MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/tuners/tuner-simple.h b/drivers/media/tuners/tuner-simple.h new file mode 100644 index 000000000000..381fa5d35a9b --- /dev/null +++ b/drivers/media/tuners/tuner-simple.h @@ -0,0 +1,39 @@ +/* + 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 __TUNER_SIMPLE_H__ +#define __TUNER_SIMPLE_H__ + +#include +#include "dvb_frontend.h" + +#if defined(CONFIG_MEDIA_TUNER_SIMPLE) || (defined(CONFIG_MEDIA_TUNER_SIMPLE_MODULE) && defined(MODULE)) +extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + unsigned int type); +#else +static inline struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + unsigned int type) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __TUNER_SIMPLE_H__ */ diff --git a/drivers/media/tuners/tuner-types.c b/drivers/media/tuners/tuner-types.c new file mode 100644 index 000000000000..2da4440c16ee --- /dev/null +++ b/drivers/media/tuners/tuner-types.c @@ -0,0 +1,1883 @@ +/* + * + * i2c tv tuner chip device type database. + * + */ + +#include +#include +#include +#include + +/* ---------------------------------------------------------------------- */ + +/* + * The floats in the tuner struct are computed at compile time + * by gcc and cast back to integers. Thus we don't violate the + * "no float in kernel" rule. + * + * A tuner_range may be referenced by multiple tuner_params structs. + * There are many duplicates in here. Reusing tuner_range structs, + * rather than defining new ones for each tuner, will cut down on + * memory usage, and is preferred when possible. + * + * Each tuner_params array may contain one or more elements, one + * for each video standard. + * + * FIXME: tuner_params struct contains an element, tda988x. We must + * set this for all tuners that contain a tda988x chip, and then we + * can remove this setting from the various card structs. + * + * FIXME: Right now, all tuners are using the first tuner_params[] + * array element for analog mode. In the future, we will be merging + * similar tuner definitions together, such that each tuner definition + * will have a tuner_params struct for each available video standard. + * At that point, the tuner_params[] array element will be chosen + * based on the video standard in use. + */ + +/* The following was taken from dvb-pll.c: */ + +/* Set AGC TOP value to 103 dBuV: + * 0x80 = Control Byte + * 0x40 = 250 uA charge pump (irrelevant) + * 0x18 = Aux Byte to follow + * 0x06 = 64.5 kHz divider (irrelevant) + * 0x01 = Disable Vt (aka sleep) + * + * 0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA) + * 0x50 = AGC Take over point = 103 dBuV + */ +static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 }; + +/* 0x04 = 166.67 kHz divider + * + * 0x80 = AGC Time constant 50ms Iagc = 9 uA + * 0x20 = AGC Take over point = 112 dBuV + */ +static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 }; + +/* 0-9 */ +/* ------------ TUNER_TEMIC_PAL - TEMIC PAL ------------ */ + +static struct tuner_range tuner_temic_pal_ranges[] = { + { 16 * 140.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0x04, }, + { 16 * 999.99 , 0x8e, 0x01, }, +}; + +static struct tuner_params tuner_temic_pal_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_pal_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_PAL_I - Philips PAL_I ------------ */ + +static struct tuner_range tuner_philips_pal_i_ranges[] = { + { 16 * 140.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_philips_pal_i_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_philips_pal_i_ranges, + .count = ARRAY_SIZE(tuner_philips_pal_i_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_NTSC - Philips NTSC ------------ */ + +static struct tuner_range tuner_philips_ntsc_ranges[] = { + { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 451.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_philips_ntsc_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_philips_ntsc_ranges, + .count = ARRAY_SIZE(tuner_philips_ntsc_ranges), + .cb_first_if_lower_freq = 1, + }, +}; + +/* ------------ TUNER_PHILIPS_SECAM - Philips SECAM ------------ */ + +static struct tuner_range tuner_philips_secam_ranges[] = { + { 16 * 168.25 /*MHz*/, 0x8e, 0xa7, }, + { 16 * 447.25 /*MHz*/, 0x8e, 0x97, }, + { 16 * 999.99 , 0x8e, 0x37, }, +}; + +static struct tuner_params tuner_philips_secam_params[] = { + { + .type = TUNER_PARAM_TYPE_SECAM, + .ranges = tuner_philips_secam_ranges, + .count = ARRAY_SIZE(tuner_philips_secam_ranges), + .cb_first_if_lower_freq = 1, + }, +}; + +/* ------------ TUNER_PHILIPS_PAL - Philips PAL ------------ */ + +static struct tuner_range tuner_philips_pal_ranges[] = { + { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 447.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_philips_pal_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_philips_pal_ranges, + .count = ARRAY_SIZE(tuner_philips_pal_ranges), + .cb_first_if_lower_freq = 1, + }, +}; + +/* ------------ TUNER_TEMIC_NTSC - TEMIC NTSC ------------ */ + +static struct tuner_range tuner_temic_ntsc_ranges[] = { + { 16 * 157.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0x04, }, + { 16 * 999.99 , 0x8e, 0x01, }, +}; + +static struct tuner_params tuner_temic_ntsc_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_temic_ntsc_ranges, + .count = ARRAY_SIZE(tuner_temic_ntsc_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_PAL_I - TEMIC PAL_I ------------ */ + +static struct tuner_range tuner_temic_pal_i_ranges[] = { + { 16 * 170.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 450.00 /*MHz*/, 0x8e, 0x04, }, + { 16 * 999.99 , 0x8e, 0x01, }, +}; + +static struct tuner_params tuner_temic_pal_i_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_pal_i_ranges, + .count = ARRAY_SIZE(tuner_temic_pal_i_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4036FY5_NTSC - TEMIC NTSC ------------ */ + +static struct tuner_range tuner_temic_4036fy5_ntsc_ranges[] = { + { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_temic_4036fy5_ntsc_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_temic_4036fy5_ntsc_ranges, + .count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_ranges), + }, +}; + +/* ------------ TUNER_ALPS_TSBH1_NTSC - TEMIC NTSC ------------ */ + +static struct tuner_range tuner_alps_tsb_1_ranges[] = { + { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 385.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_params tuner_alps_tsbh1_ntsc_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_alps_tsb_1_ranges, + .count = ARRAY_SIZE(tuner_alps_tsb_1_ranges), + }, +}; + +/* 10-19 */ +/* ------------ TUNER_ALPS_TSBE1_PAL - TEMIC PAL ------------ */ + +static struct tuner_params tuner_alps_tsb_1_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_alps_tsb_1_ranges, + .count = ARRAY_SIZE(tuner_alps_tsb_1_ranges), + }, +}; + +/* ------------ TUNER_ALPS_TSBB5_PAL_I - Alps PAL_I ------------ */ + +static struct tuner_range tuner_alps_tsb_5_pal_ranges[] = { + { 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 351.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_params tuner_alps_tsbb5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_alps_tsb_5_pal_ranges, + .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), + }, +}; + +/* ------------ TUNER_ALPS_TSBE5_PAL - Alps PAL ------------ */ + +static struct tuner_params tuner_alps_tsbe5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_alps_tsb_5_pal_ranges, + .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), + }, +}; + +/* ------------ TUNER_ALPS_TSBC5_PAL - Alps PAL ------------ */ + +static struct tuner_params tuner_alps_tsbc5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_alps_tsb_5_pal_ranges, + .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4006FH5_PAL - TEMIC PAL ------------ */ + +static struct tuner_range tuner_lg_pal_ranges[] = { + { 16 * 170.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 450.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_temic_4006fh5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_pal_ranges, + .count = ARRAY_SIZE(tuner_lg_pal_ranges), + }, +}; + +/* ------------ TUNER_ALPS_TSHC6_NTSC - Alps NTSC ------------ */ + +static struct tuner_range tuner_alps_tshc6_ntsc_ranges[] = { + { 16 * 137.25 /*MHz*/, 0x8e, 0x14, }, + { 16 * 385.25 /*MHz*/, 0x8e, 0x12, }, + { 16 * 999.99 , 0x8e, 0x11, }, +}; + +static struct tuner_params tuner_alps_tshc6_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_alps_tshc6_ntsc_ranges, + .count = ARRAY_SIZE(tuner_alps_tshc6_ntsc_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_PAL_DK - TEMIC PAL ------------ */ + +static struct tuner_range tuner_temic_pal_dk_ranges[] = { + { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 456.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_temic_pal_dk_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_pal_dk_ranges, + .count = ARRAY_SIZE(tuner_temic_pal_dk_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_NTSC_M - Philips NTSC ------------ */ + +static struct tuner_range tuner_philips_ntsc_m_ranges[] = { + { 16 * 160.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 454.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_philips_ntsc_m_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_philips_ntsc_m_ranges, + .count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4066FY5_PAL_I - TEMIC PAL_I ------------ */ + +static struct tuner_range tuner_temic_40x6f_5_pal_ranges[] = { + { 16 * 169.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 454.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_temic_4066fy5_pal_i_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_40x6f_5_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4006FN5_MULTI_PAL - TEMIC PAL ------------ */ + +static struct tuner_params tuner_temic_4006fn5_multi_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_40x6f_5_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), + }, +}; + +/* 20-29 */ +/* ------------ TUNER_TEMIC_4009FR5_PAL - TEMIC PAL ------------ */ + +static struct tuner_range tuner_temic_4009f_5_pal_ranges[] = { + { 16 * 141.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 464.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_temic_4009f_5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_4009f_5_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4039FR5_NTSC - TEMIC NTSC ------------ */ + +static struct tuner_range tuner_temic_4x3x_f_5_ntsc_ranges[] = { + { 16 * 158.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 453.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_temic_4039fr5_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_temic_4x3x_f_5_ntsc_ranges, + .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4046FM5 - TEMIC PAL ------------ */ + +static struct tuner_params tuner_temic_4046fm5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_40x6f_5_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_PAL_DK - Philips PAL ------------ */ + +static struct tuner_params tuner_philips_pal_dk_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_pal_ranges, + .count = ARRAY_SIZE(tuner_lg_pal_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_FQ1216ME - Philips PAL ------------ */ + +static struct tuner_params tuner_philips_fq1216me_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_pal_ranges, + .count = ARRAY_SIZE(tuner_lg_pal_ranges), + .has_tda9887 = 1, + .port1_active = 1, + .port2_active = 1, + .port2_invert_for_secam_lc = 1, + }, +}; + +/* ------------ TUNER_LG_PAL_I_FM - LGINNOTEK PAL_I ------------ */ + +static struct tuner_params tuner_lg_pal_i_fm_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_pal_ranges, + .count = ARRAY_SIZE(tuner_lg_pal_ranges), + }, +}; + +/* ------------ TUNER_LG_PAL_I - LGINNOTEK PAL_I ------------ */ + +static struct tuner_params tuner_lg_pal_i_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_pal_ranges, + .count = ARRAY_SIZE(tuner_lg_pal_ranges), + }, +}; + +/* ------------ TUNER_LG_NTSC_FM - LGINNOTEK NTSC ------------ */ + +static struct tuner_range tuner_lg_ntsc_fm_ranges[] = { + { 16 * 210.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 497.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_lg_ntsc_fm_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_lg_ntsc_fm_ranges, + .count = ARRAY_SIZE(tuner_lg_ntsc_fm_ranges), + }, +}; + +/* ------------ TUNER_LG_PAL_FM - LGINNOTEK PAL ------------ */ + +static struct tuner_params tuner_lg_pal_fm_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_pal_ranges, + .count = ARRAY_SIZE(tuner_lg_pal_ranges), + }, +}; + +/* ------------ TUNER_LG_PAL - LGINNOTEK PAL ------------ */ + +static struct tuner_params tuner_lg_pal_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_pal_ranges, + .count = ARRAY_SIZE(tuner_lg_pal_ranges), + }, +}; + +/* 30-39 */ +/* ------------ TUNER_TEMIC_4009FN5_MULTI_PAL_FM - TEMIC PAL ------------ */ + +static struct tuner_params tuner_temic_4009_fn5_multi_pal_fm_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_4009f_5_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), + }, +}; + +/* ------------ TUNER_SHARP_2U5JF5540_NTSC - SHARP NTSC ------------ */ + +static struct tuner_range tuner_sharp_2u5jf5540_ntsc_ranges[] = { + { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 317.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_params tuner_sharp_2u5jf5540_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_sharp_2u5jf5540_ntsc_ranges, + .count = ARRAY_SIZE(tuner_sharp_2u5jf5540_ntsc_ranges), + }, +}; + +/* ------------ TUNER_Samsung_PAL_TCPM9091PD27 - Samsung PAL ------------ */ + +static struct tuner_range tuner_samsung_pal_tcpm9091pd27_ranges[] = { + { 16 * 169 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 464 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_samsung_pal_tcpm9091pd27_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_samsung_pal_tcpm9091pd27_ranges, + .count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4106FH5 - TEMIC PAL ------------ */ + +static struct tuner_params tuner_temic_4106fh5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_4009f_5_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4012FY5 - TEMIC PAL ------------ */ + +static struct tuner_params tuner_temic_4012fy5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_pal_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4136FY5 - TEMIC NTSC ------------ */ + +static struct tuner_params tuner_temic_4136_fy5_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_temic_4x3x_f_5_ntsc_ranges, + .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges), + }, +}; + +/* ------------ TUNER_LG_PAL_NEW_TAPC - LGINNOTEK PAL ------------ */ + +static struct tuner_range tuner_lg_new_tapc_ranges[] = { + { 16 * 170.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 450.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_params tuner_lg_pal_new_tapc_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_new_tapc_ranges, + .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_FM1216ME_MK3 - Philips PAL ------------ */ + +static struct tuner_range tuner_fm1216me_mk3_pal_ranges[] = { + { 16 * 158.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 442.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, +}; + +static struct tuner_params tuner_fm1216me_mk3_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_fm1216me_mk3_pal_ranges, + .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges), + .cb_first_if_lower_freq = 1, + .has_tda9887 = 1, + .port1_active = 1, + .port2_active = 1, + .port2_invert_for_secam_lc = 1, + .port1_fm_high_sensitivity = 1, + .default_top_mid = -2, + .default_top_secam_mid = -2, + .default_top_secam_high = -2, + }, +}; + +/* ------------ TUNER_PHILIPS_FM1216MK5 - Philips PAL ------------ */ + +static struct tuner_range tuner_fm1216mk5_pal_ranges[] = { + { 16 * 158.00 /*MHz*/, 0xce, 0x01, }, + { 16 * 441.00 /*MHz*/, 0xce, 0x02, }, + { 16 * 864.00 , 0xce, 0x04, }, +}; + +static struct tuner_params tuner_fm1216mk5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_fm1216mk5_pal_ranges, + .count = ARRAY_SIZE(tuner_fm1216mk5_pal_ranges), + .cb_first_if_lower_freq = 1, + .has_tda9887 = 1, + .port1_active = 1, + .port2_active = 1, + .port2_invert_for_secam_lc = 1, + .port1_fm_high_sensitivity = 1, + .default_top_mid = -2, + .default_top_secam_mid = -2, + .default_top_secam_high = -2, + }, +}; + +/* ------------ TUNER_LG_NTSC_NEW_TAPC - LGINNOTEK NTSC ------------ */ + +static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_lg_new_tapc_ranges, + .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), + }, +}; + +/* 40-49 */ +/* ------------ TUNER_HITACHI_NTSC - HITACHI NTSC ------------ */ + +static struct tuner_params tuner_hitachi_ntsc_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_lg_new_tapc_ranges, + .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_PAL_MK - Philips PAL ------------ */ + +static struct tuner_range tuner_philips_pal_mk_pal_ranges[] = { + { 16 * 140.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0xc2, }, + { 16 * 999.99 , 0x8e, 0xcf, }, +}; + +static struct tuner_params tuner_philips_pal_mk_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_philips_pal_mk_pal_ranges, + .count = ARRAY_SIZE(tuner_philips_pal_mk_pal_ranges), + }, +}; + +/* ---- TUNER_PHILIPS_FCV1236D - Philips FCV1236D (ATSC/NTSC) ---- */ + +static struct tuner_range tuner_philips_fcv1236d_ntsc_ranges[] = { + { 16 * 157.25 /*MHz*/, 0x8e, 0xa2, }, + { 16 * 451.25 /*MHz*/, 0x8e, 0x92, }, + { 16 * 999.99 , 0x8e, 0x32, }, +}; + +static struct tuner_range tuner_philips_fcv1236d_atsc_ranges[] = { + { 16 * 159.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 453.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_philips_fcv1236d_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_philips_fcv1236d_ntsc_ranges, + .count = ARRAY_SIZE(tuner_philips_fcv1236d_ntsc_ranges), + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_philips_fcv1236d_atsc_ranges, + .count = ARRAY_SIZE(tuner_philips_fcv1236d_atsc_ranges), + .iffreq = 16 * 44.00, + }, +}; + +/* ------------ TUNER_PHILIPS_FM1236_MK3 - Philips NTSC ------------ */ + +static struct tuner_range tuner_fm1236_mk3_ntsc_ranges[] = { + { 16 * 160.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 442.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, +}; + +static struct tuner_params tuner_fm1236_mk3_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_fm1236_mk3_ntsc_ranges, + .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), + .cb_first_if_lower_freq = 1, + .has_tda9887 = 1, + .port1_active = 1, + .port2_active = 1, + .port1_fm_high_sensitivity = 1, + }, +}; + +/* ------------ TUNER_PHILIPS_4IN1 - Philips NTSC ------------ */ + +static struct tuner_params tuner_philips_4in1_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_fm1236_mk3_ntsc_ranges, + .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), + }, +}; + +/* ------------ TUNER_MICROTUNE_4049FM5 - Microtune PAL ------------ */ + +static struct tuner_params tuner_microtune_4049_fm5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_4009f_5_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), + .has_tda9887 = 1, + .port1_invert_for_secam_lc = 1, + .default_pll_gating_18 = 1, + .fm_gain_normal=1, + .radio_if = 1, /* 33.3 MHz */ + }, +}; + +/* ------------ TUNER_PANASONIC_VP27 - Panasonic NTSC ------------ */ + +static struct tuner_range tuner_panasonic_vp27_ntsc_ranges[] = { + { 16 * 160.00 /*MHz*/, 0xce, 0x01, }, + { 16 * 454.00 /*MHz*/, 0xce, 0x02, }, + { 16 * 999.99 , 0xce, 0x08, }, +}; + +static struct tuner_params tuner_panasonic_vp27_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_panasonic_vp27_ntsc_ranges, + .count = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges), + .has_tda9887 = 1, + .intercarrier_mode = 1, + .default_top_low = -3, + .default_top_mid = -3, + .default_top_high = -3, + }, +}; + +/* ------------ TUNER_TNF_8831BGFF - Philips PAL ------------ */ + +static struct tuner_range tuner_tnf_8831bgff_pal_ranges[] = { + { 16 * 161.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_tnf_8831bgff_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_tnf_8831bgff_pal_ranges, + .count = ARRAY_SIZE(tuner_tnf_8831bgff_pal_ranges), + }, +}; + +/* ------------ TUNER_MICROTUNE_4042FI5 - Microtune NTSC ------------ */ + +static struct tuner_range tuner_microtune_4042fi5_ntsc_ranges[] = { + { 16 * 162.00 /*MHz*/, 0x8e, 0xa2, }, + { 16 * 457.00 /*MHz*/, 0x8e, 0x94, }, + { 16 * 999.99 , 0x8e, 0x31, }, +}; + +static struct tuner_range tuner_microtune_4042fi5_atsc_ranges[] = { + { 16 * 162.00 /*MHz*/, 0x8e, 0xa1, }, + { 16 * 457.00 /*MHz*/, 0x8e, 0x91, }, + { 16 * 999.99 , 0x8e, 0x31, }, +}; + +static struct tuner_params tuner_microtune_4042fi5_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_microtune_4042fi5_ntsc_ranges, + .count = ARRAY_SIZE(tuner_microtune_4042fi5_ntsc_ranges), + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_microtune_4042fi5_atsc_ranges, + .count = ARRAY_SIZE(tuner_microtune_4042fi5_atsc_ranges), + .iffreq = 16 * 44.00 /*MHz*/, + }, +}; + +/* 50-59 */ +/* ------------ TUNER_TCL_2002N - TCL NTSC ------------ */ + +static struct tuner_range tuner_tcl_2002n_ntsc_ranges[] = { + { 16 * 172.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 448.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_params tuner_tcl_2002n_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_tcl_2002n_ntsc_ranges, + .count = ARRAY_SIZE(tuner_tcl_2002n_ntsc_ranges), + .cb_first_if_lower_freq = 1, + }, +}; + +/* ------------ TUNER_PHILIPS_FM1256_IH3 - Philips PAL ------------ */ + +static struct tuner_params tuner_philips_fm1256_ih3_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_fm1236_mk3_ntsc_ranges, + .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), + .radio_if = 1, /* 33.3 MHz */ + }, +}; + +/* ------------ TUNER_THOMSON_DTT7610 - THOMSON ATSC ------------ */ + +/* single range used for both ntsc and atsc */ +static struct tuner_range tuner_thomson_dtt7610_ntsc_ranges[] = { + { 16 * 157.25 /*MHz*/, 0x8e, 0x39, }, + { 16 * 454.00 /*MHz*/, 0x8e, 0x3a, }, + { 16 * 999.99 , 0x8e, 0x3c, }, +}; + +static struct tuner_params tuner_thomson_dtt7610_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_thomson_dtt7610_ntsc_ranges, + .count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges), + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_thomson_dtt7610_ntsc_ranges, + .count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges), + .iffreq = 16 * 44.00 /*MHz*/, + }, +}; + +/* ------------ TUNER_PHILIPS_FQ1286 - Philips NTSC ------------ */ + +static struct tuner_range tuner_philips_fq1286_ntsc_ranges[] = { + { 16 * 160.00 /*MHz*/, 0x8e, 0x41, }, + { 16 * 454.00 /*MHz*/, 0x8e, 0x42, }, + { 16 * 999.99 , 0x8e, 0x04, }, +}; + +static struct tuner_params tuner_philips_fq1286_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_philips_fq1286_ntsc_ranges, + .count = ARRAY_SIZE(tuner_philips_fq1286_ntsc_ranges), + }, +}; + +/* ------------ TUNER_TCL_2002MB - TCL PAL ------------ */ + +static struct tuner_range tuner_tcl_2002mb_pal_ranges[] = { + { 16 * 170.00 /*MHz*/, 0xce, 0x01, }, + { 16 * 450.00 /*MHz*/, 0xce, 0x02, }, + { 16 * 999.99 , 0xce, 0x08, }, +}; + +static struct tuner_params tuner_tcl_2002mb_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_tcl_2002mb_pal_ranges, + .count = ARRAY_SIZE(tuner_tcl_2002mb_pal_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_FQ1216AME_MK4 - Philips PAL ------------ */ + +static struct tuner_range tuner_philips_fq12_6a___mk4_pal_ranges[] = { + { 16 * 160.00 /*MHz*/, 0xce, 0x01, }, + { 16 * 442.00 /*MHz*/, 0xce, 0x02, }, + { 16 * 999.99 , 0xce, 0x04, }, +}; + +static struct tuner_params tuner_philips_fq1216ame_mk4_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_philips_fq12_6a___mk4_pal_ranges, + .count = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_pal_ranges), + .has_tda9887 = 1, + .port1_active = 1, + .port2_invert_for_secam_lc = 1, + .default_top_mid = -2, + .default_top_secam_low = -2, + .default_top_secam_mid = -2, + .default_top_secam_high = -2, + }, +}; + +/* ------------ TUNER_PHILIPS_FQ1236A_MK4 - Philips NTSC ------------ */ + +static struct tuner_params tuner_philips_fq1236a_mk4_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_fm1236_mk3_ntsc_ranges, + .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), + }, +}; + +/* ------------ TUNER_YMEC_TVF_8531MF - Philips NTSC ------------ */ + +static struct tuner_params tuner_ymec_tvf_8531mf_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_philips_ntsc_m_ranges, + .count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges), + }, +}; + +/* ------------ TUNER_YMEC_TVF_5533MF - Philips NTSC ------------ */ + +static struct tuner_range tuner_ymec_tvf_5533mf_ntsc_ranges[] = { + { 16 * 160.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 454.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, +}; + +static struct tuner_params tuner_ymec_tvf_5533mf_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_ymec_tvf_5533mf_ntsc_ranges, + .count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_ntsc_ranges), + }, +}; + +/* 60-69 */ +/* ------------ TUNER_THOMSON_DTT761X - THOMSON ATSC ------------ */ +/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ + +static struct tuner_range tuner_thomson_dtt761x_ntsc_ranges[] = { + { 16 * 145.25 /*MHz*/, 0x8e, 0x39, }, + { 16 * 415.25 /*MHz*/, 0x8e, 0x3a, }, + { 16 * 999.99 , 0x8e, 0x3c, }, +}; + +static struct tuner_range tuner_thomson_dtt761x_atsc_ranges[] = { + { 16 * 147.00 /*MHz*/, 0x8e, 0x39, }, + { 16 * 417.00 /*MHz*/, 0x8e, 0x3a, }, + { 16 * 999.99 , 0x8e, 0x3c, }, +}; + +static struct tuner_params tuner_thomson_dtt761x_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_thomson_dtt761x_ntsc_ranges, + .count = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges), + .has_tda9887 = 1, + .fm_gain_normal = 1, + .radio_if = 2, /* 41.3 MHz */ + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_thomson_dtt761x_atsc_ranges, + .count = ARRAY_SIZE(tuner_thomson_dtt761x_atsc_ranges), + .iffreq = 16 * 44.00, /*MHz*/ + }, +}; + +/* ------------ TUNER_TENA_9533_DI - Philips PAL ------------ */ + +static struct tuner_range tuner_tena_9533_di_pal_ranges[] = { + { 16 * 160.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 464.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, +}; + +static struct tuner_params tuner_tena_9533_di_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_tena_9533_di_pal_ranges, + .count = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges), + }, +}; + +/* ------------ TUNER_TENA_TNF_5337 - Tena tnf5337MFD STD M/N ------------ */ + +static struct tuner_range tuner_tena_tnf_5337_ntsc_ranges[] = { + { 16 * 166.25 /*MHz*/, 0x86, 0x01, }, + { 16 * 466.25 /*MHz*/, 0x86, 0x02, }, + { 16 * 999.99 , 0x86, 0x08, }, +}; + +static struct tuner_params tuner_tena_tnf_5337_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_tena_tnf_5337_ntsc_ranges, + .count = ARRAY_SIZE(tuner_tena_tnf_5337_ntsc_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_FMD1216ME(X)_MK3 - Philips PAL ------------ */ + +static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = { + { 16 * 160.00 /*MHz*/, 0x86, 0x51, }, + { 16 * 442.00 /*MHz*/, 0x86, 0x52, }, + { 16 * 999.99 , 0x86, 0x54, }, +}; + +static struct tuner_range tuner_philips_fmd1216me_mk3_dvb_ranges[] = { + { 16 * 143.87 /*MHz*/, 0xbc, 0x41 }, + { 16 * 158.87 /*MHz*/, 0xf4, 0x41 }, + { 16 * 329.87 /*MHz*/, 0xbc, 0x42 }, + { 16 * 441.87 /*MHz*/, 0xf4, 0x42 }, + { 16 * 625.87 /*MHz*/, 0xbc, 0x44 }, + { 16 * 803.87 /*MHz*/, 0xf4, 0x44 }, + { 16 * 999.99 , 0xfc, 0x44 }, +}; + +static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_philips_fmd1216me_mk3_pal_ranges, + .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges), + .has_tda9887 = 1, + .port1_active = 1, + .port2_active = 1, + .port2_fm_high_sensitivity = 1, + .port2_invert_for_secam_lc = 1, + .port1_set_for_fm_mono = 1, + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges, + .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges), + .iffreq = 16 * 36.125, /*MHz*/ + }, +}; + +static struct tuner_params tuner_philips_fmd1216mex_mk3_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_philips_fmd1216me_mk3_pal_ranges, + .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges), + .has_tda9887 = 1, + .port1_active = 1, + .port2_active = 1, + .port2_fm_high_sensitivity = 1, + .port2_invert_for_secam_lc = 1, + .port1_set_for_fm_mono = 1, + .radio_if = 1, + .fm_gain_normal = 1, + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges, + .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges), + .iffreq = 16 * 36.125, /*MHz*/ + }, +}; + +/* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */ + +static struct tuner_range tuner_tua6034_ntsc_ranges[] = { + { 16 * 165.00 /*MHz*/, 0x8e, 0x01 }, + { 16 * 450.00 /*MHz*/, 0x8e, 0x02 }, + { 16 * 999.99 , 0x8e, 0x04 }, +}; + +static struct tuner_range tuner_tua6034_atsc_ranges[] = { + { 16 * 165.00 /*MHz*/, 0xce, 0x01 }, + { 16 * 450.00 /*MHz*/, 0xce, 0x02 }, + { 16 * 999.99 , 0xce, 0x04 }, +}; + +static struct tuner_params tuner_lg_tdvs_h06xf_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_tua6034_ntsc_ranges, + .count = ARRAY_SIZE(tuner_tua6034_ntsc_ranges), + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_tua6034_atsc_ranges, + .count = ARRAY_SIZE(tuner_tua6034_atsc_ranges), + .iffreq = 16 * 44.00, + }, +}; + +/* ------------ TUNER_YMEC_TVF66T5_B_DFF - Philips PAL ------------ */ + +static struct tuner_range tuner_ymec_tvf66t5_b_dff_pal_ranges[] = { + { 16 * 160.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 464.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_params tuner_ymec_tvf66t5_b_dff_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_ymec_tvf66t5_b_dff_pal_ranges, + .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_pal_ranges), + }, +}; + +/* ------------ TUNER_LG_NTSC_TALN_MINI - LGINNOTEK NTSC ------------ */ + +static struct tuner_range tuner_lg_taln_ntsc_ranges[] = { + { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 373.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_range tuner_lg_taln_pal_secam_ranges[] = { + { 16 * 150.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 425.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_params tuner_lg_taln_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_lg_taln_ntsc_ranges, + .count = ARRAY_SIZE(tuner_lg_taln_ntsc_ranges), + },{ + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_taln_pal_secam_ranges, + .count = ARRAY_SIZE(tuner_lg_taln_pal_secam_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_TD1316 - Philips PAL ------------ */ + +static struct tuner_range tuner_philips_td1316_pal_ranges[] = { + { 16 * 160.00 /*MHz*/, 0xc8, 0xa1, }, + { 16 * 442.00 /*MHz*/, 0xc8, 0xa2, }, + { 16 * 999.99 , 0xc8, 0xa4, }, +}; + +static struct tuner_range tuner_philips_td1316_dvb_ranges[] = { + { 16 * 93.834 /*MHz*/, 0xca, 0x60, }, + { 16 * 123.834 /*MHz*/, 0xca, 0xa0, }, + { 16 * 163.834 /*MHz*/, 0xca, 0xc0, }, + { 16 * 253.834 /*MHz*/, 0xca, 0x60, }, + { 16 * 383.834 /*MHz*/, 0xca, 0xa0, }, + { 16 * 443.834 /*MHz*/, 0xca, 0xc0, }, + { 16 * 583.834 /*MHz*/, 0xca, 0x60, }, + { 16 * 793.834 /*MHz*/, 0xca, 0xa0, }, + { 16 * 999.999 , 0xca, 0xe0, }, +}; + +static struct tuner_params tuner_philips_td1316_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_philips_td1316_pal_ranges, + .count = ARRAY_SIZE(tuner_philips_td1316_pal_ranges), + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_philips_td1316_dvb_ranges, + .count = ARRAY_SIZE(tuner_philips_td1316_dvb_ranges), + .iffreq = 16 * 36.166667 /*MHz*/, + }, +}; + +/* ------------ TUNER_PHILIPS_TUV1236D - Philips ATSC ------------ */ + +static struct tuner_range tuner_tuv1236d_ntsc_ranges[] = { + { 16 * 157.25 /*MHz*/, 0xce, 0x01, }, + { 16 * 454.00 /*MHz*/, 0xce, 0x02, }, + { 16 * 999.99 , 0xce, 0x04, }, +}; + +static struct tuner_range tuner_tuv1236d_atsc_ranges[] = { + { 16 * 157.25 /*MHz*/, 0xc6, 0x41, }, + { 16 * 454.00 /*MHz*/, 0xc6, 0x42, }, + { 16 * 999.99 , 0xc6, 0x44, }, +}; + +static struct tuner_params tuner_tuv1236d_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_tuv1236d_ntsc_ranges, + .count = ARRAY_SIZE(tuner_tuv1236d_ntsc_ranges), + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_tuv1236d_atsc_ranges, + .count = ARRAY_SIZE(tuner_tuv1236d_atsc_ranges), + .iffreq = 16 * 44.00, + }, +}; + +/* ------------ TUNER_TNF_xxx5 - Texas Instruments--------- */ +/* This is known to work with Tenna TVF58t5-MFF and TVF5835 MFF + * but it is expected to work also with other Tenna/Ymec + * models based on TI SN 761677 chip on both PAL and NTSC + */ + +static struct tuner_range tuner_tnf_5335_d_if_pal_ranges[] = { + { 16 * 168.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 471.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_range tuner_tnf_5335mf_ntsc_ranges[] = { + { 16 * 169.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 469.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_params tuner_tnf_5335mf_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_tnf_5335mf_ntsc_ranges, + .count = ARRAY_SIZE(tuner_tnf_5335mf_ntsc_ranges), + }, + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_tnf_5335_d_if_pal_ranges, + .count = ARRAY_SIZE(tuner_tnf_5335_d_if_pal_ranges), + }, +}; + +/* 70-79 */ +/* ------------ TUNER_SAMSUNG_TCPN_2121P30A - Samsung NTSC ------------ */ + +/* '+ 4' turns on the Low Noise Amplifier */ +static struct tuner_range tuner_samsung_tcpn_2121p30a_ntsc_ranges[] = { + { 16 * 130.00 /*MHz*/, 0xce, 0x01 + 4, }, + { 16 * 364.50 /*MHz*/, 0xce, 0x02 + 4, }, + { 16 * 999.99 , 0xce, 0x08 + 4, }, +}; + +static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges, + .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges), + }, +}; + +/* ------------ TUNER_THOMSON_FE6600 - DViCO Hybrid PAL ------------ */ + +static struct tuner_range tuner_thomson_fe6600_pal_ranges[] = { + { 16 * 160.00 /*MHz*/, 0xfe, 0x11, }, + { 16 * 442.00 /*MHz*/, 0xf6, 0x12, }, + { 16 * 999.99 , 0xf6, 0x18, }, +}; + +static struct tuner_range tuner_thomson_fe6600_dvb_ranges[] = { + { 16 * 250.00 /*MHz*/, 0xb4, 0x12, }, + { 16 * 455.00 /*MHz*/, 0xfe, 0x11, }, + { 16 * 775.50 /*MHz*/, 0xbc, 0x18, }, + { 16 * 999.99 , 0xf4, 0x18, }, +}; + +static struct tuner_params tuner_thomson_fe6600_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_thomson_fe6600_pal_ranges, + .count = ARRAY_SIZE(tuner_thomson_fe6600_pal_ranges), + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_thomson_fe6600_dvb_ranges, + .count = ARRAY_SIZE(tuner_thomson_fe6600_dvb_ranges), + .iffreq = 16 * 36.125 /*MHz*/, + }, +}; + +/* ------------ TUNER_SAMSUNG_TCPG_6121P30A - Samsung PAL ------------ */ + +/* '+ 4' turns on the Low Noise Amplifier */ +static struct tuner_range tuner_samsung_tcpg_6121p30a_pal_ranges[] = { + { 16 * 146.25 /*MHz*/, 0xce, 0x01 + 4, }, + { 16 * 428.50 /*MHz*/, 0xce, 0x02 + 4, }, + { 16 * 999.99 , 0xce, 0x08 + 4, }, +}; + +static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_samsung_tcpg_6121p30a_pal_ranges, + .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_pal_ranges), + .has_tda9887 = 1, + .port1_active = 1, + .port2_active = 1, + .port2_invert_for_secam_lc = 1, + }, +}; + +/* ------------ TUNER_TCL_MF02GIP-5N-E - TCL MF02GIP-5N ------------ */ + +static struct tuner_range tuner_tcl_mf02gip_5n_ntsc_ranges[] = { + { 16 * 172.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 448.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, +}; + +static struct tuner_params tuner_tcl_mf02gip_5n_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_tcl_mf02gip_5n_ntsc_ranges, + .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_ntsc_ranges), + .cb_first_if_lower_freq = 1, + }, +}; + +/* 80-89 */ +/* --------- TUNER_PHILIPS_FQ1216LME_MK3 -- active loopthrough, no FM ------- */ + +static struct tuner_params tuner_fq1216lme_mk3_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_fm1216me_mk3_pal_ranges, + .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges), + .cb_first_if_lower_freq = 1, /* not specified, but safe to do */ + .has_tda9887 = 1, /* TDA9886 */ + .port1_active = 1, + .port2_active = 1, + .port2_invert_for_secam_lc = 1, + .default_top_low = 4, + .default_top_mid = 4, + .default_top_high = 4, + .default_top_secam_low = 4, + .default_top_secam_mid = 4, + .default_top_secam_high = 4, + }, +}; + +/* ----- TUNER_PARTSNIC_PTI_5NF05 - Partsnic (Daewoo) PTI-5NF05 NTSC ----- */ + +static struct tuner_range tuner_partsnic_pti_5nf05_ranges[] = { + /* The datasheet specified channel ranges and the bandswitch byte */ + /* The control byte value of 0x8e is just a guess */ + { 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, /* Channels 2 - B */ + { 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, /* Channels C - W+11 */ + { 16 * 999.99 , 0x8e, 0x08, }, /* Channels W+12 - 69 */ +}; + +static struct tuner_params tuner_partsnic_pti_5nf05_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_partsnic_pti_5nf05_ranges, + .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_ranges), + .cb_first_if_lower_freq = 1, /* not specified but safe to do */ + }, +}; + +/* --------- TUNER_PHILIPS_CU1216L - DVB-C NIM ------------------------- */ + +static struct tuner_range tuner_cu1216l_ranges[] = { + { 16 * 160.25 /*MHz*/, 0xce, 0x01 }, + { 16 * 444.25 /*MHz*/, 0xce, 0x02 }, + { 16 * 999.99 , 0xce, 0x04 }, +}; + +static struct tuner_params tuner_philips_cu1216l_params[] = { + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_cu1216l_ranges, + .count = ARRAY_SIZE(tuner_cu1216l_ranges), + .iffreq = 16 * 36.125, /*MHz*/ + }, +}; + +/* ---------------------- TUNER_SONY_BTF_PXN01Z ------------------------ */ + +static struct tuner_range tuner_sony_btf_pxn01z_ranges[] = { + { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, +}; + +static struct tuner_params tuner_sony_btf_pxn01z_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_sony_btf_pxn01z_ranges, + .count = ARRAY_SIZE(tuner_sony_btf_pxn01z_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_FQ1236_MK5 - Philips NTSC ------------ */ + +static struct tuner_params tuner_philips_fq1236_mk5_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_fm1236_mk3_ntsc_ranges, + .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), + .has_tda9887 = 1, /* TDA9885, no FM radio */ + }, +}; + +/* --------------------------------------------------------------------- */ + +struct tunertype tuners[] = { + /* 0-9 */ + [TUNER_TEMIC_PAL] = { /* TEMIC PAL */ + .name = "Temic PAL (4002 FH5)", + .params = tuner_temic_pal_params, + .count = ARRAY_SIZE(tuner_temic_pal_params), + }, + [TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */ + .name = "Philips PAL_I (FI1246 and compatibles)", + .params = tuner_philips_pal_i_params, + .count = ARRAY_SIZE(tuner_philips_pal_i_params), + }, + [TUNER_PHILIPS_NTSC] = { /* Philips NTSC */ + .name = "Philips NTSC (FI1236,FM1236 and compatibles)", + .params = tuner_philips_ntsc_params, + .count = ARRAY_SIZE(tuner_philips_ntsc_params), + }, + [TUNER_PHILIPS_SECAM] = { /* Philips SECAM */ + .name = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", + .params = tuner_philips_secam_params, + .count = ARRAY_SIZE(tuner_philips_secam_params), + }, + [TUNER_ABSENT] = { /* Tuner Absent */ + .name = "NoTuner", + }, + [TUNER_PHILIPS_PAL] = { /* Philips PAL */ + .name = "Philips PAL_BG (FI1216 and compatibles)", + .params = tuner_philips_pal_params, + .count = ARRAY_SIZE(tuner_philips_pal_params), + }, + [TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */ + .name = "Temic NTSC (4032 FY5)", + .params = tuner_temic_ntsc_params, + .count = ARRAY_SIZE(tuner_temic_ntsc_params), + }, + [TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */ + .name = "Temic PAL_I (4062 FY5)", + .params = tuner_temic_pal_i_params, + .count = ARRAY_SIZE(tuner_temic_pal_i_params), + }, + [TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */ + .name = "Temic NTSC (4036 FY5)", + .params = tuner_temic_4036fy5_ntsc_params, + .count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_params), + }, + [TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */ + .name = "Alps HSBH1", + .params = tuner_alps_tsbh1_ntsc_params, + .count = ARRAY_SIZE(tuner_alps_tsbh1_ntsc_params), + }, + + /* 10-19 */ + [TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */ + .name = "Alps TSBE1", + .params = tuner_alps_tsb_1_params, + .count = ARRAY_SIZE(tuner_alps_tsb_1_params), + }, + [TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */ + .name = "Alps TSBB5", + .params = tuner_alps_tsbb5_params, + .count = ARRAY_SIZE(tuner_alps_tsbb5_params), + }, + [TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */ + .name = "Alps TSBE5", + .params = tuner_alps_tsbe5_params, + .count = ARRAY_SIZE(tuner_alps_tsbe5_params), + }, + [TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */ + .name = "Alps TSBC5", + .params = tuner_alps_tsbc5_params, + .count = ARRAY_SIZE(tuner_alps_tsbc5_params), + }, + [TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */ + .name = "Temic PAL_BG (4006FH5)", + .params = tuner_temic_4006fh5_params, + .count = ARRAY_SIZE(tuner_temic_4006fh5_params), + }, + [TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */ + .name = "Alps TSCH6", + .params = tuner_alps_tshc6_params, + .count = ARRAY_SIZE(tuner_alps_tshc6_params), + }, + [TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */ + .name = "Temic PAL_DK (4016 FY5)", + .params = tuner_temic_pal_dk_params, + .count = ARRAY_SIZE(tuner_temic_pal_dk_params), + }, + [TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */ + .name = "Philips NTSC_M (MK2)", + .params = tuner_philips_ntsc_m_params, + .count = ARRAY_SIZE(tuner_philips_ntsc_m_params), + }, + [TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */ + .name = "Temic PAL_I (4066 FY5)", + .params = tuner_temic_4066fy5_pal_i_params, + .count = ARRAY_SIZE(tuner_temic_4066fy5_pal_i_params), + }, + [TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */ + .name = "Temic PAL* auto (4006 FN5)", + .params = tuner_temic_4006fn5_multi_params, + .count = ARRAY_SIZE(tuner_temic_4006fn5_multi_params), + }, + + /* 20-29 */ + [TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */ + .name = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", + .params = tuner_temic_4009f_5_params, + .count = ARRAY_SIZE(tuner_temic_4009f_5_params), + }, + [TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */ + .name = "Temic NTSC (4039 FR5)", + .params = tuner_temic_4039fr5_params, + .count = ARRAY_SIZE(tuner_temic_4039fr5_params), + }, + [TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */ + .name = "Temic PAL/SECAM multi (4046 FM5)", + .params = tuner_temic_4046fm5_params, + .count = ARRAY_SIZE(tuner_temic_4046fm5_params), + }, + [TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */ + .name = "Philips PAL_DK (FI1256 and compatibles)", + .params = tuner_philips_pal_dk_params, + .count = ARRAY_SIZE(tuner_philips_pal_dk_params), + }, + [TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */ + .name = "Philips PAL/SECAM multi (FQ1216ME)", + .params = tuner_philips_fq1216me_params, + .count = ARRAY_SIZE(tuner_philips_fq1216me_params), + }, + [TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */ + .name = "LG PAL_I+FM (TAPC-I001D)", + .params = tuner_lg_pal_i_fm_params, + .count = ARRAY_SIZE(tuner_lg_pal_i_fm_params), + }, + [TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */ + .name = "LG PAL_I (TAPC-I701D)", + .params = tuner_lg_pal_i_params, + .count = ARRAY_SIZE(tuner_lg_pal_i_params), + }, + [TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */ + .name = "LG NTSC+FM (TPI8NSR01F)", + .params = tuner_lg_ntsc_fm_params, + .count = ARRAY_SIZE(tuner_lg_ntsc_fm_params), + }, + [TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */ + .name = "LG PAL_BG+FM (TPI8PSB01D)", + .params = tuner_lg_pal_fm_params, + .count = ARRAY_SIZE(tuner_lg_pal_fm_params), + }, + [TUNER_LG_PAL] = { /* LGINNOTEK PAL */ + .name = "LG PAL_BG (TPI8PSB11D)", + .params = tuner_lg_pal_params, + .count = ARRAY_SIZE(tuner_lg_pal_params), + }, + + /* 30-39 */ + [TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */ + .name = "Temic PAL* auto + FM (4009 FN5)", + .params = tuner_temic_4009_fn5_multi_pal_fm_params, + .count = ARRAY_SIZE(tuner_temic_4009_fn5_multi_pal_fm_params), + }, + [TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */ + .name = "SHARP NTSC_JP (2U5JF5540)", + .params = tuner_sharp_2u5jf5540_params, + .count = ARRAY_SIZE(tuner_sharp_2u5jf5540_params), + }, + [TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */ + .name = "Samsung PAL TCPM9091PD27", + .params = tuner_samsung_pal_tcpm9091pd27_params, + .count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_params), + }, + [TUNER_MT2032] = { /* Microtune PAL|NTSC */ + .name = "MT20xx universal", + /* see mt20xx.c for details */ }, + [TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */ + .name = "Temic PAL_BG (4106 FH5)", + .params = tuner_temic_4106fh5_params, + .count = ARRAY_SIZE(tuner_temic_4106fh5_params), + }, + [TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */ + .name = "Temic PAL_DK/SECAM_L (4012 FY5)", + .params = tuner_temic_4012fy5_params, + .count = ARRAY_SIZE(tuner_temic_4012fy5_params), + }, + [TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */ + .name = "Temic NTSC (4136 FY5)", + .params = tuner_temic_4136_fy5_params, + .count = ARRAY_SIZE(tuner_temic_4136_fy5_params), + }, + [TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */ + .name = "LG PAL (newer TAPC series)", + .params = tuner_lg_pal_new_tapc_params, + .count = ARRAY_SIZE(tuner_lg_pal_new_tapc_params), + }, + [TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */ + .name = "Philips PAL/SECAM multi (FM1216ME MK3)", + .params = tuner_fm1216me_mk3_params, + .count = ARRAY_SIZE(tuner_fm1216me_mk3_params), + }, + [TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */ + .name = "LG NTSC (newer TAPC series)", + .params = tuner_lg_ntsc_new_tapc_params, + .count = ARRAY_SIZE(tuner_lg_ntsc_new_tapc_params), + }, + + /* 40-49 */ + [TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */ + .name = "HITACHI V7-J180AT", + .params = tuner_hitachi_ntsc_params, + .count = ARRAY_SIZE(tuner_hitachi_ntsc_params), + }, + [TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */ + .name = "Philips PAL_MK (FI1216 MK)", + .params = tuner_philips_pal_mk_params, + .count = ARRAY_SIZE(tuner_philips_pal_mk_params), + }, + [TUNER_PHILIPS_FCV1236D] = { /* Philips ATSC */ + .name = "Philips FCV1236D ATSC/NTSC dual in", + .params = tuner_philips_fcv1236d_params, + .count = ARRAY_SIZE(tuner_philips_fcv1236d_params), + .min = 16 * 53.00, + .max = 16 * 803.00, + .stepsize = 62500, + }, + [TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */ + .name = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", + .params = tuner_fm1236_mk3_params, + .count = ARRAY_SIZE(tuner_fm1236_mk3_params), + }, + [TUNER_PHILIPS_4IN1] = { /* Philips NTSC */ + .name = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", + .params = tuner_philips_4in1_params, + .count = ARRAY_SIZE(tuner_philips_4in1_params), + }, + [TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */ + .name = "Microtune 4049 FM5", + .params = tuner_microtune_4049_fm5_params, + .count = ARRAY_SIZE(tuner_microtune_4049_fm5_params), + }, + [TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */ + .name = "Panasonic VP27s/ENGE4324D", + .params = tuner_panasonic_vp27_params, + .count = ARRAY_SIZE(tuner_panasonic_vp27_params), + }, + [TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */ + .name = "LG NTSC (TAPE series)", + .params = tuner_fm1236_mk3_params, + .count = ARRAY_SIZE(tuner_fm1236_mk3_params), + }, + [TUNER_TNF_8831BGFF] = { /* Philips PAL */ + .name = "Tenna TNF 8831 BGFF)", + .params = tuner_tnf_8831bgff_params, + .count = ARRAY_SIZE(tuner_tnf_8831bgff_params), + }, + [TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */ + .name = "Microtune 4042 FI5 ATSC/NTSC dual in", + .params = tuner_microtune_4042fi5_params, + .count = ARRAY_SIZE(tuner_microtune_4042fi5_params), + .min = 16 * 57.00, + .max = 16 * 858.00, + .stepsize = 62500, + }, + + /* 50-59 */ + [TUNER_TCL_2002N] = { /* TCL NTSC */ + .name = "TCL 2002N", + .params = tuner_tcl_2002n_params, + .count = ARRAY_SIZE(tuner_tcl_2002n_params), + }, + [TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */ + .name = "Philips PAL/SECAM_D (FM 1256 I-H3)", + .params = tuner_philips_fm1256_ih3_params, + .count = ARRAY_SIZE(tuner_philips_fm1256_ih3_params), + }, + [TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */ + .name = "Thomson DTT 7610 (ATSC/NTSC)", + .params = tuner_thomson_dtt7610_params, + .count = ARRAY_SIZE(tuner_thomson_dtt7610_params), + .min = 16 * 44.00, + .max = 16 * 958.00, + .stepsize = 62500, + }, + [TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */ + .name = "Philips FQ1286", + .params = tuner_philips_fq1286_params, + .count = ARRAY_SIZE(tuner_philips_fq1286_params), + }, + [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */ + .name = "Philips/NXP TDA 8290/8295 + 8275/8275A/18271", + /* see tda8290.c for details */ }, + [TUNER_TCL_2002MB] = { /* TCL PAL */ + .name = "TCL 2002MB", + .params = tuner_tcl_2002mb_params, + .count = ARRAY_SIZE(tuner_tcl_2002mb_params), + }, + [TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */ + .name = "Philips PAL/SECAM multi (FQ1216AME MK4)", + .params = tuner_philips_fq1216ame_mk4_params, + .count = ARRAY_SIZE(tuner_philips_fq1216ame_mk4_params), + }, + [TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */ + .name = "Philips FQ1236A MK4", + .params = tuner_philips_fq1236a_mk4_params, + .count = ARRAY_SIZE(tuner_philips_fq1236a_mk4_params), + }, + [TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */ + .name = "Ymec TVision TVF-8531MF/8831MF/8731MF", + .params = tuner_ymec_tvf_8531mf_params, + .count = ARRAY_SIZE(tuner_ymec_tvf_8531mf_params), + }, + [TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */ + .name = "Ymec TVision TVF-5533MF", + .params = tuner_ymec_tvf_5533mf_params, + .count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_params), + }, + + /* 60-69 */ + [TUNER_THOMSON_DTT761X] = { /* THOMSON ATSC */ + /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ + .name = "Thomson DTT 761X (ATSC/NTSC)", + .params = tuner_thomson_dtt761x_params, + .count = ARRAY_SIZE(tuner_thomson_dtt761x_params), + .min = 16 * 57.00, + .max = 16 * 863.00, + .stepsize = 62500, + .initdata = tua603x_agc103, + }, + [TUNER_TENA_9533_DI] = { /* Philips PAL */ + .name = "Tena TNF9533-D/IF/TNF9533-B/DF", + .params = tuner_tena_9533_di_params, + .count = ARRAY_SIZE(tuner_tena_9533_di_params), + }, + [TUNER_TEA5767] = { /* Philips RADIO */ + .name = "Philips TEA5767HN FM Radio", + /* see tea5767.c for details */ + }, + [TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */ + .name = "Philips FMD1216ME MK3 Hybrid Tuner", + .params = tuner_philips_fmd1216me_mk3_params, + .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params), + .min = 16 * 50.87, + .max = 16 * 858.00, + .stepsize = 166667, + .initdata = tua603x_agc112, + .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 }, + }, + [TUNER_LG_TDVS_H06XF] = { /* LGINNOTEK ATSC */ + .name = "LG TDVS-H06xF", /* H061F, H062F & H064F */ + .params = tuner_lg_tdvs_h06xf_params, + .count = ARRAY_SIZE(tuner_lg_tdvs_h06xf_params), + .min = 16 * 54.00, + .max = 16 * 863.00, + .stepsize = 62500, + .initdata = tua603x_agc103, + }, + [TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */ + .name = "Ymec TVF66T5-B/DFF", + .params = tuner_ymec_tvf66t5_b_dff_params, + .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_params), + }, + [TUNER_LG_TALN] = { /* LGINNOTEK NTSC / PAL / SECAM */ + .name = "LG TALN series", + .params = tuner_lg_taln_params, + .count = ARRAY_SIZE(tuner_lg_taln_params), + }, + [TUNER_PHILIPS_TD1316] = { /* Philips PAL */ + .name = "Philips TD1316 Hybrid Tuner", + .params = tuner_philips_td1316_params, + .count = ARRAY_SIZE(tuner_philips_td1316_params), + .min = 16 * 87.00, + .max = 16 * 895.00, + .stepsize = 166667, + }, + [TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */ + .name = "Philips TUV1236D ATSC/NTSC dual in", + .params = tuner_tuv1236d_params, + .count = ARRAY_SIZE(tuner_tuv1236d_params), + .min = 16 * 54.00, + .max = 16 * 864.00, + .stepsize = 62500, + }, + [TUNER_TNF_5335MF] = { /* Tenna PAL/NTSC */ + .name = "Tena TNF 5335 and similar models", + .params = tuner_tnf_5335mf_params, + .count = ARRAY_SIZE(tuner_tnf_5335mf_params), + }, + + /* 70-79 */ + [TUNER_SAMSUNG_TCPN_2121P30A] = { /* Samsung NTSC */ + .name = "Samsung TCPN 2121P30A", + .params = tuner_samsung_tcpn_2121p30a_params, + .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params), + }, + [TUNER_XC2028] = { /* Xceive 2028 */ + .name = "Xceive xc2028/xc3028 tuner", + /* see tuner-xc2028.c for details */ + }, + [TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */ + .name = "Thomson FE6600", + .params = tuner_thomson_fe6600_params, + .count = ARRAY_SIZE(tuner_thomson_fe6600_params), + .min = 16 * 44.25, + .max = 16 * 858.00, + .stepsize = 166667, + }, + [TUNER_SAMSUNG_TCPG_6121P30A] = { /* Samsung PAL */ + .name = "Samsung TCPG 6121P30A", + .params = tuner_samsung_tcpg_6121p30a_params, + .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_params), + }, + [TUNER_TDA9887] = { /* Philips TDA 9887 IF PLL Demodulator. + This chip is part of some modern tuners */ + .name = "Philips TDA988[5,6,7] IF PLL Demodulator", + /* see tda9887.c for details */ + }, + [TUNER_TEA5761] = { /* Philips RADIO */ + .name = "Philips TEA5761 FM Radio", + /* see tea5767.c for details */ + }, + [TUNER_XC5000] = { /* Xceive 5000 */ + .name = "Xceive 5000 tuner", + /* see xc5000.c for details */ + }, + [TUNER_XC4000] = { /* Xceive 4000 */ + .name = "Xceive 4000 tuner", + /* see xc4000.c for details */ + }, + [TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */ + .name = "TCL tuner MF02GIP-5N-E", + .params = tuner_tcl_mf02gip_5n_params, + .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params), + }, + [TUNER_PHILIPS_FMD1216MEX_MK3] = { /* Philips PAL */ + .name = "Philips FMD1216MEX MK3 Hybrid Tuner", + .params = tuner_philips_fmd1216mex_mk3_params, + .count = ARRAY_SIZE(tuner_philips_fmd1216mex_mk3_params), + .min = 16 * 50.87, + .max = 16 * 858.00, + .stepsize = 166667, + .initdata = tua603x_agc112, + .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 }, + }, + [TUNER_PHILIPS_FM1216MK5] = { /* Philips PAL */ + .name = "Philips PAL/SECAM multi (FM1216 MK5)", + .params = tuner_fm1216mk5_params, + .count = ARRAY_SIZE(tuner_fm1216mk5_params), + }, + + /* 80-89 */ + [TUNER_PHILIPS_FQ1216LME_MK3] = { /* PAL/SECAM, Loop-thru, no FM */ + .name = "Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough", + .params = tuner_fq1216lme_mk3_params, + .count = ARRAY_SIZE(tuner_fq1216lme_mk3_params), + }, + + [TUNER_PARTSNIC_PTI_5NF05] = { + .name = "Partsnic (Daewoo) PTI-5NF05", + .params = tuner_partsnic_pti_5nf05_params, + .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_params), + }, + [TUNER_PHILIPS_CU1216L] = { + .name = "Philips CU1216L", + .params = tuner_philips_cu1216l_params, + .count = ARRAY_SIZE(tuner_philips_cu1216l_params), + .stepsize = 62500, + }, + [TUNER_NXP_TDA18271] = { + .name = "NXP TDA18271", + /* see tda18271-fe.c for details */ + }, + [TUNER_SONY_BTF_PXN01Z] = { + .name = "Sony BTF-Pxn01Z", + .params = tuner_sony_btf_pxn01z_params, + .count = ARRAY_SIZE(tuner_sony_btf_pxn01z_params), + }, + [TUNER_PHILIPS_FQ1236_MK5] = { /* NTSC, TDA9885, no FM radio */ + .name = "Philips FQ1236 MK5", + .params = tuner_philips_fq1236_mk5_params, + .count = ARRAY_SIZE(tuner_philips_fq1236_mk5_params), + }, + [TUNER_TENA_TNF_5337] = { /* Tena 5337 MFD */ + .name = "Tena TNF5337 MFD", + .params = tuner_tena_tnf_5337_params, + .count = ARRAY_SIZE(tuner_tena_tnf_5337_params), + }, + [TUNER_XC5000C] = { /* Xceive 5000C */ + .name = "Xceive 5000C tuner", + /* see xc5000.c for details */ + }, +}; +EXPORT_SYMBOL(tuners); + +unsigned const int tuner_count = ARRAY_SIZE(tuners); +EXPORT_SYMBOL(tuner_count); + +MODULE_DESCRIPTION("Simple tuner device type database"); +MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/tuner-xc2028-types.h b/drivers/media/tuners/tuner-xc2028-types.h new file mode 100644 index 000000000000..74dc46a71f64 --- /dev/null +++ b/drivers/media/tuners/tuner-xc2028-types.h @@ -0,0 +1,141 @@ +/* tuner-xc2028_types + * + * This file includes internal tipes to be used inside tuner-xc2028. + * Shouldn't be included outside tuner-xc2028 + * + * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License v2 + */ + +/* xc3028 firmware types */ + +/* BASE firmware should be loaded before any other firmware */ +#define BASE (1<<0) +#define BASE_TYPES (BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1) + +/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */ +#define F8MHZ (1<<1) + +/* Multichannel Television Sound (MTS) + Those firmwares are capable of using xc2038 DSP to decode audio and + produce a baseband audio output on some pins of the chip. + There are MTS firmwares for the most used video standards. It should be + required to use MTS firmwares, depending on the way audio is routed into + the bridge chip + */ +#define MTS (1<<2) + +/* FIXME: I have no idea what's the difference between + D2620 and D2633 firmwares + */ +#define D2620 (1<<3) +#define D2633 (1<<4) + +/* DTV firmwares for 6, 7 and 8 MHz + DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS + DTV8 - 8MHz - DVB-C/DVB-T + */ +#define DTV6 (1 << 5) +#define QAM (1 << 6) +#define DTV7 (1<<7) +#define DTV78 (1<<8) +#define DTV8 (1<<9) + +#define DTV_TYPES (D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC) + +/* There's a FM | BASE firmware + FM specific firmware (std=0) */ +#define FM (1<<10) + +#define STD_SPECIFIC_TYPES (MTS|FM|LCD|NOGD) + +/* Applies only for FM firmware + Makes it use RF input 1 (pin #2) instead of input 2 (pin #4) + */ +#define INPUT1 (1<<11) + + +/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M) + and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) + There are variants both with and without NOGD + Those firmwares produce better result with LCD displays + */ +#define LCD (1<<12) + +/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M) + and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) + The NOGD firmwares don't have group delay compensation filter + */ +#define NOGD (1<<13) + +/* Old firmwares were broken into init0 and init1 */ +#define INIT1 (1<<14) + +/* SCODE firmware selects particular behaviours */ +#define MONO (1 << 15) +#define ATSC (1 << 16) +#define IF (1 << 17) +#define LG60 (1 << 18) +#define ATI638 (1 << 19) +#define OREN538 (1 << 20) +#define OREN36 (1 << 21) +#define TOYOTA388 (1 << 22) +#define TOYOTA794 (1 << 23) +#define DIBCOM52 (1 << 24) +#define ZARLINK456 (1 << 25) +#define CHINA (1 << 26) +#define F6MHZ (1 << 27) +#define INPUT2 (1 << 28) +#define SCODE (1 << 29) + +/* This flag identifies that the scode table has a new format */ +#define HAS_IF (1 << 30) + +/* There are different scode tables for MTS and non-MTS. + The MTS firmwares support mono only + */ +#define SCODE_TYPES (SCODE | MTS) + + +/* Newer types not defined on videodev2.h. + The original idea were to move all those types to videodev2.h, but + it seemed overkill, since, with the exception of SECAM/K3, the other + types seem to be autodetected. + It is not clear where secam/k3 is used, nor we have a feedback of this + working or being autodetected by the standard secam firmware. + */ + +#define V4L2_STD_SECAM_K3 (0x04000000) + +/* Audio types */ + +#define V4L2_STD_A2_A (1LL<<32) +#define V4L2_STD_A2_B (1LL<<33) +#define V4L2_STD_NICAM_A (1LL<<34) +#define V4L2_STD_NICAM_B (1LL<<35) +#define V4L2_STD_AM (1LL<<36) +#define V4L2_STD_BTSC (1LL<<37) +#define V4L2_STD_EIAJ (1LL<<38) + +#define V4L2_STD_A2 (V4L2_STD_A2_A | V4L2_STD_A2_B) +#define V4L2_STD_NICAM (V4L2_STD_NICAM_A | V4L2_STD_NICAM_B) + +/* To preserve backward compatibilty, + (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported + */ + +#define V4L2_STD_AUDIO (V4L2_STD_A2 | \ + V4L2_STD_NICAM | \ + V4L2_STD_AM | \ + V4L2_STD_BTSC | \ + V4L2_STD_EIAJ) + +/* Used standards with audio restrictions */ + +#define V4L2_STD_PAL_BG_A2_A (V4L2_STD_PAL_BG | V4L2_STD_A2_A) +#define V4L2_STD_PAL_BG_A2_B (V4L2_STD_PAL_BG | V4L2_STD_A2_B) +#define V4L2_STD_PAL_BG_NICAM_A (V4L2_STD_PAL_BG | V4L2_STD_NICAM_A) +#define V4L2_STD_PAL_BG_NICAM_B (V4L2_STD_PAL_BG | V4L2_STD_NICAM_B) +#define V4L2_STD_PAL_DK_A2 (V4L2_STD_PAL_DK | V4L2_STD_A2) +#define V4L2_STD_PAL_DK_NICAM (V4L2_STD_PAL_DK | V4L2_STD_NICAM) +#define V4L2_STD_SECAM_L_NICAM (V4L2_STD_SECAM_L | V4L2_STD_NICAM) +#define V4L2_STD_SECAM_L_AM (V4L2_STD_SECAM_L | V4L2_STD_AM) diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c new file mode 100644 index 000000000000..7bcb6b0ff1df --- /dev/null +++ b/drivers/media/tuners/tuner-xc2028.c @@ -0,0 +1,1509 @@ +/* tuner-xc2028 + * + * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) + * + * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com) + * - frontend interface + * + * This code is placed under the terms of the GNU General Public License v2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tuner-i2c.h" +#include "tuner-xc2028.h" +#include "tuner-xc2028-types.h" + +#include +#include "dvb_frontend.h" + +/* Registers (Write-only) */ +#define XREG_INIT 0x00 +#define XREG_RF_FREQ 0x02 +#define XREG_POWER_DOWN 0x08 + +/* Registers (Read-only) */ +#define XREG_FREQ_ERROR 0x01 +#define XREG_LOCK 0x02 +#define XREG_VERSION 0x04 +#define XREG_PRODUCT_ID 0x08 +#define XREG_HSYNC_FREQ 0x10 +#define XREG_FRAME_LINES 0x20 +#define XREG_SNR 0x40 + +#define XREG_ADC_ENV 0x0100 + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +static int no_poweroff; +module_param(no_poweroff, int, 0644); +MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" + "1 keep device energized and with tuner ready all the times.\n" + " Faster, but consumes more power and keeps the device hotter\n"); + +static char audio_std[8]; +module_param_string(audio_std, audio_std, sizeof(audio_std), 0); +MODULE_PARM_DESC(audio_std, + "Audio standard. XC3028 audio decoder explicitly " + "needs to know what audio\n" + "standard is needed for some video standards with audio A2 or NICAM.\n" + "The valid values are:\n" + "A2\n" + "A2/A\n" + "A2/B\n" + "NICAM\n" + "NICAM/A\n" + "NICAM/B\n"); + +static char firmware_name[30]; +module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); +MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the " + "default firmware name\n"); + +static LIST_HEAD(hybrid_tuner_instance_list); +static DEFINE_MUTEX(xc2028_list_mutex); + +/* struct for storing firmware table */ +struct firmware_description { + unsigned int type; + v4l2_std_id id; + __u16 int_freq; + unsigned char *ptr; + unsigned int size; +}; + +struct firmware_properties { + unsigned int type; + v4l2_std_id id; + v4l2_std_id std_req; + __u16 int_freq; + unsigned int scode_table; + int scode_nr; +}; + +enum xc2028_state { + XC2028_NO_FIRMWARE = 0, + XC2028_WAITING_FIRMWARE, + XC2028_ACTIVE, + XC2028_SLEEP, + XC2028_NODEV, +}; + +struct xc2028_data { + struct list_head hybrid_tuner_instance_list; + struct tuner_i2c_props i2c_props; + __u32 frequency; + + enum xc2028_state state; + const char *fname; + + struct firmware_description *firm; + int firm_size; + __u16 firm_version; + + __u16 hwmodel; + __u16 hwvers; + + struct xc2028_ctrl ctrl; + + struct firmware_properties cur_fw; + + struct mutex lock; +}; + +#define i2c_send(priv, buf, size) ({ \ + int _rc; \ + _rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \ + if (size != _rc) \ + tuner_info("i2c output error: rc = %d (should be %d)\n",\ + _rc, (int)size); \ + if (priv->ctrl.msleep) \ + msleep(priv->ctrl.msleep); \ + _rc; \ +}) + +#define i2c_rcv(priv, buf, size) ({ \ + int _rc; \ + _rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \ + if (size != _rc) \ + tuner_err("i2c input error: rc = %d (should be %d)\n", \ + _rc, (int)size); \ + _rc; \ +}) + +#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \ + int _rc; \ + _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \ + ibuf, isize); \ + if (isize != _rc) \ + tuner_err("i2c input error: rc = %d (should be %d)\n", \ + _rc, (int)isize); \ + if (priv->ctrl.msleep) \ + msleep(priv->ctrl.msleep); \ + _rc; \ +}) + +#define send_seq(priv, data...) ({ \ + static u8 _val[] = data; \ + int _rc; \ + if (sizeof(_val) != \ + (_rc = tuner_i2c_xfer_send(&priv->i2c_props, \ + _val, sizeof(_val)))) { \ + tuner_err("Error on line %d: %d\n", __LINE__, _rc); \ + } else if (priv->ctrl.msleep) \ + msleep(priv->ctrl.msleep); \ + _rc; \ +}) + +static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) +{ + unsigned char buf[2]; + unsigned char ibuf[2]; + + tuner_dbg("%s %04x called\n", __func__, reg); + + buf[0] = reg >> 8; + buf[1] = (unsigned char) reg; + + if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2) + return -EIO; + + *val = (ibuf[1]) | (ibuf[0] << 8); + return 0; +} + +#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) +static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) +{ + if (type & BASE) + printk("BASE "); + if (type & INIT1) + printk("INIT1 "); + if (type & F8MHZ) + printk("F8MHZ "); + if (type & MTS) + printk("MTS "); + if (type & D2620) + printk("D2620 "); + if (type & D2633) + printk("D2633 "); + if (type & DTV6) + printk("DTV6 "); + if (type & QAM) + printk("QAM "); + if (type & DTV7) + printk("DTV7 "); + if (type & DTV78) + printk("DTV78 "); + if (type & DTV8) + printk("DTV8 "); + if (type & FM) + printk("FM "); + if (type & INPUT1) + printk("INPUT1 "); + if (type & LCD) + printk("LCD "); + if (type & NOGD) + printk("NOGD "); + if (type & MONO) + printk("MONO "); + if (type & ATSC) + printk("ATSC "); + if (type & IF) + printk("IF "); + if (type & LG60) + printk("LG60 "); + if (type & ATI638) + printk("ATI638 "); + if (type & OREN538) + printk("OREN538 "); + if (type & OREN36) + printk("OREN36 "); + if (type & TOYOTA388) + printk("TOYOTA388 "); + if (type & TOYOTA794) + printk("TOYOTA794 "); + if (type & DIBCOM52) + printk("DIBCOM52 "); + if (type & ZARLINK456) + printk("ZARLINK456 "); + if (type & CHINA) + printk("CHINA "); + if (type & F6MHZ) + printk("F6MHZ "); + if (type & INPUT2) + printk("INPUT2 "); + if (type & SCODE) + printk("SCODE "); + if (type & HAS_IF) + printk("HAS_IF_%d ", int_freq); +} + +static v4l2_std_id parse_audio_std_option(void) +{ + if (strcasecmp(audio_std, "A2") == 0) + return V4L2_STD_A2; + if (strcasecmp(audio_std, "A2/A") == 0) + return V4L2_STD_A2_A; + if (strcasecmp(audio_std, "A2/B") == 0) + return V4L2_STD_A2_B; + if (strcasecmp(audio_std, "NICAM") == 0) + return V4L2_STD_NICAM; + if (strcasecmp(audio_std, "NICAM/A") == 0) + return V4L2_STD_NICAM_A; + if (strcasecmp(audio_std, "NICAM/B") == 0) + return V4L2_STD_NICAM_B; + + return 0; +} + +static int check_device_status(struct xc2028_data *priv) +{ + switch (priv->state) { + case XC2028_NO_FIRMWARE: + case XC2028_WAITING_FIRMWARE: + return -EAGAIN; + case XC2028_ACTIVE: + case XC2028_SLEEP: + return 0; + case XC2028_NODEV: + return -ENODEV; + } + return 0; +} + +static void free_firmware(struct xc2028_data *priv) +{ + int i; + tuner_dbg("%s called\n", __func__); + + if (!priv->firm) + return; + + for (i = 0; i < priv->firm_size; i++) + kfree(priv->firm[i].ptr); + + kfree(priv->firm); + + priv->firm = NULL; + priv->firm_size = 0; + priv->state = XC2028_NO_FIRMWARE; + + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); +} + +static int load_all_firmwares(struct dvb_frontend *fe, + const struct firmware *fw) +{ + struct xc2028_data *priv = fe->tuner_priv; + const unsigned char *p, *endp; + int rc = 0; + int n, n_array; + char name[33]; + + tuner_dbg("%s called\n", __func__); + + p = fw->data; + endp = p + fw->size; + + if (fw->size < sizeof(name) - 1 + 2 + 2) { + tuner_err("Error: firmware file %s has invalid size!\n", + priv->fname); + goto corrupt; + } + + memcpy(name, p, sizeof(name) - 1); + name[sizeof(name) - 1] = 0; + p += sizeof(name) - 1; + + priv->firm_version = get_unaligned_le16(p); + p += 2; + + n_array = get_unaligned_le16(p); + p += 2; + + tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n", + n_array, priv->fname, name, + priv->firm_version >> 8, priv->firm_version & 0xff); + + priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL); + if (priv->firm == NULL) { + tuner_err("Not enough memory to load firmware file.\n"); + rc = -ENOMEM; + goto err; + } + priv->firm_size = n_array; + + n = -1; + while (p < endp) { + __u32 type, size; + v4l2_std_id id; + __u16 int_freq = 0; + + n++; + if (n >= n_array) { + tuner_err("More firmware images in file than " + "were expected!\n"); + goto corrupt; + } + + /* Checks if there's enough bytes to read */ + if (endp - p < sizeof(type) + sizeof(id) + sizeof(size)) + goto header; + + type = get_unaligned_le32(p); + p += sizeof(type); + + id = get_unaligned_le64(p); + p += sizeof(id); + + if (type & HAS_IF) { + int_freq = get_unaligned_le16(p); + p += sizeof(int_freq); + if (endp - p < sizeof(size)) + goto header; + } + + size = get_unaligned_le32(p); + p += sizeof(size); + + if (!size || size > endp - p) { + tuner_err("Firmware type "); + dump_firm_type(type); + printk("(%x), id %llx is corrupted " + "(size=%d, expected %d)\n", + type, (unsigned long long)id, + (unsigned)(endp - p), size); + goto corrupt; + } + + priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); + if (priv->firm[n].ptr == NULL) { + tuner_err("Not enough memory to load firmware file.\n"); + rc = -ENOMEM; + goto err; + } + tuner_dbg("Reading firmware type "); + if (debug) { + dump_firm_type_and_int_freq(type, int_freq); + printk("(%x), id %llx, size=%d.\n", + type, (unsigned long long)id, size); + } + + memcpy(priv->firm[n].ptr, p, size); + priv->firm[n].type = type; + priv->firm[n].id = id; + priv->firm[n].size = size; + priv->firm[n].int_freq = int_freq; + + p += size; + } + + if (n + 1 != priv->firm_size) { + tuner_err("Firmware file is incomplete!\n"); + goto corrupt; + } + + goto done; + +header: + tuner_err("Firmware header is incomplete!\n"); +corrupt: + rc = -EINVAL; + tuner_err("Error: firmware file is corrupted!\n"); + +err: + tuner_info("Releasing partially loaded firmware file.\n"); + free_firmware(priv); + +done: + if (rc == 0) + tuner_dbg("Firmware files loaded.\n"); + else + priv->state = XC2028_NODEV; + + return rc; +} + +static int seek_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id) +{ + struct xc2028_data *priv = fe->tuner_priv; + int i, best_i = -1, best_nr_matches = 0; + unsigned int type_mask = 0; + + tuner_dbg("%s called, want type=", __func__); + if (debug) { + dump_firm_type(type); + printk("(%x), id %016llx.\n", type, (unsigned long long)*id); + } + + if (!priv->firm) { + tuner_err("Error! firmware not loaded\n"); + return -EINVAL; + } + + if (((type & ~SCODE) == 0) && (*id == 0)) + *id = V4L2_STD_PAL; + + if (type & BASE) + type_mask = BASE_TYPES; + else if (type & SCODE) { + type &= SCODE_TYPES; + type_mask = SCODE_TYPES & ~HAS_IF; + } else if (type & DTV_TYPES) + type_mask = DTV_TYPES; + else if (type & STD_SPECIFIC_TYPES) + type_mask = STD_SPECIFIC_TYPES; + + type &= type_mask; + + if (!(type & SCODE)) + type_mask = ~0; + + /* Seek for exact match */ + for (i = 0; i < priv->firm_size; i++) { + if ((type == (priv->firm[i].type & type_mask)) && + (*id == priv->firm[i].id)) + goto found; + } + + /* Seek for generic video standard match */ + for (i = 0; i < priv->firm_size; i++) { + v4l2_std_id match_mask; + int nr_matches; + + if (type != (priv->firm[i].type & type_mask)) + continue; + + match_mask = *id & priv->firm[i].id; + if (!match_mask) + continue; + + if ((*id & match_mask) == *id) + goto found; /* Supports all the requested standards */ + + nr_matches = hweight64(match_mask); + if (nr_matches > best_nr_matches) { + best_nr_matches = nr_matches; + best_i = i; + } + } + + if (best_nr_matches > 0) { + tuner_dbg("Selecting best matching firmware (%d bits) for " + "type=", best_nr_matches); + dump_firm_type(type); + printk("(%x), id %016llx:\n", type, (unsigned long long)*id); + i = best_i; + goto found; + } + + /*FIXME: Would make sense to seek for type "hint" match ? */ + + i = -ENOENT; + goto ret; + +found: + *id = priv->firm[i].id; + +ret: + tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found"); + if (debug) { + dump_firm_type(type); + printk("(%x), id %016llx.\n", type, (unsigned long long)*id); + } + return i; +} + +static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg) +{ + struct xc2028_data *priv = fe->tuner_priv; + + /* analog side (tuner-core) uses i2c_adap->algo_data. + * digital side is not guaranteed to have algo_data defined. + * + * digital side will always have fe->dvb defined. + * analog side (tuner-core) doesn't (yet) define fe->dvb. + */ + + return (!fe->callback) ? -EINVAL : + fe->callback(((fe->dvb) && (fe->dvb->priv)) ? + fe->dvb->priv : priv->i2c_props.adap->algo_data, + DVB_FRONTEND_COMPONENT_TUNER, cmd, arg); +} + +static int load_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id) +{ + struct xc2028_data *priv = fe->tuner_priv; + int pos, rc; + unsigned char *p, *endp, buf[priv->ctrl.max_len]; + + tuner_dbg("%s called\n", __func__); + + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + + tuner_info("Loading firmware for type="); + dump_firm_type(priv->firm[pos].type); + printk("(%x), id %016llx.\n", priv->firm[pos].type, + (unsigned long long)*id); + + p = priv->firm[pos].ptr; + endp = p + priv->firm[pos].size; + + while (p < endp) { + __u16 size; + + /* Checks if there's enough bytes to read */ + if (p + sizeof(size) > endp) { + tuner_err("Firmware chunk size is wrong\n"); + return -EINVAL; + } + + size = le16_to_cpu(*(__u16 *) p); + p += sizeof(size); + + if (size == 0xffff) + return 0; + + if (!size) { + /* Special callback command received */ + rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0); + if (rc < 0) { + tuner_err("Error at RESET code %d\n", + (*p) & 0x7f); + return -EINVAL; + } + continue; + } + if (size >= 0xff00) { + switch (size) { + case 0xff00: + rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0); + if (rc < 0) { + tuner_err("Error at RESET code %d\n", + (*p) & 0x7f); + return -EINVAL; + } + break; + default: + tuner_info("Invalid RESET code %d\n", + size & 0x7f); + return -EINVAL; + + } + continue; + } + + /* Checks for a sleep command */ + if (size & 0x8000) { + msleep(size & 0x7fff); + continue; + } + + if ((size + p > endp)) { + tuner_err("missing bytes: need %d, have %d\n", + size, (int)(endp - p)); + return -EINVAL; + } + + buf[0] = *p; + p++; + size--; + + /* Sends message chunks */ + while (size > 0) { + int len = (size < priv->ctrl.max_len - 1) ? + size : priv->ctrl.max_len - 1; + + memcpy(buf + 1, p, len); + + rc = i2c_send(priv, buf, len + 1); + if (rc < 0) { + tuner_err("%d returned from send\n", rc); + return -EINVAL; + } + + p += len; + size -= len; + } + + /* silently fail if the frontend doesn't support I2C flush */ + rc = do_tuner_callback(fe, XC2028_I2C_FLUSH, 0); + if ((rc < 0) && (rc != -EINVAL)) { + tuner_err("error executing flush: %d\n", rc); + return rc; + } + } + return 0; +} + +static int load_scode(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id, __u16 int_freq, int scode) +{ + struct xc2028_data *priv = fe->tuner_priv; + int pos, rc; + unsigned char *p; + + tuner_dbg("%s called\n", __func__); + + if (!int_freq) { + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + } else { + for (pos = 0; pos < priv->firm_size; pos++) { + if ((priv->firm[pos].int_freq == int_freq) && + (priv->firm[pos].type & HAS_IF)) + break; + } + if (pos == priv->firm_size) + return -ENOENT; + } + + p = priv->firm[pos].ptr; + + if (priv->firm[pos].type & HAS_IF) { + if (priv->firm[pos].size != 12 * 16 || scode >= 16) + return -EINVAL; + p += 12 * scode; + } else { + /* 16 SCODE entries per file; each SCODE entry is 12 bytes and + * has a 2-byte size header in the firmware format. */ + if (priv->firm[pos].size != 14 * 16 || scode >= 16 || + le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12) + return -EINVAL; + p += 14 * scode + 2; + } + + tuner_info("Loading SCODE for type="); + dump_firm_type_and_int_freq(priv->firm[pos].type, + priv->firm[pos].int_freq); + printk("(%x), id %016llx.\n", priv->firm[pos].type, + (unsigned long long)*id); + + if (priv->firm_version < 0x0202) + rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00}); + else + rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00}); + if (rc < 0) + return -EIO; + + rc = i2c_send(priv, p, 12); + if (rc < 0) + return -EIO; + + rc = send_seq(priv, {0x00, 0x8c}); + if (rc < 0) + return -EIO; + + return 0; +} + +static int check_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id std, __u16 int_freq) +{ + struct xc2028_data *priv = fe->tuner_priv; + struct firmware_properties new_fw; + int rc, retry_count = 0; + u16 version, hwmodel; + v4l2_std_id std0; + + tuner_dbg("%s called\n", __func__); + + rc = check_device_status(priv); + if (rc < 0) + return rc; + + if (priv->ctrl.mts && !(type & FM)) + type |= MTS; + +retry: + new_fw.type = type; + new_fw.id = std; + new_fw.std_req = std; + new_fw.scode_table = SCODE | priv->ctrl.scode_table; + new_fw.scode_nr = 0; + new_fw.int_freq = int_freq; + + tuner_dbg("checking firmware, user requested type="); + if (debug) { + dump_firm_type(new_fw.type); + printk("(%x), id %016llx, ", new_fw.type, + (unsigned long long)new_fw.std_req); + if (!int_freq) { + printk("scode_tbl "); + dump_firm_type(priv->ctrl.scode_table); + printk("(%x), ", priv->ctrl.scode_table); + } else + printk("int_freq %d, ", new_fw.int_freq); + printk("scode_nr %d\n", new_fw.scode_nr); + } + + /* + * No need to reload base firmware if it matches and if the tuner + * is not at sleep mode + */ + if ((priv->state == XC2028_ACTIVE) && + (((BASE | new_fw.type) & BASE_TYPES) == + (priv->cur_fw.type & BASE_TYPES))) { + tuner_dbg("BASE firmware not changed.\n"); + goto skip_base; + } + + /* Updating BASE - forget about all currently loaded firmware */ + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); + + /* Reset is needed before loading firmware */ + rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0); + if (rc < 0) + goto fail; + + /* BASE firmwares are all std0 */ + std0 = 0; + rc = load_firmware(fe, BASE | new_fw.type, &std0); + if (rc < 0) { + tuner_err("Error %d while loading base firmware\n", + rc); + goto fail; + } + + /* Load INIT1, if needed */ + tuner_dbg("Load init1 firmware, if exists\n"); + + rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0); + if (rc == -ENOENT) + rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ, + &std0); + if (rc < 0 && rc != -ENOENT) { + tuner_err("Error %d while loading init1 firmware\n", + rc); + goto fail; + } + +skip_base: + /* + * No need to reload standard specific firmware if base firmware + * was not reloaded and requested video standards have not changed. + */ + if (priv->cur_fw.type == (BASE | new_fw.type) && + priv->cur_fw.std_req == std) { + tuner_dbg("Std-specific firmware already loaded.\n"); + goto skip_std_specific; + } + + /* Reloading std-specific firmware forces a SCODE update */ + priv->cur_fw.scode_table = 0; + + rc = load_firmware(fe, new_fw.type, &new_fw.id); + if (rc == -ENOENT) + rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id); + + if (rc < 0) + goto fail; + +skip_std_specific: + if (priv->cur_fw.scode_table == new_fw.scode_table && + priv->cur_fw.scode_nr == new_fw.scode_nr) { + tuner_dbg("SCODE firmware already loaded.\n"); + goto check_device; + } + + if (new_fw.type & FM) + goto check_device; + + /* Load SCODE firmware, if exists */ + tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr); + + rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, + new_fw.int_freq, new_fw.scode_nr); + +check_device: + if (xc2028_get_reg(priv, 0x0004, &version) < 0 || + xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) { + tuner_err("Unable to read tuner registers.\n"); + goto fail; + } + + tuner_dbg("Device is Xceive %d version %d.%d, " + "firmware version %d.%d\n", + hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, + (version & 0xf0) >> 4, version & 0xf); + + + if (priv->ctrl.read_not_reliable) + goto read_not_reliable; + + /* Check firmware version against what we downloaded. */ + if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) { + if (!priv->ctrl.read_not_reliable) { + tuner_err("Incorrect readback of firmware version.\n"); + goto fail; + } else { + tuner_err("Returned an incorrect version. However, " + "read is not reliable enough. Ignoring it.\n"); + hwmodel = 3028; + } + } + + /* Check that the tuner hardware model remains consistent over time. */ + if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) { + priv->hwmodel = hwmodel; + priv->hwvers = version & 0xff00; + } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || + priv->hwvers != (version & 0xff00)) { + tuner_err("Read invalid device hardware information - tuner " + "hung?\n"); + goto fail; + } + +read_not_reliable: + memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); + + /* + * By setting BASE in cur_fw.type only after successfully loading all + * firmwares, we can: + * 1. Identify that BASE firmware with type=0 has been loaded; + * 2. Tell whether BASE firmware was just changed the next time through. + */ + priv->cur_fw.type |= BASE; + priv->state = XC2028_ACTIVE; + + return 0; + +fail: + priv->state = XC2028_SLEEP; + + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); + if (retry_count < 8) { + msleep(50); + retry_count++; + tuner_dbg("Retrying firmware load\n"); + goto retry; + } + + if (rc == -ENOENT) + rc = -EINVAL; + return rc; +} + +static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) +{ + struct xc2028_data *priv = fe->tuner_priv; + u16 frq_lock, signal = 0; + int rc, i; + + tuner_dbg("%s called\n", __func__); + + rc = check_device_status(priv); + if (rc < 0) + return rc; + + mutex_lock(&priv->lock); + + /* Sync Lock Indicator */ + for (i = 0; i < 3; i++) { + rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock); + if (rc < 0) + goto ret; + + if (frq_lock) + break; + msleep(6); + } + + /* Frequency didn't lock */ + if (frq_lock == 2) + goto ret; + + /* Get SNR of the video signal */ + rc = xc2028_get_reg(priv, XREG_SNR, &signal); + if (rc < 0) + goto ret; + + /* Signal level is 3 bits only */ + + signal = ((1 << 12) - 1) | ((signal & 0x07) << 12); + +ret: + mutex_unlock(&priv->lock); + + *strength = signal; + + tuner_dbg("signal strength is %d\n", signal); + + return rc; +} + +static int xc2028_get_afc(struct dvb_frontend *fe, s32 *afc) +{ + struct xc2028_data *priv = fe->tuner_priv; + int i, rc; + u16 frq_lock = 0; + s16 afc_reg = 0; + + rc = check_device_status(priv); + if (rc < 0) + return rc; + + mutex_lock(&priv->lock); + + /* Sync Lock Indicator */ + for (i = 0; i < 3; i++) { + rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock); + if (rc < 0) + goto ret; + + if (frq_lock) + break; + msleep(6); + } + + /* Frequency didn't lock */ + if (frq_lock == 2) + goto ret; + + /* Get AFC */ + rc = xc2028_get_reg(priv, XREG_FREQ_ERROR, &afc_reg); + if (rc < 0) + goto ret; + + *afc = afc_reg * 15625; /* Hz */ + + tuner_dbg("AFC is %d Hz\n", *afc); + +ret: + mutex_unlock(&priv->lock); + + return rc; +} + +#define DIV 15625 + +static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, + enum v4l2_tuner_type new_type, + unsigned int type, + v4l2_std_id std, + u16 int_freq) +{ + struct xc2028_data *priv = fe->tuner_priv; + int rc = -EINVAL; + unsigned char buf[4]; + u32 div, offset = 0; + + tuner_dbg("%s called\n", __func__); + + mutex_lock(&priv->lock); + + tuner_dbg("should set frequency %d kHz\n", freq / 1000); + + if (check_firmware(fe, type, std, int_freq) < 0) + goto ret; + + /* On some cases xc2028 can disable video output, if + * very weak signals are received. By sending a soft + * reset, this is re-enabled. So, it is better to always + * send a soft reset before changing channels, to be sure + * that xc2028 will be in a safe state. + * Maybe this might also be needed for DTV. + */ + switch (new_type) { + case V4L2_TUNER_ANALOG_TV: + rc = send_seq(priv, {0x00, 0x00}); + + /* Analog mode requires offset = 0 */ + break; + case V4L2_TUNER_RADIO: + /* Radio mode requires offset = 0 */ + break; + case V4L2_TUNER_DIGITAL_TV: + /* + * Digital modes require an offset to adjust to the + * proper frequency. The offset depends on what + * firmware version is used. + */ + + /* + * Adjust to the center frequency. This is calculated by the + * formula: offset = 1.25MHz - BW/2 + * For DTV 7/8, the firmware uses BW = 8000, so it needs a + * further adjustment to get the frequency center on VHF + */ + + /* + * The firmware DTV78 used to work fine in UHF band (8 MHz + * bandwidth) but not at all in VHF band (7 MHz bandwidth). + * The real problem was connected to the formula used to + * calculate the center frequency offset in VHF band. + * In fact, removing the 500KHz adjustment fixed the problem. + * This is coherent to what was implemented for the DTV7 + * firmware. + * In the end, now the center frequency is the same for all 3 + * firmwares (DTV7, DTV8, DTV78) and doesn't depend on channel + * bandwidth. + */ + + if (priv->cur_fw.type & DTV6) + offset = 1750000; + else /* DTV7 or DTV8 or DTV78 */ + offset = 2750000; + + /* + * xc3028 additional "magic" + * Depending on the firmware version, it needs some adjustments + * to properly centralize the frequency. This seems to be + * needed to compensate the SCODE table adjustments made by + * newer firmwares + */ + + /* + * The proper adjustment would be to do it at s-code table. + * However, this didn't work, as reported by + * Robert Lowery + */ + +#if 0 + /* + * Still need tests for XC3028L (firmware 3.2 or upper) + * So, for now, let's just comment the per-firmware + * version of this change. Reports with xc3028l working + * with and without the lines bellow are welcome + */ + + if (priv->firm_version < 0x0302) { + if (priv->cur_fw.type & DTV7) + offset += 500000; + } else { + if (priv->cur_fw.type & DTV7) + offset -= 300000; + else if (type != ATSC) /* DVB @6MHz, DTV 8 and DTV 7/8 */ + offset += 200000; + } +#endif + } + + div = (freq - offset + DIV / 2) / DIV; + + /* CMD= Set frequency */ + if (priv->firm_version < 0x0202) + rc = send_seq(priv, {0x00, XREG_RF_FREQ, 0x00, 0x00}); + else + rc = send_seq(priv, {0x80, XREG_RF_FREQ, 0x00, 0x00}); + if (rc < 0) + goto ret; + + /* Return code shouldn't be checked. + The reset CLK is needed only with tm6000. + Driver should work fine even if this fails. + */ + if (priv->ctrl.msleep) + msleep(priv->ctrl.msleep); + do_tuner_callback(fe, XC2028_RESET_CLK, 1); + + msleep(10); + + buf[0] = 0xff & (div >> 24); + buf[1] = 0xff & (div >> 16); + buf[2] = 0xff & (div >> 8); + buf[3] = 0xff & (div); + + rc = i2c_send(priv, buf, sizeof(buf)); + if (rc < 0) + goto ret; + msleep(100); + + priv->frequency = freq; + + tuner_dbg("divisor= %*ph (freq=%d.%03d)\n", 4, buf, + freq / 1000000, (freq % 1000000) / 1000); + + rc = 0; + +ret: + mutex_unlock(&priv->lock); + + return rc; +} + +static int xc2028_set_analog_freq(struct dvb_frontend *fe, + struct analog_parameters *p) +{ + struct xc2028_data *priv = fe->tuner_priv; + unsigned int type=0; + + tuner_dbg("%s called\n", __func__); + + if (p->mode == V4L2_TUNER_RADIO) { + type |= FM; + if (priv->ctrl.input1) + type |= INPUT1; + return generic_set_freq(fe, (625l * p->frequency) / 10, + V4L2_TUNER_RADIO, type, 0, 0); + } + + /* if std is not defined, choose one */ + if (!p->std) + p->std = V4L2_STD_MN; + + /* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */ + if (!(p->std & V4L2_STD_MN)) + type |= F8MHZ; + + /* Add audio hack to std mask */ + p->std |= parse_audio_std_option(); + + return generic_set_freq(fe, 62500l * p->frequency, + V4L2_TUNER_ANALOG_TV, type, p->std, 0); +} + +static int xc2028_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; + struct xc2028_data *priv = fe->tuner_priv; + int rc; + unsigned int type = 0; + u16 demod = 0; + + tuner_dbg("%s called\n", __func__); + + rc = check_device_status(priv); + if (rc < 0) + return rc; + + switch (delsys) { + case SYS_DVBT: + case SYS_DVBT2: + /* + * The only countries with 6MHz seem to be Taiwan/Uruguay. + * Both seem to require QAM firmware for OFDM decoding + * Tested in Taiwan by Terry Wu + */ + if (bw <= 6000000) + type |= QAM; + + switch (priv->ctrl.type) { + case XC2028_D2633: + type |= D2633; + break; + case XC2028_D2620: + type |= D2620; + break; + case XC2028_AUTO: + default: + /* Zarlink seems to need D2633 */ + if (priv->ctrl.demod == XC3028_FE_ZARLINK456) + type |= D2633; + else + type |= D2620; + } + break; + case SYS_ATSC: + /* The only ATSC firmware (at least on v2.7) is D2633 */ + type |= ATSC | D2633; + break; + /* DVB-S and pure QAM (FE_QAM) are not supported */ + default: + return -EINVAL; + } + + if (bw <= 6000000) { + type |= DTV6; + priv->ctrl.vhfbw7 = 0; + priv->ctrl.uhfbw8 = 0; + } else if (bw <= 7000000) { + if (c->frequency < 470000000) + priv->ctrl.vhfbw7 = 1; + else + priv->ctrl.uhfbw8 = 0; + type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7; + type |= F8MHZ; + } else { + if (c->frequency < 470000000) + priv->ctrl.vhfbw7 = 0; + else + priv->ctrl.uhfbw8 = 1; + type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8; + type |= F8MHZ; + } + + /* All S-code tables need a 200kHz shift */ + if (priv->ctrl.demod) { + demod = priv->ctrl.demod; + + /* + * Newer firmwares require a 200 kHz offset only for ATSC + */ + if (type == ATSC || priv->firm_version < 0x0302) + demod += 200; + /* + * The DTV7 S-code table needs a 700 kHz shift. + * + * DTV7 is only used in Australia. Germany or Italy may also + * use this firmware after initialization, but a tune to a UHF + * channel should then cause DTV78 to be used. + * + * Unfortunately, on real-field tests, the s-code offset + * didn't work as expected, as reported by + * Robert Lowery + */ + } + + return generic_set_freq(fe, c->frequency, + V4L2_TUNER_DIGITAL_TV, type, 0, demod); +} + +static int xc2028_sleep(struct dvb_frontend *fe) +{ + struct xc2028_data *priv = fe->tuner_priv; + int rc; + + rc = check_device_status(priv); + if (rc < 0) + return rc; + + /* Avoid firmware reload on slow devices or if PM disabled */ + if (no_poweroff || priv->ctrl.disable_power_mgmt) + return 0; + + tuner_dbg("Putting xc2028/3028 into poweroff mode.\n"); + if (debug > 1) { + tuner_dbg("Printing sleep stack trace:\n"); + dump_stack(); + } + + mutex_lock(&priv->lock); + + if (priv->firm_version < 0x0202) + rc = send_seq(priv, {0x00, XREG_POWER_DOWN, 0x00, 0x00}); + else + rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00}); + + priv->state = XC2028_SLEEP; + + mutex_unlock(&priv->lock); + + return rc; +} + +static int xc2028_dvb_release(struct dvb_frontend *fe) +{ + struct xc2028_data *priv = fe->tuner_priv; + + tuner_dbg("%s called\n", __func__); + + mutex_lock(&xc2028_list_mutex); + + /* only perform final cleanup if this is the last instance */ + if (hybrid_tuner_report_instance_count(priv) == 1) { + free_firmware(priv); + kfree(priv->ctrl.fname); + priv->ctrl.fname = NULL; + } + + if (priv) + hybrid_tuner_release_state(priv); + + mutex_unlock(&xc2028_list_mutex); + + fe->tuner_priv = NULL; + + return 0; +} + +static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct xc2028_data *priv = fe->tuner_priv; + int rc; + + tuner_dbg("%s called\n", __func__); + + rc = check_device_status(priv); + if (rc < 0) + return rc; + + *frequency = priv->frequency; + + return 0; +} + +static void load_firmware_cb(const struct firmware *fw, + void *context) +{ + struct dvb_frontend *fe = context; + struct xc2028_data *priv = fe->tuner_priv; + int rc; + + tuner_dbg("request_firmware_nowait(): %s\n", fw ? "OK" : "error"); + if (!fw) { + tuner_err("Could not load firmware %s.\n", priv->fname); + priv->state = XC2028_NODEV; + return; + } + + rc = load_all_firmwares(fe, fw); + + release_firmware(fw); + + if (rc < 0) + return; + priv->state = XC2028_SLEEP; +} + +static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) +{ + struct xc2028_data *priv = fe->tuner_priv; + struct xc2028_ctrl *p = priv_cfg; + int rc = 0; + + tuner_dbg("%s called\n", __func__); + + mutex_lock(&priv->lock); + + /* + * Copy the config data. + * For the firmware name, keep a local copy of the string, + * in order to avoid troubles during device release. + */ + if (priv->ctrl.fname) + kfree(priv->ctrl.fname); + memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); + if (p->fname) { + priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); + if (priv->ctrl.fname == NULL) + rc = -ENOMEM; + } + + /* + * If firmware name changed, frees firmware. As free_firmware will + * reset the status to NO_FIRMWARE, this forces a new request_firmware + */ + if (!firmware_name[0] && p->fname && + priv->fname && strcmp(p->fname, priv->fname)) + free_firmware(priv); + + if (priv->ctrl.max_len < 9) + priv->ctrl.max_len = 13; + + if (priv->state == XC2028_NO_FIRMWARE) { + if (!firmware_name[0]) + priv->fname = priv->ctrl.fname; + else + priv->fname = firmware_name; + + rc = request_firmware_nowait(THIS_MODULE, 1, + priv->fname, + priv->i2c_props.adap->dev.parent, + GFP_KERNEL, + fe, load_firmware_cb); + if (rc < 0) { + tuner_err("Failed to request firmware %s\n", + priv->fname); + priv->state = XC2028_NODEV; + } else + priv->state = XC2028_WAITING_FIRMWARE; + } + mutex_unlock(&priv->lock); + + return rc; +} + +static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { + .info = { + .name = "Xceive XC3028", + .frequency_min = 42000000, + .frequency_max = 864000000, + .frequency_step = 50000, + }, + + .set_config = xc2028_set_config, + .set_analog_params = xc2028_set_analog_freq, + .release = xc2028_dvb_release, + .get_frequency = xc2028_get_frequency, + .get_rf_strength = xc2028_signal, + .get_afc = xc2028_get_afc, + .set_params = xc2028_set_params, + .sleep = xc2028_sleep, +}; + +struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, + struct xc2028_config *cfg) +{ + struct xc2028_data *priv; + int instance; + + if (debug) + printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n"); + + if (NULL == cfg) + return NULL; + + if (!fe) { + printk(KERN_ERR "xc2028: No frontend!\n"); + return NULL; + } + + mutex_lock(&xc2028_list_mutex); + + instance = hybrid_tuner_request_state(struct xc2028_data, priv, + hybrid_tuner_instance_list, + cfg->i2c_adap, cfg->i2c_addr, + "xc2028"); + switch (instance) { + case 0: + /* memory allocation failure */ + goto fail; + break; + case 1: + /* new tuner instance */ + priv->ctrl.max_len = 13; + + mutex_init(&priv->lock); + + fe->tuner_priv = priv; + break; + case 2: + /* existing tuner instance */ + fe->tuner_priv = priv; + break; + } + + memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops, + sizeof(xc2028_dvb_tuner_ops)); + + tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner"); + + if (cfg->ctrl) + xc2028_set_config(fe, cfg->ctrl); + + mutex_unlock(&xc2028_list_mutex); + + return fe; +fail: + mutex_unlock(&xc2028_list_mutex); + + xc2028_dvb_release(fe); + return NULL; +} + +EXPORT_SYMBOL(xc2028_attach); + +MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver"); +MODULE_AUTHOR("Michel Ludwig "); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE); +MODULE_FIRMWARE(XC3028L_DEFAULT_FIRMWARE); diff --git a/drivers/media/tuners/tuner-xc2028.h b/drivers/media/tuners/tuner-xc2028.h new file mode 100644 index 000000000000..9ebfb2d0ff14 --- /dev/null +++ b/drivers/media/tuners/tuner-xc2028.h @@ -0,0 +1,72 @@ +/* tuner-xc2028 + * + * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License v2 + */ + +#ifndef __TUNER_XC2028_H__ +#define __TUNER_XC2028_H__ + +#include "dvb_frontend.h" + +#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw" +#define XC3028L_DEFAULT_FIRMWARE "xc3028L-v36.fw" + +/* Dmoduler IF (kHz) */ +#define XC3028_FE_DEFAULT 0 /* Don't load SCODE */ +#define XC3028_FE_LG60 6000 +#define XC3028_FE_ATI638 6380 +#define XC3028_FE_OREN538 5380 +#define XC3028_FE_OREN36 3600 +#define XC3028_FE_TOYOTA388 3880 +#define XC3028_FE_TOYOTA794 7940 +#define XC3028_FE_DIBCOM52 5200 +#define XC3028_FE_ZARLINK456 4560 +#define XC3028_FE_CHINA 5200 + +enum firmware_type { + XC2028_AUTO = 0, /* By default, auto-detects */ + XC2028_D2633, + XC2028_D2620, +}; + +struct xc2028_ctrl { + char *fname; + int max_len; + int msleep; + unsigned int scode_table; + unsigned int mts :1; + unsigned int input1:1; + unsigned int vhfbw7:1; + unsigned int uhfbw8:1; + unsigned int disable_power_mgmt:1; + unsigned int read_not_reliable:1; + unsigned int demod; + enum firmware_type type:2; +}; + +struct xc2028_config { + struct i2c_adapter *i2c_adap; + u8 i2c_addr; + struct xc2028_ctrl *ctrl; +}; + +/* xc2028 commands for callback */ +#define XC2028_TUNER_RESET 0 +#define XC2028_RESET_CLK 1 +#define XC2028_I2C_FLUSH 2 + +#if defined(CONFIG_MEDIA_TUNER_XC2028) || (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE)) +extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, + struct xc2028_config *cfg); +#else +static inline struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, + struct xc2028_config *cfg) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __func__); + return NULL; +} +#endif + +#endif /* __TUNER_XC2028_H__ */ diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c new file mode 100644 index 000000000000..4937712278f6 --- /dev/null +++ b/drivers/media/tuners/xc4000.c @@ -0,0 +1,1757 @@ +/* + * Driver for Xceive XC4000 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2007 Xceive Corporation + * Copyright (c) 2007 Steven Toth + * Copyright (c) 2009 Devin Heitmueller + * Copyright (c) 2009 Davide Ferri + * Copyright (c) 2010 Istvan Varga + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "xc4000.h" +#include "tuner-i2c.h" +#include "tuner-xc2028-types.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debugging level (0 to 2, default: 0 (off))."); + +static int no_poweroff; +module_param(no_poweroff, int, 0644); +MODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, " + "0 (default): use device-specific default mode)."); + +static int audio_std; +module_param(audio_std, int, 0644); +MODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly " + "needs to know what audio standard is needed for some video standards " + "with audio A2 or NICAM. The valid settings are a sum of:\n" + " 1: use NICAM/B or A2/B instead of NICAM/A or A2/A\n" + " 2: use A2 instead of NICAM or BTSC\n" + " 4: use SECAM/K3 instead of K1\n" + " 8: use PAL-D/K audio for SECAM-D/K\n" + "16: use FM radio input 1 instead of input 2\n" + "32: use mono audio (the lower three bits are ignored)"); + +static char firmware_name[30]; +module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); +MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the " + "default firmware name."); + +static DEFINE_MUTEX(xc4000_list_mutex); +static LIST_HEAD(hybrid_tuner_instance_list); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_INFO "%s: " fmt, "xc4000", ## arg) + +/* struct for storing firmware table */ +struct firmware_description { + unsigned int type; + v4l2_std_id id; + __u16 int_freq; + unsigned char *ptr; + unsigned int size; +}; + +struct firmware_properties { + unsigned int type; + v4l2_std_id id; + v4l2_std_id std_req; + __u16 int_freq; + unsigned int scode_table; + int scode_nr; +}; + +struct xc4000_priv { + struct tuner_i2c_props i2c_props; + struct list_head hybrid_tuner_instance_list; + struct firmware_description *firm; + int firm_size; + u32 if_khz; + u32 freq_hz; + u32 bandwidth; + u8 video_standard; + u8 rf_mode; + u8 default_pm; + u8 dvb_amplitude; + u8 set_smoothedcvbs; + u8 ignore_i2c_write_errors; + __u16 firm_version; + struct firmware_properties cur_fw; + __u16 hwmodel; + __u16 hwvers; + struct mutex lock; +}; + +#define XC4000_AUDIO_STD_B 1 +#define XC4000_AUDIO_STD_A2 2 +#define XC4000_AUDIO_STD_K3 4 +#define XC4000_AUDIO_STD_L 8 +#define XC4000_AUDIO_STD_INPUT1 16 +#define XC4000_AUDIO_STD_MONO 32 + +#define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.fw" + +/* Misc Defines */ +#define MAX_TV_STANDARD 24 +#define XC_MAX_I2C_WRITE_LENGTH 64 +#define XC_POWERED_DOWN 0x80000000U + +/* Signal Types */ +#define XC_RF_MODE_AIR 0 +#define XC_RF_MODE_CABLE 1 + +/* Product id */ +#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 +#define XC_PRODUCT_ID_XC4000 0x0FA0 +#define XC_PRODUCT_ID_XC4100 0x1004 + +/* Registers (Write-only) */ +#define XREG_INIT 0x00 +#define XREG_VIDEO_MODE 0x01 +#define XREG_AUDIO_MODE 0x02 +#define XREG_RF_FREQ 0x03 +#define XREG_D_CODE 0x04 +#define XREG_DIRECTSITTING_MODE 0x05 +#define XREG_SEEK_MODE 0x06 +#define XREG_POWER_DOWN 0x08 +#define XREG_SIGNALSOURCE 0x0A +#define XREG_SMOOTHEDCVBS 0x0E +#define XREG_AMPLITUDE 0x10 + +/* Registers (Read-only) */ +#define XREG_ADC_ENV 0x00 +#define XREG_QUALITY 0x01 +#define XREG_FRAME_LINES 0x02 +#define XREG_HSYNC_FREQ 0x03 +#define XREG_LOCK 0x04 +#define XREG_FREQ_ERROR 0x05 +#define XREG_SNR 0x06 +#define XREG_VERSION 0x07 +#define XREG_PRODUCT_ID 0x08 +#define XREG_SIGNAL_LEVEL 0x0A +#define XREG_NOISE_LEVEL 0x0B + +/* + Basic firmware description. This will remain with + the driver for documentation purposes. + + This represents an I2C firmware file encoded as a + string of unsigned char. Format is as follows: + + char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB + char[1 ]=len0_LSB -> length of first write transaction + char[2 ]=data0 -> first byte to be sent + char[3 ]=data1 + char[4 ]=data2 + char[ ]=... + char[M ]=dataN -> last byte to be sent + char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB + char[M+2]=len1_LSB -> length of second write transaction + char[M+3]=data0 + char[M+4]=data1 + ... + etc. + + The [len] value should be interpreted as follows: + + len= len_MSB _ len_LSB + len=1111_1111_1111_1111 : End of I2C_SEQUENCE + len=0000_0000_0000_0000 : Reset command: Do hardware reset + len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) + len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms + + For the RESET and WAIT commands, the two following bytes will contain + immediately the length of the following transaction. +*/ + +struct XC_TV_STANDARD { + const char *Name; + u16 audio_mode; + u16 video_mode; + u16 int_freq; +}; + +/* Tuner standards */ +#define XC4000_MN_NTSC_PAL_BTSC 0 +#define XC4000_MN_NTSC_PAL_A2 1 +#define XC4000_MN_NTSC_PAL_EIAJ 2 +#define XC4000_MN_NTSC_PAL_Mono 3 +#define XC4000_BG_PAL_A2 4 +#define XC4000_BG_PAL_NICAM 5 +#define XC4000_BG_PAL_MONO 6 +#define XC4000_I_PAL_NICAM 7 +#define XC4000_I_PAL_NICAM_MONO 8 +#define XC4000_DK_PAL_A2 9 +#define XC4000_DK_PAL_NICAM 10 +#define XC4000_DK_PAL_MONO 11 +#define XC4000_DK_SECAM_A2DK1 12 +#define XC4000_DK_SECAM_A2LDK3 13 +#define XC4000_DK_SECAM_A2MONO 14 +#define XC4000_DK_SECAM_NICAM 15 +#define XC4000_L_SECAM_NICAM 16 +#define XC4000_LC_SECAM_NICAM 17 +#define XC4000_DTV6 18 +#define XC4000_DTV8 19 +#define XC4000_DTV7_8 20 +#define XC4000_DTV7 21 +#define XC4000_FM_Radio_INPUT2 22 +#define XC4000_FM_Radio_INPUT1 23 + +static struct XC_TV_STANDARD xc4000_standard[MAX_TV_STANDARD] = { + {"M/N-NTSC/PAL-BTSC", 0x0000, 0x80A0, 4500}, + {"M/N-NTSC/PAL-A2", 0x0000, 0x80A0, 4600}, + {"M/N-NTSC/PAL-EIAJ", 0x0040, 0x80A0, 4500}, + {"M/N-NTSC/PAL-Mono", 0x0078, 0x80A0, 4500}, + {"B/G-PAL-A2", 0x0000, 0x8159, 5640}, + {"B/G-PAL-NICAM", 0x0004, 0x8159, 5740}, + {"B/G-PAL-MONO", 0x0078, 0x8159, 5500}, + {"I-PAL-NICAM", 0x0080, 0x8049, 6240}, + {"I-PAL-NICAM-MONO", 0x0078, 0x8049, 6000}, + {"D/K-PAL-A2", 0x0000, 0x8049, 6380}, + {"D/K-PAL-NICAM", 0x0080, 0x8049, 6200}, + {"D/K-PAL-MONO", 0x0078, 0x8049, 6500}, + {"D/K-SECAM-A2 DK1", 0x0000, 0x8049, 6340}, + {"D/K-SECAM-A2 L/DK3", 0x0000, 0x8049, 6000}, + {"D/K-SECAM-A2 MONO", 0x0078, 0x8049, 6500}, + {"D/K-SECAM-NICAM", 0x0080, 0x8049, 6200}, + {"L-SECAM-NICAM", 0x8080, 0x0009, 6200}, + {"L'-SECAM-NICAM", 0x8080, 0x4009, 6200}, + {"DTV6", 0x00C0, 0x8002, 0}, + {"DTV8", 0x00C0, 0x800B, 0}, + {"DTV7/8", 0x00C0, 0x801B, 0}, + {"DTV7", 0x00C0, 0x8007, 0}, + {"FM Radio-INPUT2", 0x0008, 0x9800, 10700}, + {"FM Radio-INPUT1", 0x0008, 0x9000, 10700} +}; + +static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val); +static int xc4000_tuner_reset(struct dvb_frontend *fe); +static void xc_debug_dump(struct xc4000_priv *priv); + +static int xc_send_i2c_data(struct xc4000_priv *priv, u8 *buf, int len) +{ + struct i2c_msg msg = { .addr = priv->i2c_props.addr, + .flags = 0, .buf = buf, .len = len }; + if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { + if (priv->ignore_i2c_write_errors == 0) { + printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n", + len); + if (len == 4) { + printk(KERN_ERR "bytes %*ph\n", 4, buf); + } + return -EREMOTEIO; + } + } + return 0; +} + +static int xc4000_tuner_reset(struct dvb_frontend *fe) +{ + struct xc4000_priv *priv = fe->tuner_priv; + int ret; + + dprintk(1, "%s()\n", __func__); + + if (fe->callback) { + ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ? + fe->dvb->priv : + priv->i2c_props.adap->algo_data, + DVB_FRONTEND_COMPONENT_TUNER, + XC4000_TUNER_RESET, 0); + if (ret) { + printk(KERN_ERR "xc4000: reset failed\n"); + return -EREMOTEIO; + } + } else { + printk(KERN_ERR "xc4000: no tuner reset callback function, " + "fatal\n"); + return -EINVAL; + } + return 0; +} + +static int xc_write_reg(struct xc4000_priv *priv, u16 regAddr, u16 i2cData) +{ + u8 buf[4]; + int result; + + buf[0] = (regAddr >> 8) & 0xFF; + buf[1] = regAddr & 0xFF; + buf[2] = (i2cData >> 8) & 0xFF; + buf[3] = i2cData & 0xFF; + result = xc_send_i2c_data(priv, buf, 4); + + return result; +} + +static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) +{ + struct xc4000_priv *priv = fe->tuner_priv; + + int i, nbytes_to_send, result; + unsigned int len, pos, index; + u8 buf[XC_MAX_I2C_WRITE_LENGTH]; + + index = 0; + while ((i2c_sequence[index] != 0xFF) || + (i2c_sequence[index + 1] != 0xFF)) { + len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; + if (len == 0x0000) { + /* RESET command */ + /* NOTE: this is ignored, as the reset callback was */ + /* already called by check_firmware() */ + index += 2; + } else if (len & 0x8000) { + /* WAIT command */ + msleep(len & 0x7FFF); + index += 2; + } else { + /* Send i2c data whilst ensuring individual transactions + * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. + */ + index += 2; + buf[0] = i2c_sequence[index]; + buf[1] = i2c_sequence[index + 1]; + pos = 2; + while (pos < len) { + if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) + nbytes_to_send = + XC_MAX_I2C_WRITE_LENGTH; + else + nbytes_to_send = (len - pos + 2); + for (i = 2; i < nbytes_to_send; i++) { + buf[i] = i2c_sequence[index + pos + + i - 2]; + } + result = xc_send_i2c_data(priv, buf, + nbytes_to_send); + + if (result != 0) + return result; + + pos += nbytes_to_send - 2; + } + index += len; + } + } + return 0; +} + +static int xc_set_tv_standard(struct xc4000_priv *priv, + u16 video_mode, u16 audio_mode) +{ + int ret; + dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode); + dprintk(1, "%s() Standard = %s\n", + __func__, + xc4000_standard[priv->video_standard].Name); + + /* Don't complain when the request fails because of i2c stretching */ + priv->ignore_i2c_write_errors = 1; + + ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode); + if (ret == 0) + ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode); + + priv->ignore_i2c_write_errors = 0; + + return ret; +} + +static int xc_set_signal_source(struct xc4000_priv *priv, u16 rf_mode) +{ + dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, + rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); + + if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) { + rf_mode = XC_RF_MODE_CABLE; + printk(KERN_ERR + "%s(), Invalid mode, defaulting to CABLE", + __func__); + } + return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); +} + +static const struct dvb_tuner_ops xc4000_tuner_ops; + +static int xc_set_rf_frequency(struct xc4000_priv *priv, u32 freq_hz) +{ + u16 freq_code; + + dprintk(1, "%s(%u)\n", __func__, freq_hz); + + if ((freq_hz > xc4000_tuner_ops.info.frequency_max) || + (freq_hz < xc4000_tuner_ops.info.frequency_min)) + return -EINVAL; + + freq_code = (u16)(freq_hz / 15625); + + /* WAS: Starting in firmware version 1.1.44, Xceive recommends using the + FINERFREQ for all normal tuning (the doc indicates reg 0x03 should + only be used for fast scanning for channel lock) */ + /* WAS: XREG_FINERFREQ */ + return xc_write_reg(priv, XREG_RF_FREQ, freq_code); +} + +static int xc_get_adc_envelope(struct xc4000_priv *priv, u16 *adc_envelope) +{ + return xc4000_readreg(priv, XREG_ADC_ENV, adc_envelope); +} + +static int xc_get_frequency_error(struct xc4000_priv *priv, u32 *freq_error_hz) +{ + int result; + u16 regData; + u32 tmp; + + result = xc4000_readreg(priv, XREG_FREQ_ERROR, ®Data); + if (result != 0) + return result; + + tmp = (u32)regData & 0xFFFFU; + tmp = (tmp < 0x8000U ? tmp : 0x10000U - tmp); + (*freq_error_hz) = tmp * 15625; + return result; +} + +static int xc_get_lock_status(struct xc4000_priv *priv, u16 *lock_status) +{ + return xc4000_readreg(priv, XREG_LOCK, lock_status); +} + +static int xc_get_version(struct xc4000_priv *priv, + u8 *hw_majorversion, u8 *hw_minorversion, + u8 *fw_majorversion, u8 *fw_minorversion) +{ + u16 data; + int result; + + result = xc4000_readreg(priv, XREG_VERSION, &data); + if (result != 0) + return result; + + (*hw_majorversion) = (data >> 12) & 0x0F; + (*hw_minorversion) = (data >> 8) & 0x0F; + (*fw_majorversion) = (data >> 4) & 0x0F; + (*fw_minorversion) = data & 0x0F; + + return 0; +} + +static int xc_get_hsync_freq(struct xc4000_priv *priv, u32 *hsync_freq_hz) +{ + u16 regData; + int result; + + result = xc4000_readreg(priv, XREG_HSYNC_FREQ, ®Data); + if (result != 0) + return result; + + (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; + return result; +} + +static int xc_get_frame_lines(struct xc4000_priv *priv, u16 *frame_lines) +{ + return xc4000_readreg(priv, XREG_FRAME_LINES, frame_lines); +} + +static int xc_get_quality(struct xc4000_priv *priv, u16 *quality) +{ + return xc4000_readreg(priv, XREG_QUALITY, quality); +} + +static int xc_get_signal_level(struct xc4000_priv *priv, u16 *signal) +{ + return xc4000_readreg(priv, XREG_SIGNAL_LEVEL, signal); +} + +static int xc_get_noise_level(struct xc4000_priv *priv, u16 *noise) +{ + return xc4000_readreg(priv, XREG_NOISE_LEVEL, noise); +} + +static u16 xc_wait_for_lock(struct xc4000_priv *priv) +{ + u16 lock_state = 0; + int watchdog_count = 40; + + while ((lock_state == 0) && (watchdog_count > 0)) { + xc_get_lock_status(priv, &lock_state); + if (lock_state != 1) { + msleep(5); + watchdog_count--; + } + } + return lock_state; +} + +static int xc_tune_channel(struct xc4000_priv *priv, u32 freq_hz) +{ + int found = 1; + int result; + + dprintk(1, "%s(%u)\n", __func__, freq_hz); + + /* Don't complain when the request fails because of i2c stretching */ + priv->ignore_i2c_write_errors = 1; + result = xc_set_rf_frequency(priv, freq_hz); + priv->ignore_i2c_write_errors = 0; + + if (result != 0) + return 0; + + /* wait for lock only in analog TV mode */ + if ((priv->cur_fw.type & (FM | DTV6 | DTV7 | DTV78 | DTV8)) == 0) { + if (xc_wait_for_lock(priv) != 1) + found = 0; + } + + /* Wait for stats to stabilize. + * Frame Lines needs two frame times after initial lock + * before it is valid. + */ + msleep(debug ? 100 : 10); + + if (debug) + xc_debug_dump(priv); + + return found; +} + +static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val) +{ + u8 buf[2] = { reg >> 8, reg & 0xff }; + u8 bval[2] = { 0, 0 }; + struct i2c_msg msg[2] = { + { .addr = priv->i2c_props.addr, + .flags = 0, .buf = &buf[0], .len = 2 }, + { .addr = priv->i2c_props.addr, + .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, + }; + + if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) { + printk(KERN_ERR "xc4000: I2C read failed\n"); + return -EREMOTEIO; + } + + *val = (bval[0] << 8) | bval[1]; + return 0; +} + +#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) +static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) +{ + if (type & BASE) + printk(KERN_CONT "BASE "); + if (type & INIT1) + printk(KERN_CONT "INIT1 "); + if (type & F8MHZ) + printk(KERN_CONT "F8MHZ "); + if (type & MTS) + printk(KERN_CONT "MTS "); + if (type & D2620) + printk(KERN_CONT "D2620 "); + if (type & D2633) + printk(KERN_CONT "D2633 "); + if (type & DTV6) + printk(KERN_CONT "DTV6 "); + if (type & QAM) + printk(KERN_CONT "QAM "); + if (type & DTV7) + printk(KERN_CONT "DTV7 "); + if (type & DTV78) + printk(KERN_CONT "DTV78 "); + if (type & DTV8) + printk(KERN_CONT "DTV8 "); + if (type & FM) + printk(KERN_CONT "FM "); + if (type & INPUT1) + printk(KERN_CONT "INPUT1 "); + if (type & LCD) + printk(KERN_CONT "LCD "); + if (type & NOGD) + printk(KERN_CONT "NOGD "); + if (type & MONO) + printk(KERN_CONT "MONO "); + if (type & ATSC) + printk(KERN_CONT "ATSC "); + if (type & IF) + printk(KERN_CONT "IF "); + if (type & LG60) + printk(KERN_CONT "LG60 "); + if (type & ATI638) + printk(KERN_CONT "ATI638 "); + if (type & OREN538) + printk(KERN_CONT "OREN538 "); + if (type & OREN36) + printk(KERN_CONT "OREN36 "); + if (type & TOYOTA388) + printk(KERN_CONT "TOYOTA388 "); + if (type & TOYOTA794) + printk(KERN_CONT "TOYOTA794 "); + if (type & DIBCOM52) + printk(KERN_CONT "DIBCOM52 "); + if (type & ZARLINK456) + printk(KERN_CONT "ZARLINK456 "); + if (type & CHINA) + printk(KERN_CONT "CHINA "); + if (type & F6MHZ) + printk(KERN_CONT "F6MHZ "); + if (type & INPUT2) + printk(KERN_CONT "INPUT2 "); + if (type & SCODE) + printk(KERN_CONT "SCODE "); + if (type & HAS_IF) + printk(KERN_CONT "HAS_IF_%d ", int_freq); +} + +static int seek_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id) +{ + struct xc4000_priv *priv = fe->tuner_priv; + int i, best_i = -1; + unsigned int best_nr_diffs = 255U; + + if (!priv->firm) { + printk(KERN_ERR "Error! firmware not loaded\n"); + return -EINVAL; + } + + if (((type & ~SCODE) == 0) && (*id == 0)) + *id = V4L2_STD_PAL; + + /* Seek for generic video standard match */ + for (i = 0; i < priv->firm_size; i++) { + v4l2_std_id id_diff_mask = + (priv->firm[i].id ^ (*id)) & (*id); + unsigned int type_diff_mask = + (priv->firm[i].type ^ type) + & (BASE_TYPES | DTV_TYPES | LCD | NOGD | MONO | SCODE); + unsigned int nr_diffs; + + if (type_diff_mask + & (BASE | INIT1 | FM | DTV6 | DTV7 | DTV78 | DTV8 | SCODE)) + continue; + + nr_diffs = hweight64(id_diff_mask) + hweight32(type_diff_mask); + if (!nr_diffs) /* Supports all the requested standards */ + goto found; + + if (nr_diffs < best_nr_diffs) { + best_nr_diffs = nr_diffs; + best_i = i; + } + } + + /* FIXME: Would make sense to seek for type "hint" match ? */ + if (best_i < 0) { + i = -ENOENT; + goto ret; + } + + if (best_nr_diffs > 0U) { + printk(KERN_WARNING + "Selecting best matching firmware (%u bits differ) for " + "type=(%x), id %016llx:\n", + best_nr_diffs, type, (unsigned long long)*id); + i = best_i; + } + +found: + *id = priv->firm[i].id; + +ret: + if (debug) { + printk(KERN_DEBUG "%s firmware for type=", + (i < 0) ? "Can't find" : "Found"); + dump_firm_type(type); + printk(KERN_DEBUG "(%x), id %016llx.\n", type, (unsigned long long)*id); + } + return i; +} + +static int load_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id) +{ + struct xc4000_priv *priv = fe->tuner_priv; + int pos, rc; + unsigned char *p; + + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + + p = priv->firm[pos].ptr; + + /* Don't complain when the request fails because of i2c stretching */ + priv->ignore_i2c_write_errors = 1; + + rc = xc_load_i2c_sequence(fe, p); + + priv->ignore_i2c_write_errors = 0; + + return rc; +} + +static int xc4000_fwupload(struct dvb_frontend *fe) +{ + struct xc4000_priv *priv = fe->tuner_priv; + const struct firmware *fw = NULL; + const unsigned char *p, *endp; + int rc = 0; + int n, n_array; + char name[33]; + const char *fname; + + if (firmware_name[0] != '\0') + fname = firmware_name; + else + fname = XC4000_DEFAULT_FIRMWARE; + + dprintk(1, "Reading firmware %s\n", fname); + rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent); + if (rc < 0) { + if (rc == -ENOENT) + printk(KERN_ERR "Error: firmware %s not found.\n", fname); + else + printk(KERN_ERR "Error %d while requesting firmware %s\n", + rc, fname); + + return rc; + } + p = fw->data; + endp = p + fw->size; + + if (fw->size < sizeof(name) - 1 + 2 + 2) { + printk(KERN_ERR "Error: firmware file %s has invalid size!\n", + fname); + goto corrupt; + } + + memcpy(name, p, sizeof(name) - 1); + name[sizeof(name) - 1] = '\0'; + p += sizeof(name) - 1; + + priv->firm_version = get_unaligned_le16(p); + p += 2; + + n_array = get_unaligned_le16(p); + p += 2; + + dprintk(1, "Loading %d firmware images from %s, type: %s, ver %d.%d\n", + n_array, fname, name, + priv->firm_version >> 8, priv->firm_version & 0xff); + + priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL); + if (priv->firm == NULL) { + printk(KERN_ERR "Not enough memory to load firmware file.\n"); + rc = -ENOMEM; + goto done; + } + priv->firm_size = n_array; + + n = -1; + while (p < endp) { + __u32 type, size; + v4l2_std_id id; + __u16 int_freq = 0; + + n++; + if (n >= n_array) { + printk(KERN_ERR "More firmware images in file than " + "were expected!\n"); + goto corrupt; + } + + /* Checks if there's enough bytes to read */ + if (endp - p < sizeof(type) + sizeof(id) + sizeof(size)) + goto header; + + type = get_unaligned_le32(p); + p += sizeof(type); + + id = get_unaligned_le64(p); + p += sizeof(id); + + if (type & HAS_IF) { + int_freq = get_unaligned_le16(p); + p += sizeof(int_freq); + if (endp - p < sizeof(size)) + goto header; + } + + size = get_unaligned_le32(p); + p += sizeof(size); + + if (!size || size > endp - p) { + printk(KERN_ERR "Firmware type (%x), id %llx is corrupted (size=%d, expected %d)\n", + type, (unsigned long long)id, + (unsigned)(endp - p), size); + goto corrupt; + } + + priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); + if (priv->firm[n].ptr == NULL) { + printk(KERN_ERR "Not enough memory to load firmware file.\n"); + rc = -ENOMEM; + goto done; + } + + if (debug) { + printk(KERN_DEBUG "Reading firmware type "); + dump_firm_type_and_int_freq(type, int_freq); + printk(KERN_DEBUG "(%x), id %llx, size=%d.\n", + type, (unsigned long long)id, size); + } + + memcpy(priv->firm[n].ptr, p, size); + priv->firm[n].type = type; + priv->firm[n].id = id; + priv->firm[n].size = size; + priv->firm[n].int_freq = int_freq; + + p += size; + } + + if (n + 1 != priv->firm_size) { + printk(KERN_ERR "Firmware file is incomplete!\n"); + goto corrupt; + } + + goto done; + +header: + printk(KERN_ERR "Firmware header is incomplete!\n"); +corrupt: + rc = -EINVAL; + printk(KERN_ERR "Error: firmware file is corrupted!\n"); + +done: + release_firmware(fw); + if (rc == 0) + dprintk(1, "Firmware files loaded.\n"); + + return rc; +} + +static int load_scode(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id, __u16 int_freq, int scode) +{ + struct xc4000_priv *priv = fe->tuner_priv; + int pos, rc; + unsigned char *p; + u8 scode_buf[13]; + u8 indirect_mode[5]; + + dprintk(1, "%s called int_freq=%d\n", __func__, int_freq); + + if (!int_freq) { + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + } else { + for (pos = 0; pos < priv->firm_size; pos++) { + if ((priv->firm[pos].int_freq == int_freq) && + (priv->firm[pos].type & HAS_IF)) + break; + } + if (pos == priv->firm_size) + return -ENOENT; + } + + p = priv->firm[pos].ptr; + + if (priv->firm[pos].size != 12 * 16 || scode >= 16) + return -EINVAL; + p += 12 * scode; + + if (debug) { + tuner_info("Loading SCODE for type="); + dump_firm_type_and_int_freq(priv->firm[pos].type, + priv->firm[pos].int_freq); + printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type, + (unsigned long long)*id); + } + + scode_buf[0] = 0x00; + memcpy(&scode_buf[1], p, 12); + + /* Enter direct-mode */ + rc = xc_write_reg(priv, XREG_DIRECTSITTING_MODE, 0); + if (rc < 0) { + printk(KERN_ERR "failed to put device into direct mode!\n"); + return -EIO; + } + + rc = xc_send_i2c_data(priv, scode_buf, 13); + if (rc != 0) { + /* Even if the send failed, make sure we set back to indirect + mode */ + printk(KERN_ERR "Failed to set scode %d\n", rc); + } + + /* Switch back to indirect-mode */ + memset(indirect_mode, 0, sizeof(indirect_mode)); + indirect_mode[4] = 0x88; + xc_send_i2c_data(priv, indirect_mode, sizeof(indirect_mode)); + msleep(10); + + return 0; +} + +static int check_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id std, __u16 int_freq) +{ + struct xc4000_priv *priv = fe->tuner_priv; + struct firmware_properties new_fw; + int rc = 0, is_retry = 0; + u16 hwmodel; + v4l2_std_id std0; + u8 hw_major, hw_minor, fw_major, fw_minor; + + dprintk(1, "%s called\n", __func__); + + if (!priv->firm) { + rc = xc4000_fwupload(fe); + if (rc < 0) + return rc; + } + +retry: + new_fw.type = type; + new_fw.id = std; + new_fw.std_req = std; + new_fw.scode_table = SCODE; + new_fw.scode_nr = 0; + new_fw.int_freq = int_freq; + + dprintk(1, "checking firmware, user requested type="); + if (debug) { + dump_firm_type(new_fw.type); + printk(KERN_CONT "(%x), id %016llx, ", new_fw.type, + (unsigned long long)new_fw.std_req); + if (!int_freq) + printk(KERN_CONT "scode_tbl "); + else + printk(KERN_CONT "int_freq %d, ", new_fw.int_freq); + printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr); + } + + /* No need to reload base firmware if it matches */ + if (priv->cur_fw.type & BASE) { + dprintk(1, "BASE firmware not changed.\n"); + goto skip_base; + } + + /* Updating BASE - forget about all currently loaded firmware */ + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); + + /* Reset is needed before loading firmware */ + rc = xc4000_tuner_reset(fe); + if (rc < 0) + goto fail; + + /* BASE firmwares are all std0 */ + std0 = 0; + rc = load_firmware(fe, BASE, &std0); + if (rc < 0) { + printk(KERN_ERR "Error %d while loading base firmware\n", rc); + goto fail; + } + + /* Load INIT1, if needed */ + dprintk(1, "Load init1 firmware, if exists\n"); + + rc = load_firmware(fe, BASE | INIT1, &std0); + if (rc == -ENOENT) + rc = load_firmware(fe, BASE | INIT1, &std0); + if (rc < 0 && rc != -ENOENT) { + tuner_err("Error %d while loading init1 firmware\n", + rc); + goto fail; + } + +skip_base: + /* + * No need to reload standard specific firmware if base firmware + * was not reloaded and requested video standards have not changed. + */ + if (priv->cur_fw.type == (BASE | new_fw.type) && + priv->cur_fw.std_req == std) { + dprintk(1, "Std-specific firmware already loaded.\n"); + goto skip_std_specific; + } + + /* Reloading std-specific firmware forces a SCODE update */ + priv->cur_fw.scode_table = 0; + + /* Load the standard firmware */ + rc = load_firmware(fe, new_fw.type, &new_fw.id); + + if (rc < 0) + goto fail; + +skip_std_specific: + if (priv->cur_fw.scode_table == new_fw.scode_table && + priv->cur_fw.scode_nr == new_fw.scode_nr) { + dprintk(1, "SCODE firmware already loaded.\n"); + goto check_device; + } + + /* Load SCODE firmware, if exists */ + rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, + new_fw.int_freq, new_fw.scode_nr); + if (rc != 0) + dprintk(1, "load scode failed %d\n", rc); + +check_device: + rc = xc4000_readreg(priv, XREG_PRODUCT_ID, &hwmodel); + + if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major, + &fw_minor) != 0) { + printk(KERN_ERR "Unable to read tuner registers.\n"); + goto fail; + } + + dprintk(1, "Device is Xceive %d version %d.%d, " + "firmware version %d.%d\n", + hwmodel, hw_major, hw_minor, fw_major, fw_minor); + + /* Check firmware version against what we downloaded. */ + if (priv->firm_version != ((fw_major << 8) | fw_minor)) { + printk(KERN_WARNING + "Incorrect readback of firmware version %d.%d.\n", + fw_major, fw_minor); + goto fail; + } + + /* Check that the tuner hardware model remains consistent over time. */ + if (priv->hwmodel == 0 && + (hwmodel == XC_PRODUCT_ID_XC4000 || + hwmodel == XC_PRODUCT_ID_XC4100)) { + priv->hwmodel = hwmodel; + priv->hwvers = (hw_major << 8) | hw_minor; + } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || + priv->hwvers != ((hw_major << 8) | hw_minor)) { + printk(KERN_WARNING + "Read invalid device hardware information - tuner " + "hung?\n"); + goto fail; + } + + memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); + + /* + * By setting BASE in cur_fw.type only after successfully loading all + * firmwares, we can: + * 1. Identify that BASE firmware with type=0 has been loaded; + * 2. Tell whether BASE firmware was just changed the next time through. + */ + priv->cur_fw.type |= BASE; + + return 0; + +fail: + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); + if (!is_retry) { + msleep(50); + is_retry = 1; + dprintk(1, "Retrying firmware load\n"); + goto retry; + } + + if (rc == -ENOENT) + rc = -EINVAL; + return rc; +} + +static void xc_debug_dump(struct xc4000_priv *priv) +{ + u16 adc_envelope; + u32 freq_error_hz = 0; + u16 lock_status; + u32 hsync_freq_hz = 0; + u16 frame_lines; + u16 quality; + u16 signal = 0; + u16 noise = 0; + u8 hw_majorversion = 0, hw_minorversion = 0; + u8 fw_majorversion = 0, fw_minorversion = 0; + + xc_get_adc_envelope(priv, &adc_envelope); + dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); + + xc_get_frequency_error(priv, &freq_error_hz); + dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); + + xc_get_lock_status(priv, &lock_status); + dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", + lock_status); + + xc_get_version(priv, &hw_majorversion, &hw_minorversion, + &fw_majorversion, &fw_minorversion); + dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n", + hw_majorversion, hw_minorversion, + fw_majorversion, fw_minorversion); + + if (priv->video_standard < XC4000_DTV6) { + xc_get_hsync_freq(priv, &hsync_freq_hz); + dprintk(1, "*** Horizontal sync frequency = %d Hz\n", + hsync_freq_hz); + + xc_get_frame_lines(priv, &frame_lines); + dprintk(1, "*** Frame lines = %d\n", frame_lines); + } + + xc_get_quality(priv, &quality); + dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); + + xc_get_signal_level(priv, &signal); + dprintk(1, "*** Signal level = -%ddB (%d)\n", signal >> 8, signal); + + xc_get_noise_level(priv, &noise); + dprintk(1, "*** Noise level = %ddB (%d)\n", noise >> 8, noise); +} + +static int xc4000_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; + struct xc4000_priv *priv = fe->tuner_priv; + unsigned int type; + int ret = -EREMOTEIO; + + dprintk(1, "%s() frequency=%d (Hz)\n", __func__, c->frequency); + + mutex_lock(&priv->lock); + + switch (delsys) { + case SYS_ATSC: + dprintk(1, "%s() VSB modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_AIR; + priv->freq_hz = c->frequency - 1750000; + priv->video_standard = XC4000_DTV6; + type = DTV6; + break; + case SYS_DVBC_ANNEX_B: + dprintk(1, "%s() QAM modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_CABLE; + priv->freq_hz = c->frequency - 1750000; + priv->video_standard = XC4000_DTV6; + type = DTV6; + break; + case SYS_DVBT: + case SYS_DVBT2: + dprintk(1, "%s() OFDM\n", __func__); + if (bw == 0) { + if (c->frequency < 400000000) { + priv->freq_hz = c->frequency - 2250000; + } else { + priv->freq_hz = c->frequency - 2750000; + } + priv->video_standard = XC4000_DTV7_8; + type = DTV78; + } else if (bw <= 6000000) { + priv->video_standard = XC4000_DTV6; + priv->freq_hz = c->frequency - 1750000; + type = DTV6; + } else if (bw <= 7000000) { + priv->video_standard = XC4000_DTV7; + priv->freq_hz = c->frequency - 2250000; + type = DTV7; + } else { + priv->video_standard = XC4000_DTV8; + priv->freq_hz = c->frequency - 2750000; + type = DTV8; + } + priv->rf_mode = XC_RF_MODE_AIR; + break; + default: + printk(KERN_ERR "xc4000 delivery system not supported!\n"); + ret = -EINVAL; + goto fail; + } + + dprintk(1, "%s() frequency=%d (compensated)\n", + __func__, priv->freq_hz); + + /* Make sure the correct firmware type is loaded */ + if (check_firmware(fe, type, 0, priv->if_khz) != 0) + goto fail; + + priv->bandwidth = c->bandwidth_hz; + + ret = xc_set_signal_source(priv, priv->rf_mode); + if (ret != 0) { + printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n", + priv->rf_mode); + goto fail; + } else { + u16 video_mode, audio_mode; + video_mode = xc4000_standard[priv->video_standard].video_mode; + audio_mode = xc4000_standard[priv->video_standard].audio_mode; + if (type == DTV6 && priv->firm_version != 0x0102) + video_mode |= 0x0001; + ret = xc_set_tv_standard(priv, video_mode, audio_mode); + if (ret != 0) { + printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n"); + /* DJH - do not return when it fails... */ + /* goto fail; */ + } + } + + if (xc_write_reg(priv, XREG_D_CODE, 0) == 0) + ret = 0; + if (priv->dvb_amplitude != 0) { + if (xc_write_reg(priv, XREG_AMPLITUDE, + (priv->firm_version != 0x0102 || + priv->dvb_amplitude != 134 ? + priv->dvb_amplitude : 132)) != 0) + ret = -EREMOTEIO; + } + if (priv->set_smoothedcvbs != 0) { + if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0) + ret = -EREMOTEIO; + } + if (ret != 0) { + printk(KERN_ERR "xc4000: setting registers failed\n"); + /* goto fail; */ + } + + xc_tune_channel(priv, priv->freq_hz); + + ret = 0; + +fail: + mutex_unlock(&priv->lock); + + return ret; +} + +static int xc4000_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct xc4000_priv *priv = fe->tuner_priv; + unsigned int type = 0; + int ret = -EREMOTEIO; + + if (params->mode == V4L2_TUNER_RADIO) { + dprintk(1, "%s() frequency=%d (in units of 62.5Hz)\n", + __func__, params->frequency); + + mutex_lock(&priv->lock); + + params->std = 0; + priv->freq_hz = params->frequency * 125L / 2; + + if (audio_std & XC4000_AUDIO_STD_INPUT1) { + priv->video_standard = XC4000_FM_Radio_INPUT1; + type = FM | INPUT1; + } else { + priv->video_standard = XC4000_FM_Radio_INPUT2; + type = FM | INPUT2; + } + + goto tune_channel; + } + + dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", + __func__, params->frequency); + + mutex_lock(&priv->lock); + + /* params->frequency is in units of 62.5khz */ + priv->freq_hz = params->frequency * 62500; + + params->std &= V4L2_STD_ALL; + /* if std is not defined, choose one */ + if (!params->std) + params->std = V4L2_STD_PAL_BG; + + if (audio_std & XC4000_AUDIO_STD_MONO) + type = MONO; + + if (params->std & V4L2_STD_MN) { + params->std = V4L2_STD_MN; + if (audio_std & XC4000_AUDIO_STD_MONO) { + priv->video_standard = XC4000_MN_NTSC_PAL_Mono; + } else if (audio_std & XC4000_AUDIO_STD_A2) { + params->std |= V4L2_STD_A2; + priv->video_standard = XC4000_MN_NTSC_PAL_A2; + } else { + params->std |= V4L2_STD_BTSC; + priv->video_standard = XC4000_MN_NTSC_PAL_BTSC; + } + goto tune_channel; + } + + if (params->std & V4L2_STD_PAL_BG) { + params->std = V4L2_STD_PAL_BG; + if (audio_std & XC4000_AUDIO_STD_MONO) { + priv->video_standard = XC4000_BG_PAL_MONO; + } else if (!(audio_std & XC4000_AUDIO_STD_A2)) { + if (!(audio_std & XC4000_AUDIO_STD_B)) { + params->std |= V4L2_STD_NICAM_A; + priv->video_standard = XC4000_BG_PAL_NICAM; + } else { + params->std |= V4L2_STD_NICAM_B; + priv->video_standard = XC4000_BG_PAL_NICAM; + } + } else { + if (!(audio_std & XC4000_AUDIO_STD_B)) { + params->std |= V4L2_STD_A2_A; + priv->video_standard = XC4000_BG_PAL_A2; + } else { + params->std |= V4L2_STD_A2_B; + priv->video_standard = XC4000_BG_PAL_A2; + } + } + goto tune_channel; + } + + if (params->std & V4L2_STD_PAL_I) { + /* default to NICAM audio standard */ + params->std = V4L2_STD_PAL_I | V4L2_STD_NICAM; + if (audio_std & XC4000_AUDIO_STD_MONO) + priv->video_standard = XC4000_I_PAL_NICAM_MONO; + else + priv->video_standard = XC4000_I_PAL_NICAM; + goto tune_channel; + } + + if (params->std & V4L2_STD_PAL_DK) { + params->std = V4L2_STD_PAL_DK; + if (audio_std & XC4000_AUDIO_STD_MONO) { + priv->video_standard = XC4000_DK_PAL_MONO; + } else if (audio_std & XC4000_AUDIO_STD_A2) { + params->std |= V4L2_STD_A2; + priv->video_standard = XC4000_DK_PAL_A2; + } else { + params->std |= V4L2_STD_NICAM; + priv->video_standard = XC4000_DK_PAL_NICAM; + } + goto tune_channel; + } + + if (params->std & V4L2_STD_SECAM_DK) { + /* default to A2 audio standard */ + params->std = V4L2_STD_SECAM_DK | V4L2_STD_A2; + if (audio_std & XC4000_AUDIO_STD_L) { + type = 0; + priv->video_standard = XC4000_DK_SECAM_NICAM; + } else if (audio_std & XC4000_AUDIO_STD_MONO) { + priv->video_standard = XC4000_DK_SECAM_A2MONO; + } else if (audio_std & XC4000_AUDIO_STD_K3) { + params->std |= V4L2_STD_SECAM_K3; + priv->video_standard = XC4000_DK_SECAM_A2LDK3; + } else { + priv->video_standard = XC4000_DK_SECAM_A2DK1; + } + goto tune_channel; + } + + if (params->std & V4L2_STD_SECAM_L) { + /* default to NICAM audio standard */ + type = 0; + params->std = V4L2_STD_SECAM_L | V4L2_STD_NICAM; + priv->video_standard = XC4000_L_SECAM_NICAM; + goto tune_channel; + } + + if (params->std & V4L2_STD_SECAM_LC) { + /* default to NICAM audio standard */ + type = 0; + params->std = V4L2_STD_SECAM_LC | V4L2_STD_NICAM; + priv->video_standard = XC4000_LC_SECAM_NICAM; + goto tune_channel; + } + +tune_channel: + /* FIXME: it could be air. */ + priv->rf_mode = XC_RF_MODE_CABLE; + + if (check_firmware(fe, type, params->std, + xc4000_standard[priv->video_standard].int_freq) != 0) + goto fail; + + ret = xc_set_signal_source(priv, priv->rf_mode); + if (ret != 0) { + printk(KERN_ERR + "xc4000: xc_set_signal_source(%d) failed\n", + priv->rf_mode); + goto fail; + } else { + u16 video_mode, audio_mode; + video_mode = xc4000_standard[priv->video_standard].video_mode; + audio_mode = xc4000_standard[priv->video_standard].audio_mode; + if (priv->video_standard < XC4000_BG_PAL_A2) { + if (type & NOGD) + video_mode &= 0xFF7F; + } else if (priv->video_standard < XC4000_I_PAL_NICAM) { + if (priv->firm_version == 0x0102) + video_mode &= 0xFEFF; + if (audio_std & XC4000_AUDIO_STD_B) + video_mode |= 0x0080; + } + ret = xc_set_tv_standard(priv, video_mode, audio_mode); + if (ret != 0) { + printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n"); + goto fail; + } + } + + if (xc_write_reg(priv, XREG_D_CODE, 0) == 0) + ret = 0; + if (xc_write_reg(priv, XREG_AMPLITUDE, 1) != 0) + ret = -EREMOTEIO; + if (priv->set_smoothedcvbs != 0) { + if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0) + ret = -EREMOTEIO; + } + if (ret != 0) { + printk(KERN_ERR "xc4000: setting registers failed\n"); + goto fail; + } + + xc_tune_channel(priv, priv->freq_hz); + + ret = 0; + +fail: + mutex_unlock(&priv->lock); + + return ret; +} + +static int xc4000_get_signal(struct dvb_frontend *fe, u16 *strength) +{ + struct xc4000_priv *priv = fe->tuner_priv; + u16 value = 0; + int rc; + + mutex_lock(&priv->lock); + rc = xc4000_readreg(priv, XREG_SIGNAL_LEVEL, &value); + mutex_unlock(&priv->lock); + + if (rc < 0) + goto ret; + + /* Informations from real testing of DVB-T and radio part, + coeficient for one dB is 0xff. + */ + tuner_dbg("Signal strength: -%ddB (%05d)\n", value >> 8, value); + + /* all known digital modes */ + if ((priv->video_standard == XC4000_DTV6) || + (priv->video_standard == XC4000_DTV7) || + (priv->video_standard == XC4000_DTV7_8) || + (priv->video_standard == XC4000_DTV8)) + goto digital; + + /* Analog mode has NOISE LEVEL important, signal + depends only on gain of antenna and amplifiers, + but it doesn't tell anything about real quality + of reception. + */ + mutex_lock(&priv->lock); + rc = xc4000_readreg(priv, XREG_NOISE_LEVEL, &value); + mutex_unlock(&priv->lock); + + tuner_dbg("Noise level: %ddB (%05d)\n", value >> 8, value); + + /* highest noise level: 32dB */ + if (value >= 0x2000) { + value = 0; + } else { + value = ~value << 3; + } + + goto ret; + + /* Digital mode has SIGNAL LEVEL important and real + noise level is stored in demodulator registers. + */ +digital: + /* best signal: -50dB */ + if (value <= 0x3200) { + value = 0xffff; + /* minimum: -114dB - should be 0x7200 but real zero is 0x713A */ + } else if (value >= 0x713A) { + value = 0; + } else { + value = ~(value - 0x3200) << 2; + } + +ret: + *strength = value; + + return rc; +} + +static int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq) +{ + struct xc4000_priv *priv = fe->tuner_priv; + + *freq = priv->freq_hz; + + if (debug) { + mutex_lock(&priv->lock); + if ((priv->cur_fw.type + & (BASE | FM | DTV6 | DTV7 | DTV78 | DTV8)) == BASE) { + u16 snr = 0; + if (xc4000_readreg(priv, XREG_SNR, &snr) == 0) { + mutex_unlock(&priv->lock); + dprintk(1, "%s() freq = %u, SNR = %d\n", + __func__, *freq, snr); + return 0; + } + } + mutex_unlock(&priv->lock); + } + + dprintk(1, "%s()\n", __func__); + + return 0; +} + +static int xc4000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) +{ + struct xc4000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + + *bw = priv->bandwidth; + return 0; +} + +static int xc4000_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct xc4000_priv *priv = fe->tuner_priv; + u16 lock_status = 0; + + mutex_lock(&priv->lock); + + if (priv->cur_fw.type & BASE) + xc_get_lock_status(priv, &lock_status); + + *status = (lock_status == 1 ? + TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO : 0); + if (priv->cur_fw.type & (DTV6 | DTV7 | DTV78 | DTV8)) + *status &= (~TUNER_STATUS_STEREO); + + mutex_unlock(&priv->lock); + + dprintk(2, "%s() lock_status = %d\n", __func__, lock_status); + + return 0; +} + +static int xc4000_sleep(struct dvb_frontend *fe) +{ + struct xc4000_priv *priv = fe->tuner_priv; + int ret = 0; + + dprintk(1, "%s()\n", __func__); + + mutex_lock(&priv->lock); + + /* Avoid firmware reload on slow devices */ + if ((no_poweroff == 2 || + (no_poweroff == 0 && priv->default_pm != 0)) && + (priv->cur_fw.type & BASE) != 0) { + /* force reset and firmware reload */ + priv->cur_fw.type = XC_POWERED_DOWN; + + if (xc_write_reg(priv, XREG_POWER_DOWN, 0) != 0) { + printk(KERN_ERR + "xc4000: %s() unable to shutdown tuner\n", + __func__); + ret = -EREMOTEIO; + } + msleep(20); + } + + mutex_unlock(&priv->lock); + + return ret; +} + +static int xc4000_init(struct dvb_frontend *fe) +{ + dprintk(1, "%s()\n", __func__); + + return 0; +} + +static int xc4000_release(struct dvb_frontend *fe) +{ + struct xc4000_priv *priv = fe->tuner_priv; + + dprintk(1, "%s()\n", __func__); + + mutex_lock(&xc4000_list_mutex); + + if (priv) + hybrid_tuner_release_state(priv); + + mutex_unlock(&xc4000_list_mutex); + + fe->tuner_priv = NULL; + + return 0; +} + +static const struct dvb_tuner_ops xc4000_tuner_ops = { + .info = { + .name = "Xceive XC4000", + .frequency_min = 1000000, + .frequency_max = 1023000000, + .frequency_step = 50000, + }, + + .release = xc4000_release, + .init = xc4000_init, + .sleep = xc4000_sleep, + + .set_params = xc4000_set_params, + .set_analog_params = xc4000_set_analog_params, + .get_frequency = xc4000_get_frequency, + .get_rf_strength = xc4000_get_signal, + .get_bandwidth = xc4000_get_bandwidth, + .get_status = xc4000_get_status +}; + +struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct xc4000_config *cfg) +{ + struct xc4000_priv *priv = NULL; + int instance; + u16 id = 0; + + dprintk(1, "%s(%d-%04x)\n", __func__, + i2c ? i2c_adapter_id(i2c) : -1, + cfg ? cfg->i2c_address : -1); + + mutex_lock(&xc4000_list_mutex); + + instance = hybrid_tuner_request_state(struct xc4000_priv, priv, + hybrid_tuner_instance_list, + i2c, cfg->i2c_address, "xc4000"); + switch (instance) { + case 0: + goto fail; + break; + case 1: + /* new tuner instance */ + priv->bandwidth = 6000000; + /* set default configuration */ + priv->if_khz = 4560; + priv->default_pm = 0; + priv->dvb_amplitude = 134; + priv->set_smoothedcvbs = 1; + mutex_init(&priv->lock); + fe->tuner_priv = priv; + break; + default: + /* existing tuner instance */ + fe->tuner_priv = priv; + break; + } + + if (cfg->if_khz != 0) { + /* copy configuration if provided by the caller */ + priv->if_khz = cfg->if_khz; + priv->default_pm = cfg->default_pm; + priv->dvb_amplitude = cfg->dvb_amplitude; + priv->set_smoothedcvbs = cfg->set_smoothedcvbs; + } + + /* Check if firmware has been loaded. It is possible that another + instance of the driver has loaded the firmware. + */ + + if (instance == 1) { + if (xc4000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) + goto fail; + } else { + id = ((priv->cur_fw.type & BASE) != 0 ? + priv->hwmodel : XC_PRODUCT_ID_FW_NOT_LOADED); + } + + switch (id) { + case XC_PRODUCT_ID_XC4000: + case XC_PRODUCT_ID_XC4100: + printk(KERN_INFO + "xc4000: Successfully identified at address 0x%02x\n", + cfg->i2c_address); + printk(KERN_INFO + "xc4000: Firmware has been loaded previously\n"); + break; + case XC_PRODUCT_ID_FW_NOT_LOADED: + printk(KERN_INFO + "xc4000: Successfully identified at address 0x%02x\n", + cfg->i2c_address); + printk(KERN_INFO + "xc4000: Firmware has not been loaded previously\n"); + break; + default: + printk(KERN_ERR + "xc4000: Device not found at addr 0x%02x (0x%x)\n", + cfg->i2c_address, id); + goto fail; + } + + mutex_unlock(&xc4000_list_mutex); + + memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + if (instance == 1) { + int ret; + mutex_lock(&priv->lock); + ret = xc4000_fwupload(fe); + mutex_unlock(&priv->lock); + if (ret != 0) + goto fail2; + } + + return fe; +fail: + mutex_unlock(&xc4000_list_mutex); +fail2: + xc4000_release(fe); + return NULL; +} +EXPORT_SYMBOL(xc4000_attach); + +MODULE_AUTHOR("Steven Toth, Davide Ferri"); +MODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/xc4000.h b/drivers/media/tuners/xc4000.h new file mode 100644 index 000000000000..e6a44d151cbd --- /dev/null +++ b/drivers/media/tuners/xc4000.h @@ -0,0 +1,67 @@ +/* + * Driver for Xceive XC4000 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2007 Steven Toth + * + * 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 __XC4000_H__ +#define __XC4000_H__ + +#include + +struct dvb_frontend; +struct i2c_adapter; + +struct xc4000_config { + u8 i2c_address; + /* if non-zero, power management is enabled by default */ + u8 default_pm; + /* value to be written to XREG_AMPLITUDE in DVB-T mode (0: no write) */ + u8 dvb_amplitude; + /* if non-zero, register 0x0E is set to filter analog TV video output */ + u8 set_smoothedcvbs; + /* IF for DVB-T */ + u32 if_khz; +}; + +/* xc4000 callback command */ +#define XC4000_TUNER_RESET 0 + +/* For each bridge framework, when it attaches either analog or digital, + * it has to store a reference back to its _core equivalent structure, + * so that it can service the hardware by steering gpio's etc. + * Each bridge implementation is different so cast devptr accordingly. + * The xc4000 driver cares not for this value, other than ensuring + * it's passed back to a bridge during tuner_callback(). + */ + +#if defined(CONFIG_MEDIA_TUNER_XC4000) || (defined(CONFIG_MEDIA_TUNER_XC4000_MODULE) && defined(MODULE)) +extern struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct xc4000_config *cfg); +#else +static inline struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct xc4000_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c new file mode 100644 index 000000000000..dc93cf338f36 --- /dev/null +++ b/drivers/media/tuners/xc5000.c @@ -0,0 +1,1366 @@ +/* + * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2007 Xceive Corporation + * Copyright (c) 2007 Steven Toth + * Copyright (c) 2009 Devin Heitmueller + * + * 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 +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "xc5000.h" +#include "tuner-i2c.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +static int no_poweroff; +module_param(no_poweroff, int, 0644); +MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" + "\t\t1 keep device energized and with tuner ready all the times.\n" + "\t\tFaster, but consumes more power and keeps the device hotter"); + +static DEFINE_MUTEX(xc5000_list_mutex); +static LIST_HEAD(hybrid_tuner_instance_list); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) + +struct xc5000_priv { + struct tuner_i2c_props i2c_props; + struct list_head hybrid_tuner_instance_list; + + u32 if_khz; + u16 xtal_khz; + u32 freq_hz; + u32 bandwidth; + u8 video_standard; + u8 rf_mode; + u8 radio_input; + + int chip_id; + u16 pll_register_no; + u8 init_status_supported; + u8 fw_checksum_supported; +}; + +/* Misc Defines */ +#define MAX_TV_STANDARD 24 +#define XC_MAX_I2C_WRITE_LENGTH 64 + +/* Signal Types */ +#define XC_RF_MODE_AIR 0 +#define XC_RF_MODE_CABLE 1 + +/* Result codes */ +#define XC_RESULT_SUCCESS 0 +#define XC_RESULT_RESET_FAILURE 1 +#define XC_RESULT_I2C_WRITE_FAILURE 2 +#define XC_RESULT_I2C_READ_FAILURE 3 +#define XC_RESULT_OUT_OF_RANGE 5 + +/* Product id */ +#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 +#define XC_PRODUCT_ID_FW_LOADED 0x1388 + +/* Registers */ +#define XREG_INIT 0x00 +#define XREG_VIDEO_MODE 0x01 +#define XREG_AUDIO_MODE 0x02 +#define XREG_RF_FREQ 0x03 +#define XREG_D_CODE 0x04 +#define XREG_IF_OUT 0x05 +#define XREG_SEEK_MODE 0x07 +#define XREG_POWER_DOWN 0x0A /* Obsolete */ +/* Set the output amplitude - SIF for analog, DTVP/DTVN for digital */ +#define XREG_OUTPUT_AMP 0x0B +#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */ +#define XREG_SMOOTHEDCVBS 0x0E +#define XREG_XTALFREQ 0x0F +#define XREG_FINERFREQ 0x10 +#define XREG_DDIMODE 0x11 + +#define XREG_ADC_ENV 0x00 +#define XREG_QUALITY 0x01 +#define XREG_FRAME_LINES 0x02 +#define XREG_HSYNC_FREQ 0x03 +#define XREG_LOCK 0x04 +#define XREG_FREQ_ERROR 0x05 +#define XREG_SNR 0x06 +#define XREG_VERSION 0x07 +#define XREG_PRODUCT_ID 0x08 +#define XREG_BUSY 0x09 +#define XREG_BUILD 0x0D +#define XREG_TOTALGAIN 0x0F +#define XREG_FW_CHECKSUM 0x12 +#define XREG_INIT_STATUS 0x13 + +/* + Basic firmware description. This will remain with + the driver for documentation purposes. + + This represents an I2C firmware file encoded as a + string of unsigned char. Format is as follows: + + char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB + char[1 ]=len0_LSB -> length of first write transaction + char[2 ]=data0 -> first byte to be sent + char[3 ]=data1 + char[4 ]=data2 + char[ ]=... + char[M ]=dataN -> last byte to be sent + char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB + char[M+2]=len1_LSB -> length of second write transaction + char[M+3]=data0 + char[M+4]=data1 + ... + etc. + + The [len] value should be interpreted as follows: + + len= len_MSB _ len_LSB + len=1111_1111_1111_1111 : End of I2C_SEQUENCE + len=0000_0000_0000_0000 : Reset command: Do hardware reset + len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) + len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms + + For the RESET and WAIT commands, the two following bytes will contain + immediately the length of the following transaction. + +*/ +struct XC_TV_STANDARD { + char *Name; + u16 AudioMode; + u16 VideoMode; +}; + +/* Tuner standards */ +#define MN_NTSC_PAL_BTSC 0 +#define MN_NTSC_PAL_A2 1 +#define MN_NTSC_PAL_EIAJ 2 +#define MN_NTSC_PAL_Mono 3 +#define BG_PAL_A2 4 +#define BG_PAL_NICAM 5 +#define BG_PAL_MONO 6 +#define I_PAL_NICAM 7 +#define I_PAL_NICAM_MONO 8 +#define DK_PAL_A2 9 +#define DK_PAL_NICAM 10 +#define DK_PAL_MONO 11 +#define DK_SECAM_A2DK1 12 +#define DK_SECAM_A2LDK3 13 +#define DK_SECAM_A2MONO 14 +#define L_SECAM_NICAM 15 +#define LC_SECAM_NICAM 16 +#define DTV6 17 +#define DTV8 18 +#define DTV7_8 19 +#define DTV7 20 +#define FM_Radio_INPUT2 21 +#define FM_Radio_INPUT1 22 +#define FM_Radio_INPUT1_MONO 23 + +static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { + {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020}, + {"M/N-NTSC/PAL-A2", 0x0600, 0x8020}, + {"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020}, + {"M/N-NTSC/PAL-Mono", 0x0478, 0x8020}, + {"B/G-PAL-A2", 0x0A00, 0x8049}, + {"B/G-PAL-NICAM", 0x0C04, 0x8049}, + {"B/G-PAL-MONO", 0x0878, 0x8059}, + {"I-PAL-NICAM", 0x1080, 0x8009}, + {"I-PAL-NICAM-MONO", 0x0E78, 0x8009}, + {"D/K-PAL-A2", 0x1600, 0x8009}, + {"D/K-PAL-NICAM", 0x0E80, 0x8009}, + {"D/K-PAL-MONO", 0x1478, 0x8009}, + {"D/K-SECAM-A2 DK1", 0x1200, 0x8009}, + {"D/K-SECAM-A2 L/DK3", 0x0E00, 0x8009}, + {"D/K-SECAM-A2 MONO", 0x1478, 0x8009}, + {"L-SECAM-NICAM", 0x8E82, 0x0009}, + {"L'-SECAM-NICAM", 0x8E82, 0x4009}, + {"DTV6", 0x00C0, 0x8002}, + {"DTV8", 0x00C0, 0x800B}, + {"DTV7/8", 0x00C0, 0x801B}, + {"DTV7", 0x00C0, 0x8007}, + {"FM Radio-INPUT2", 0x9802, 0x9002}, + {"FM Radio-INPUT1", 0x0208, 0x9002}, + {"FM Radio-INPUT1_MONO", 0x0278, 0x9002} +}; + + +struct xc5000_fw_cfg { + char *name; + u16 size; + u16 pll_reg; + u8 init_status_supported; + u8 fw_checksum_supported; +}; + +#define XC5000A_FIRMWARE "dvb-fe-xc5000-1.6.114.fw" +static const struct xc5000_fw_cfg xc5000a_1_6_114 = { + .name = XC5000A_FIRMWARE, + .size = 12401, + .pll_reg = 0x806c, +}; + +#define XC5000C_FIRMWARE "dvb-fe-xc5000c-4.1.30.7.fw" +static const struct xc5000_fw_cfg xc5000c_41_024_5 = { + .name = XC5000C_FIRMWARE, + .size = 16497, + .pll_reg = 0x13, + .init_status_supported = 1, + .fw_checksum_supported = 1, +}; + +static inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id) +{ + switch (chip_id) { + default: + case XC5000A: + return &xc5000a_1_6_114; + case XC5000C: + return &xc5000c_41_024_5; + } +} + +static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force); +static int xc5000_is_firmware_loaded(struct dvb_frontend *fe); +static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val); +static int xc5000_TunerReset(struct dvb_frontend *fe); + +static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) +{ + struct i2c_msg msg = { .addr = priv->i2c_props.addr, + .flags = 0, .buf = buf, .len = len }; + + if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { + printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len); + return XC_RESULT_I2C_WRITE_FAILURE; + } + return XC_RESULT_SUCCESS; +} + +#if 0 +/* This routine is never used because the only time we read data from the + i2c bus is when we read registers, and we want that to be an atomic i2c + transaction in case we are on a multi-master bus */ +static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) +{ + struct i2c_msg msg = { .addr = priv->i2c_props.addr, + .flags = I2C_M_RD, .buf = buf, .len = len }; + + if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { + printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len); + return -EREMOTEIO; + } + return 0; +} +#endif + +static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) +{ + u8 buf[2] = { reg >> 8, reg & 0xff }; + u8 bval[2] = { 0, 0 }; + struct i2c_msg msg[2] = { + { .addr = priv->i2c_props.addr, + .flags = 0, .buf = &buf[0], .len = 2 }, + { .addr = priv->i2c_props.addr, + .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, + }; + + if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) { + printk(KERN_WARNING "xc5000: I2C read failed\n"); + return -EREMOTEIO; + } + + *val = (bval[0] << 8) | bval[1]; + return XC_RESULT_SUCCESS; +} + +static void xc_wait(int wait_ms) +{ + msleep(wait_ms); +} + +static int xc5000_TunerReset(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + + dprintk(1, "%s()\n", __func__); + + if (fe->callback) { + ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ? + fe->dvb->priv : + priv->i2c_props.adap->algo_data, + DVB_FRONTEND_COMPONENT_TUNER, + XC5000_TUNER_RESET, 0); + if (ret) { + printk(KERN_ERR "xc5000: reset failed\n"); + return XC_RESULT_RESET_FAILURE; + } + } else { + printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n"); + return XC_RESULT_RESET_FAILURE; + } + return XC_RESULT_SUCCESS; +} + +static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) +{ + u8 buf[4]; + int WatchDogTimer = 100; + int result; + + buf[0] = (regAddr >> 8) & 0xFF; + buf[1] = regAddr & 0xFF; + buf[2] = (i2cData >> 8) & 0xFF; + buf[3] = i2cData & 0xFF; + result = xc_send_i2c_data(priv, buf, 4); + if (result == XC_RESULT_SUCCESS) { + /* wait for busy flag to clear */ + while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) { + result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf); + if (result == XC_RESULT_SUCCESS) { + if ((buf[0] == 0) && (buf[1] == 0)) { + /* busy flag cleared */ + break; + } else { + xc_wait(5); /* wait 5 ms */ + WatchDogTimer--; + } + } + } + } + if (WatchDogTimer <= 0) + result = XC_RESULT_I2C_WRITE_FAILURE; + + return result; +} + +static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) +{ + struct xc5000_priv *priv = fe->tuner_priv; + + int i, nbytes_to_send, result; + unsigned int len, pos, index; + u8 buf[XC_MAX_I2C_WRITE_LENGTH]; + + index = 0; + while ((i2c_sequence[index] != 0xFF) || + (i2c_sequence[index + 1] != 0xFF)) { + len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; + if (len == 0x0000) { + /* RESET command */ + result = xc5000_TunerReset(fe); + index += 2; + if (result != XC_RESULT_SUCCESS) + return result; + } else if (len & 0x8000) { + /* WAIT command */ + xc_wait(len & 0x7FFF); + index += 2; + } else { + /* Send i2c data whilst ensuring individual transactions + * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. + */ + index += 2; + buf[0] = i2c_sequence[index]; + buf[1] = i2c_sequence[index + 1]; + pos = 2; + while (pos < len) { + if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) + nbytes_to_send = + XC_MAX_I2C_WRITE_LENGTH; + else + nbytes_to_send = (len - pos + 2); + for (i = 2; i < nbytes_to_send; i++) { + buf[i] = i2c_sequence[index + pos + + i - 2]; + } + result = xc_send_i2c_data(priv, buf, + nbytes_to_send); + + if (result != XC_RESULT_SUCCESS) + return result; + + pos += nbytes_to_send - 2; + } + index += len; + } + } + return XC_RESULT_SUCCESS; +} + +static int xc_initialize(struct xc5000_priv *priv) +{ + dprintk(1, "%s()\n", __func__); + return xc_write_reg(priv, XREG_INIT, 0); +} + +static int xc_SetTVStandard(struct xc5000_priv *priv, + u16 VideoMode, u16 AudioMode) +{ + int ret; + dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, VideoMode, AudioMode); + dprintk(1, "%s() Standard = %s\n", + __func__, + XC5000_Standard[priv->video_standard].Name); + + ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode); + if (ret == XC_RESULT_SUCCESS) + ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode); + + return ret; +} + +static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) +{ + dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, + rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); + + if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) { + rf_mode = XC_RF_MODE_CABLE; + printk(KERN_ERR + "%s(), Invalid mode, defaulting to CABLE", + __func__); + } + return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); +} + +static const struct dvb_tuner_ops xc5000_tuner_ops; + +static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz) +{ + u16 freq_code; + + dprintk(1, "%s(%u)\n", __func__, freq_hz); + + if ((freq_hz > xc5000_tuner_ops.info.frequency_max) || + (freq_hz < xc5000_tuner_ops.info.frequency_min)) + return XC_RESULT_OUT_OF_RANGE; + + freq_code = (u16)(freq_hz / 15625); + + /* Starting in firmware version 1.1.44, Xceive recommends using the + FINERFREQ for all normal tuning (the doc indicates reg 0x03 should + only be used for fast scanning for channel lock) */ + return xc_write_reg(priv, XREG_FINERFREQ, freq_code); +} + + +static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz) +{ + u32 freq_code = (freq_khz * 1024)/1000; + dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n", + __func__, freq_khz, freq_code); + + return xc_write_reg(priv, XREG_IF_OUT, freq_code); +} + + +static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope) +{ + return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope); +} + +static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) +{ + int result; + u16 regData; + u32 tmp; + + result = xc5000_readreg(priv, XREG_FREQ_ERROR, ®Data); + if (result != XC_RESULT_SUCCESS) + return result; + + tmp = (u32)regData; + (*freq_error_hz) = (tmp * 15625) / 1000; + return result; +} + +static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status) +{ + return xc5000_readreg(priv, XREG_LOCK, lock_status); +} + +static int xc_get_version(struct xc5000_priv *priv, + u8 *hw_majorversion, u8 *hw_minorversion, + u8 *fw_majorversion, u8 *fw_minorversion) +{ + u16 data; + int result; + + result = xc5000_readreg(priv, XREG_VERSION, &data); + if (result != XC_RESULT_SUCCESS) + return result; + + (*hw_majorversion) = (data >> 12) & 0x0F; + (*hw_minorversion) = (data >> 8) & 0x0F; + (*fw_majorversion) = (data >> 4) & 0x0F; + (*fw_minorversion) = data & 0x0F; + + return 0; +} + +static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev) +{ + return xc5000_readreg(priv, XREG_BUILD, buildrev); +} + +static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz) +{ + u16 regData; + int result; + + result = xc5000_readreg(priv, XREG_HSYNC_FREQ, ®Data); + if (result != XC_RESULT_SUCCESS) + return result; + + (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; + return result; +} + +static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines) +{ + return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines); +} + +static int xc_get_quality(struct xc5000_priv *priv, u16 *quality) +{ + return xc5000_readreg(priv, XREG_QUALITY, quality); +} + +static int xc_get_analogsnr(struct xc5000_priv *priv, u16 *snr) +{ + return xc5000_readreg(priv, XREG_SNR, snr); +} + +static int xc_get_totalgain(struct xc5000_priv *priv, u16 *totalgain) +{ + return xc5000_readreg(priv, XREG_TOTALGAIN, totalgain); +} + +static u16 WaitForLock(struct xc5000_priv *priv) +{ + u16 lockState = 0; + int watchDogCount = 40; + + while ((lockState == 0) && (watchDogCount > 0)) { + xc_get_lock_status(priv, &lockState); + if (lockState != 1) { + xc_wait(5); + watchDogCount--; + } + } + return lockState; +} + +#define XC_TUNE_ANALOG 0 +#define XC_TUNE_DIGITAL 1 +static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode) +{ + int found = 0; + + dprintk(1, "%s(%u)\n", __func__, freq_hz); + + if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS) + return 0; + + if (mode == XC_TUNE_ANALOG) { + if (WaitForLock(priv) == 1) + found = 1; + } + + return found; +} + +static int xc_set_xtal(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret = XC_RESULT_SUCCESS; + + switch (priv->chip_id) { + default: + case XC5000A: + /* 32.000 MHz xtal is default */ + break; + case XC5000C: + switch (priv->xtal_khz) { + default: + case 32000: + /* 32.000 MHz xtal is default */ + break; + case 31875: + /* 31.875 MHz xtal configuration */ + ret = xc_write_reg(priv, 0x000f, 0x8081); + break; + } + break; + } + return ret; +} + +static int xc5000_fwupload(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + const struct firmware *fw; + int ret; + const struct xc5000_fw_cfg *desired_fw = + xc5000_assign_firmware(priv->chip_id); + priv->pll_register_no = desired_fw->pll_reg; + priv->init_status_supported = desired_fw->init_status_supported; + priv->fw_checksum_supported = desired_fw->fw_checksum_supported; + + /* request the firmware, this will block and timeout */ + printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", + desired_fw->name); + + ret = request_firmware(&fw, desired_fw->name, + priv->i2c_props.adap->dev.parent); + if (ret) { + printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); + ret = XC_RESULT_RESET_FAILURE; + goto out; + } else { + printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n", + fw->size); + ret = XC_RESULT_SUCCESS; + } + + if (fw->size != desired_fw->size) { + printk(KERN_ERR "xc5000: firmware incorrect size\n"); + ret = XC_RESULT_RESET_FAILURE; + } else { + printk(KERN_INFO "xc5000: firmware uploading...\n"); + ret = xc_load_i2c_sequence(fe, fw->data); + if (XC_RESULT_SUCCESS == ret) + ret = xc_set_xtal(fe); + if (XC_RESULT_SUCCESS == ret) + printk(KERN_INFO "xc5000: firmware upload complete...\n"); + else + printk(KERN_ERR "xc5000: firmware upload failed...\n"); + } + +out: + release_firmware(fw); + return ret; +} + +static void xc_debug_dump(struct xc5000_priv *priv) +{ + u16 adc_envelope; + u32 freq_error_hz = 0; + u16 lock_status; + u32 hsync_freq_hz = 0; + u16 frame_lines; + u16 quality; + u16 snr; + u16 totalgain; + u8 hw_majorversion = 0, hw_minorversion = 0; + u8 fw_majorversion = 0, fw_minorversion = 0; + u16 fw_buildversion = 0; + u16 regval; + + /* Wait for stats to stabilize. + * Frame Lines needs two frame times after initial lock + * before it is valid. + */ + xc_wait(100); + + xc_get_ADC_Envelope(priv, &adc_envelope); + dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); + + xc_get_frequency_error(priv, &freq_error_hz); + dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); + + xc_get_lock_status(priv, &lock_status); + dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", + lock_status); + + xc_get_version(priv, &hw_majorversion, &hw_minorversion, + &fw_majorversion, &fw_minorversion); + xc_get_buildversion(priv, &fw_buildversion); + dprintk(1, "*** HW: V%d.%d, FW: V %d.%d.%d\n", + hw_majorversion, hw_minorversion, + fw_majorversion, fw_minorversion, fw_buildversion); + + xc_get_hsync_freq(priv, &hsync_freq_hz); + dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz); + + xc_get_frame_lines(priv, &frame_lines); + dprintk(1, "*** Frame lines = %d\n", frame_lines); + + xc_get_quality(priv, &quality); + dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality & 0x07); + + xc_get_analogsnr(priv, &snr); + dprintk(1, "*** Unweighted analog SNR = %d dB\n", snr & 0x3f); + + xc_get_totalgain(priv, &totalgain); + dprintk(1, "*** Total gain = %d.%d dB\n", totalgain / 256, + (totalgain % 256) * 100 / 256); + + if (priv->pll_register_no) { + xc5000_readreg(priv, priv->pll_register_no, ®val); + dprintk(1, "*** PLL lock status = 0x%04x\n", regval); + } +} + +static int xc5000_set_params(struct dvb_frontend *fe) +{ + int ret, b; + struct xc5000_priv *priv = fe->tuner_priv; + u32 bw = fe->dtv_property_cache.bandwidth_hz; + u32 freq = fe->dtv_property_cache.frequency; + u32 delsys = fe->dtv_property_cache.delivery_system; + + if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) { + dprintk(1, "Unable to load firmware and init tuner\n"); + return -EINVAL; + } + + dprintk(1, "%s() frequency=%d (Hz)\n", __func__, freq); + + switch (delsys) { + case SYS_ATSC: + dprintk(1, "%s() VSB modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_AIR; + priv->freq_hz = freq - 1750000; + priv->video_standard = DTV6; + break; + case SYS_DVBC_ANNEX_B: + dprintk(1, "%s() QAM modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_CABLE; + priv->freq_hz = freq - 1750000; + priv->video_standard = DTV6; + break; + case SYS_ISDBT: + /* All ISDB-T are currently for 6 MHz bw */ + if (!bw) + bw = 6000000; + /* fall to OFDM handling */ + case SYS_DMBTH: + case SYS_DVBT: + case SYS_DVBT2: + dprintk(1, "%s() OFDM\n", __func__); + switch (bw) { + case 6000000: + priv->video_standard = DTV6; + priv->freq_hz = freq - 1750000; + break; + case 7000000: + priv->video_standard = DTV7; + priv->freq_hz = freq - 2250000; + break; + case 8000000: + priv->video_standard = DTV8; + priv->freq_hz = freq - 2750000; + break; + default: + printk(KERN_ERR "xc5000 bandwidth not set!\n"); + return -EINVAL; + } + priv->rf_mode = XC_RF_MODE_AIR; + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + dprintk(1, "%s() QAM modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_CABLE; + if (bw <= 6000000) { + priv->video_standard = DTV6; + priv->freq_hz = freq - 1750000; + b = 6; + } else if (bw <= 7000000) { + priv->video_standard = DTV7; + priv->freq_hz = freq - 2250000; + b = 7; + } else { + priv->video_standard = DTV7_8; + priv->freq_hz = freq - 2750000; + b = 8; + } + dprintk(1, "%s() Bandwidth %dMHz (%d)\n", __func__, + b, bw); + break; + default: + printk(KERN_ERR "xc5000: delivery system is not supported!\n"); + return -EINVAL; + } + + dprintk(1, "%s() frequency=%d (compensated to %d)\n", + __func__, freq, priv->freq_hz); + + ret = xc_SetSignalSource(priv, priv->rf_mode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR + "xc5000: xc_SetSignalSource(%d) failed\n", + priv->rf_mode); + return -EREMOTEIO; + } + + ret = xc_SetTVStandard(priv, + XC5000_Standard[priv->video_standard].VideoMode, + XC5000_Standard[priv->video_standard].AudioMode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); + return -EREMOTEIO; + } + + ret = xc_set_IF_frequency(priv, priv->if_khz); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", + priv->if_khz); + return -EIO; + } + + xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a); + + xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); + + if (debug) + xc_debug_dump(priv); + + priv->bandwidth = bw; + + return 0; +} + +static int xc5000_is_firmware_loaded(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + u16 id; + + ret = xc5000_readreg(priv, XREG_PRODUCT_ID, &id); + if (ret == XC_RESULT_SUCCESS) { + if (id == XC_PRODUCT_ID_FW_NOT_LOADED) + ret = XC_RESULT_RESET_FAILURE; + else + ret = XC_RESULT_SUCCESS; + } + + dprintk(1, "%s() returns %s id = 0x%x\n", __func__, + ret == XC_RESULT_SUCCESS ? "True" : "False", id); + return ret; +} + +static int xc5000_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct xc5000_priv *priv = fe->tuner_priv; + u16 pll_lock_status; + int ret; + + dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", + __func__, params->frequency); + + /* Fix me: it could be air. */ + priv->rf_mode = params->mode; + if (params->mode > XC_RF_MODE_CABLE) + priv->rf_mode = XC_RF_MODE_CABLE; + + /* params->frequency is in units of 62.5khz */ + priv->freq_hz = params->frequency * 62500; + + /* FIX ME: Some video standards may have several possible audio + standards. We simply default to one of them here. + */ + if (params->std & V4L2_STD_MN) { + /* default to BTSC audio standard */ + priv->video_standard = MN_NTSC_PAL_BTSC; + goto tune_channel; + } + + if (params->std & V4L2_STD_PAL_BG) { + /* default to NICAM audio standard */ + priv->video_standard = BG_PAL_NICAM; + goto tune_channel; + } + + if (params->std & V4L2_STD_PAL_I) { + /* default to NICAM audio standard */ + priv->video_standard = I_PAL_NICAM; + goto tune_channel; + } + + if (params->std & V4L2_STD_PAL_DK) { + /* default to NICAM audio standard */ + priv->video_standard = DK_PAL_NICAM; + goto tune_channel; + } + + if (params->std & V4L2_STD_SECAM_DK) { + /* default to A2 DK1 audio standard */ + priv->video_standard = DK_SECAM_A2DK1; + goto tune_channel; + } + + if (params->std & V4L2_STD_SECAM_L) { + priv->video_standard = L_SECAM_NICAM; + goto tune_channel; + } + + if (params->std & V4L2_STD_SECAM_LC) { + priv->video_standard = LC_SECAM_NICAM; + goto tune_channel; + } + +tune_channel: + ret = xc_SetSignalSource(priv, priv->rf_mode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR + "xc5000: xc_SetSignalSource(%d) failed\n", + priv->rf_mode); + return -EREMOTEIO; + } + + ret = xc_SetTVStandard(priv, + XC5000_Standard[priv->video_standard].VideoMode, + XC5000_Standard[priv->video_standard].AudioMode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); + return -EREMOTEIO; + } + + xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); + + xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); + + if (debug) + xc_debug_dump(priv); + + if (priv->pll_register_no != 0) { + msleep(20); + xc5000_readreg(priv, priv->pll_register_no, &pll_lock_status); + if (pll_lock_status > 63) { + /* PLL is unlocked, force reload of the firmware */ + dprintk(1, "xc5000: PLL not locked (0x%x). Reloading...\n", + pll_lock_status); + if (xc_load_fw_and_init_tuner(fe, 1) != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: Unable to reload fw\n"); + return -EREMOTEIO; + } + goto tune_channel; + } + } + + return 0; +} + +static int xc5000_set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + u8 radio_input; + + dprintk(1, "%s() frequency=%d (in units of khz)\n", + __func__, params->frequency); + + if (priv->radio_input == XC5000_RADIO_NOT_CONFIGURED) { + dprintk(1, "%s() radio input not configured\n", __func__); + return -EINVAL; + } + + if (priv->radio_input == XC5000_RADIO_FM1) + radio_input = FM_Radio_INPUT1; + else if (priv->radio_input == XC5000_RADIO_FM2) + radio_input = FM_Radio_INPUT2; + else if (priv->radio_input == XC5000_RADIO_FM1_MONO) + radio_input = FM_Radio_INPUT1_MONO; + else { + dprintk(1, "%s() unknown radio input %d\n", __func__, + priv->radio_input); + return -EINVAL; + } + + priv->freq_hz = params->frequency * 125 / 2; + + priv->rf_mode = XC_RF_MODE_AIR; + + ret = xc_SetTVStandard(priv, XC5000_Standard[radio_input].VideoMode, + XC5000_Standard[radio_input].AudioMode); + + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); + return -EREMOTEIO; + } + + ret = xc_SetSignalSource(priv, priv->rf_mode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR + "xc5000: xc_SetSignalSource(%d) failed\n", + priv->rf_mode); + return -EREMOTEIO; + } + + if ((priv->radio_input == XC5000_RADIO_FM1) || + (priv->radio_input == XC5000_RADIO_FM2)) + xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); + else if (priv->radio_input == XC5000_RADIO_FM1_MONO) + xc_write_reg(priv, XREG_OUTPUT_AMP, 0x06); + + xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); + + return 0; +} + +static int xc5000_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + if (priv->i2c_props.adap == NULL) + return -EINVAL; + + if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) { + dprintk(1, "Unable to load firmware and init tuner\n"); + return -EINVAL; + } + + switch (params->mode) { + case V4L2_TUNER_RADIO: + ret = xc5000_set_radio_freq(fe, params); + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + ret = xc5000_set_tv_freq(fe, params); + break; + } + + return ret; +} + + +static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) +{ + struct xc5000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + *freq = priv->freq_hz; + return 0; +} + +static int xc5000_get_if_frequency(struct dvb_frontend *fe, u32 *freq) +{ + struct xc5000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + *freq = priv->if_khz * 1000; + return 0; +} + +static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) +{ + struct xc5000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + + *bw = priv->bandwidth; + return 0; +} + +static int xc5000_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct xc5000_priv *priv = fe->tuner_priv; + u16 lock_status = 0; + + xc_get_lock_status(priv, &lock_status); + + dprintk(1, "%s() lock_status = 0x%08x\n", __func__, lock_status); + + *status = lock_status; + + return 0; +} + +static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret = XC_RESULT_SUCCESS; + u16 pll_lock_status; + u16 fw_ck; + + if (force || xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) { + +fw_retry: + + ret = xc5000_fwupload(fe); + if (ret != XC_RESULT_SUCCESS) + return ret; + + msleep(20); + + if (priv->fw_checksum_supported) { + if (xc5000_readreg(priv, XREG_FW_CHECKSUM, &fw_ck) + != XC_RESULT_SUCCESS) { + dprintk(1, "%s() FW checksum reading failed.\n", + __func__); + goto fw_retry; + } + + if (fw_ck == 0) { + dprintk(1, "%s() FW checksum failed = 0x%04x\n", + __func__, fw_ck); + goto fw_retry; + } + } + + /* Start the tuner self-calibration process */ + ret |= xc_initialize(priv); + + if (ret != XC_RESULT_SUCCESS) + goto fw_retry; + + /* Wait for calibration to complete. + * We could continue but XC5000 will clock stretch subsequent + * I2C transactions until calibration is complete. This way we + * don't have to rely on clock stretching working. + */ + xc_wait(100); + + if (priv->init_status_supported) { + if (xc5000_readreg(priv, XREG_INIT_STATUS, &fw_ck) != XC_RESULT_SUCCESS) { + dprintk(1, "%s() FW failed reading init status.\n", + __func__); + goto fw_retry; + } + + if (fw_ck == 0) { + dprintk(1, "%s() FW init status failed = 0x%04x\n", __func__, fw_ck); + goto fw_retry; + } + } + + if (priv->pll_register_no) { + xc5000_readreg(priv, priv->pll_register_no, + &pll_lock_status); + if (pll_lock_status > 63) { + /* PLL is unlocked, force reload of the firmware */ + printk(KERN_ERR "xc5000: PLL not running after fwload.\n"); + goto fw_retry; + } + } + + /* Default to "CABLE" mode */ + ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE); + } + + return ret; +} + +static int xc5000_sleep(struct dvb_frontend *fe) +{ + int ret; + + dprintk(1, "%s()\n", __func__); + + /* Avoid firmware reload on slow devices */ + if (no_poweroff) + return 0; + + /* According to Xceive technical support, the "powerdown" register + was removed in newer versions of the firmware. The "supported" + way to sleep the tuner is to pull the reset pin low for 10ms */ + ret = xc5000_TunerReset(fe); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR + "xc5000: %s() unable to shutdown tuner\n", + __func__); + return -EREMOTEIO; + } else + return XC_RESULT_SUCCESS; +} + +static int xc5000_init(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + + if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: Unable to initialise tuner\n"); + return -EREMOTEIO; + } + + if (debug) + xc_debug_dump(priv); + + return 0; +} + +static int xc5000_release(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + + dprintk(1, "%s()\n", __func__); + + mutex_lock(&xc5000_list_mutex); + + if (priv) + hybrid_tuner_release_state(priv); + + mutex_unlock(&xc5000_list_mutex); + + fe->tuner_priv = NULL; + + return 0; +} + +static int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg) +{ + struct xc5000_priv *priv = fe->tuner_priv; + struct xc5000_config *p = priv_cfg; + + dprintk(1, "%s()\n", __func__); + + if (p->if_khz) + priv->if_khz = p->if_khz; + + if (p->radio_input) + priv->radio_input = p->radio_input; + + return 0; +} + + +static const struct dvb_tuner_ops xc5000_tuner_ops = { + .info = { + .name = "Xceive XC5000", + .frequency_min = 1000000, + .frequency_max = 1023000000, + .frequency_step = 50000, + }, + + .release = xc5000_release, + .init = xc5000_init, + .sleep = xc5000_sleep, + + .set_config = xc5000_set_config, + .set_params = xc5000_set_params, + .set_analog_params = xc5000_set_analog_params, + .get_frequency = xc5000_get_frequency, + .get_if_frequency = xc5000_get_if_frequency, + .get_bandwidth = xc5000_get_bandwidth, + .get_status = xc5000_get_status +}; + +struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct xc5000_config *cfg) +{ + struct xc5000_priv *priv = NULL; + int instance; + u16 id = 0; + + dprintk(1, "%s(%d-%04x)\n", __func__, + i2c ? i2c_adapter_id(i2c) : -1, + cfg ? cfg->i2c_address : -1); + + mutex_lock(&xc5000_list_mutex); + + instance = hybrid_tuner_request_state(struct xc5000_priv, priv, + hybrid_tuner_instance_list, + i2c, cfg->i2c_address, "xc5000"); + switch (instance) { + case 0: + goto fail; + break; + case 1: + /* new tuner instance */ + priv->bandwidth = 6000000; + fe->tuner_priv = priv; + break; + default: + /* existing tuner instance */ + fe->tuner_priv = priv; + break; + } + + if (priv->if_khz == 0) { + /* If the IF hasn't been set yet, use the value provided by + the caller (occurs in hybrid devices where the analog + call to xc5000_attach occurs before the digital side) */ + priv->if_khz = cfg->if_khz; + } + + if (priv->xtal_khz == 0) + priv->xtal_khz = cfg->xtal_khz; + + if (priv->radio_input == 0) + priv->radio_input = cfg->radio_input; + + /* don't override chip id if it's already been set + unless explicitly specified */ + if ((priv->chip_id == 0) || (cfg->chip_id)) + /* use default chip id if none specified, set to 0 so + it can be overridden if this is a hybrid driver */ + priv->chip_id = (cfg->chip_id) ? cfg->chip_id : 0; + + /* Check if firmware has been loaded. It is possible that another + instance of the driver has loaded the firmware. + */ + if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS) + goto fail; + + switch (id) { + case XC_PRODUCT_ID_FW_LOADED: + printk(KERN_INFO + "xc5000: Successfully identified at address 0x%02x\n", + cfg->i2c_address); + printk(KERN_INFO + "xc5000: Firmware has been loaded previously\n"); + break; + case XC_PRODUCT_ID_FW_NOT_LOADED: + printk(KERN_INFO + "xc5000: Successfully identified at address 0x%02x\n", + cfg->i2c_address); + printk(KERN_INFO + "xc5000: Firmware has not been loaded previously\n"); + break; + default: + printk(KERN_ERR + "xc5000: Device not found at addr 0x%02x (0x%x)\n", + cfg->i2c_address, id); + goto fail; + } + + mutex_unlock(&xc5000_list_mutex); + + memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + return fe; +fail: + mutex_unlock(&xc5000_list_mutex); + + xc5000_release(fe); + return NULL; +} +EXPORT_SYMBOL(xc5000_attach); + +MODULE_AUTHOR("Steven Toth"); +MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver"); +MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(XC5000A_FIRMWARE); +MODULE_FIRMWARE(XC5000C_FIRMWARE); diff --git a/drivers/media/tuners/xc5000.h b/drivers/media/tuners/xc5000.h new file mode 100644 index 000000000000..b1a547494625 --- /dev/null +++ b/drivers/media/tuners/xc5000.h @@ -0,0 +1,74 @@ +/* + * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2007 Steven Toth + * + * 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 __XC5000_H__ +#define __XC5000_H__ + +#include + +struct dvb_frontend; +struct i2c_adapter; + +#define XC5000A 1 +#define XC5000C 2 + +struct xc5000_config { + u8 i2c_address; + u32 if_khz; + u8 radio_input; + u16 xtal_khz; + + int chip_id; +}; + +/* xc5000 callback command */ +#define XC5000_TUNER_RESET 0 + +/* Possible Radio inputs */ +#define XC5000_RADIO_NOT_CONFIGURED 0 +#define XC5000_RADIO_FM1 1 +#define XC5000_RADIO_FM2 2 +#define XC5000_RADIO_FM1_MONO 3 + +/* For each bridge framework, when it attaches either analog or digital, + * it has to store a reference back to its _core equivalent structure, + * so that it can service the hardware by steering gpio's etc. + * Each bridge implementation is different so cast devptr accordingly. + * The xc5000 driver cares not for this value, other than ensuring + * it's passed back to a bridge during tuner_callback(). + */ + +#if defined(CONFIG_MEDIA_TUNER_XC5000) || \ + (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE)) +extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct xc5000_config *cfg); +#else +static inline struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct xc5000_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff --git a/drivers/media/usb/b2c2/Makefile b/drivers/media/usb/b2c2/Makefile index 9eaf208bfa43..2f7ee5cc5b29 100644 --- a/drivers/media/usb/b2c2/Makefile +++ b/drivers/media/usb/b2c2/Makefile @@ -3,5 +3,5 @@ obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o ccflags-y += -Idrivers/media/dvb-core/ ccflags-y += -Idrivers/media/dvb-frontends/ -ccflags-y += -Idrivers/media/common/tuners/ +ccflags-y += -Idrivers/media/tuners/ ccflags-y += -Idrivers/media/common/b2c2/ diff --git a/drivers/media/usb/dvb-usb-v2/Makefile b/drivers/media/usb/dvb-usb-v2/Makefile index 24248b3acd4f..62568430418b 100644 --- a/drivers/media/usb/dvb-usb-v2/Makefile +++ b/drivers/media/usb/dvb-usb-v2/Makefile @@ -44,5 +44,5 @@ obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends -ccflags-y += -I$(srctree)/drivers/media/common/tuners +ccflags-y += -I$(srctree)/drivers/media/tuners diff --git a/drivers/media/usb/dvb-usb/Makefile b/drivers/media/usb/dvb-usb/Makefile index 94bdf4d51712..d3ab1e74647d 100644 --- a/drivers/media/usb/dvb-usb/Makefile +++ b/drivers/media/usb/dvb-usb/Makefile @@ -78,5 +78,5 @@ obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends/ # due to tuner-xc3028 -ccflags-y += -I$(srctree)/drivers/media/common/tuners +ccflags-y += -I$(srctree)/drivers/media/tuners ccflags-y += -I$(srctree)/drivers/media/pci/ttpci diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index 74b65ea00f63..c0e90bc23692 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile @@ -31,5 +31,5 @@ obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends -ccflags-y += -I$(srctree)/drivers/media/common/tuners +ccflags-y += -I$(srctree)/drivers/media/tuners diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 98160ce77d8d..9dff3e2ec613 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -192,4 +192,4 @@ obj-$(CONFIG_ARCH_OMAP) += omap/ ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends -ccflags-y += -I$(srctree)/drivers/media/common/tuners +ccflags-y += -I$(srctree)/drivers/media/tuners diff --git a/drivers/media/video/au0828/Makefile b/drivers/media/video/au0828/Makefile index 61b69e68d950..98cc20cc0ffb 100644 --- a/drivers/media/video/au0828/Makefile +++ b/drivers/media/video/au0828/Makefile @@ -2,7 +2,7 @@ au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-vid obj-$(CONFIG_VIDEO_AU0828) += au0828.o -ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/tuners ccflags-y += -Idrivers/media/dvb-core ccflags-y += -Idrivers/media/dvb-frontends diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile index 4cba4eff36d8..f6351a25c267 100644 --- a/drivers/media/video/bt8xx/Makefile +++ b/drivers/media/video/bt8xx/Makefile @@ -9,5 +9,5 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ obj-$(CONFIG_VIDEO_BT848) += bttv.o ccflags-y += -Idrivers/media/video -ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/tuners ccflags-y += -Idrivers/media/dvb-core diff --git a/drivers/media/video/cx18/Makefile b/drivers/media/video/cx18/Makefile index db5ab12d84a3..d3ff1545c2c5 100644 --- a/drivers/media/video/cx18/Makefile +++ b/drivers/media/video/cx18/Makefile @@ -10,4 +10,4 @@ obj-$(CONFIG_VIDEO_CX18_ALSA) += cx18-alsa.o ccflags-y += -Idrivers/media/dvb-core ccflags-y += -Idrivers/media/dvb-frontends -ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/tuners diff --git a/drivers/media/video/cx231xx/Makefile b/drivers/media/video/cx231xx/Makefile index 9f2d4a9df3f2..1d40fce77601 100644 --- a/drivers/media/video/cx231xx/Makefile +++ b/drivers/media/video/cx231xx/Makefile @@ -9,7 +9,7 @@ obj-$(CONFIG_VIDEO_CX231XX_ALSA) += cx231xx-alsa.o obj-$(CONFIG_VIDEO_CX231XX_DVB) += cx231xx-dvb.o ccflags-y += -Idrivers/media/video -ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/tuners ccflags-y += -Idrivers/media/dvb-core ccflags-y += -Idrivers/media/dvb-frontends ccflags-y += -Idrivers/media/usb/dvb-usb diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile index 8f82e01a6675..f92cc4c14f0c 100644 --- a/drivers/media/video/cx23885/Makefile +++ b/drivers/media/video/cx23885/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_VIDEO_CX23885) += cx23885.o obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o ccflags-y += -Idrivers/media/video -ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/tuners ccflags-y += -Idrivers/media/dvb-core ccflags-y += -Idrivers/media/dvb-frontends diff --git a/drivers/media/video/cx25821/Makefile b/drivers/media/video/cx25821/Makefile index af23e0c77e16..1434e8094803 100644 --- a/drivers/media/video/cx25821/Makefile +++ b/drivers/media/video/cx25821/Makefile @@ -8,6 +8,6 @@ obj-$(CONFIG_VIDEO_CX25821) += cx25821.o obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o ccflags-y := -Idrivers/media/video -ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/tuners ccflags-y += -Idrivers/media/dvb-core ccflags-y += -Idrivers/media/dvb-frontends diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile index 5c4d3064d494..884b4cdd8ff0 100644 --- a/drivers/media/video/cx88/Makefile +++ b/drivers/media/video/cx88/Makefile @@ -11,6 +11,6 @@ obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o ccflags-y += -Idrivers/media/video -ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/tuners ccflags-y += -Idrivers/media/dvb-core ccflags-y += -Idrivers/media/dvb-frontends diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile index f4118d23a70b..65c7c29e4161 100644 --- a/drivers/media/video/em28xx/Makefile +++ b/drivers/media/video/em28xx/Makefile @@ -10,6 +10,6 @@ obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o ccflags-y += -Idrivers/media/video -ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/tuners ccflags-y += -Idrivers/media/dvb-core ccflags-y += -Idrivers/media/dvb-frontends diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index 0015bd46f667..80b4ec18475d 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_VIDEO_IVTV) += ivtv.o obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o ccflags-y += -I$(srctree)/drivers/media/video -ccflags-y += -I$(srctree)/drivers/media/common/tuners +ccflags-y += -I$(srctree)/drivers/media/tuners ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile index 1458797bafd2..bc716db797e3 100644 --- a/drivers/media/video/pvrusb2/Makefile +++ b/drivers/media/video/pvrusb2/Makefile @@ -17,6 +17,6 @@ pvrusb2-objs := pvrusb2-i2c-core.o \ obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o ccflags-y += -Idrivers/media/video -ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/tuners ccflags-y += -Idrivers/media/dvb-core ccflags-y += -Idrivers/media/dvb-frontends diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile index 7af78a868b19..aba50088dcdc 100644 --- a/drivers/media/video/saa7134/Makefile +++ b/drivers/media/video/saa7134/Makefile @@ -11,6 +11,6 @@ obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o ccflags-y += -I$(srctree)/drivers/media/video -ccflags-y += -I$(srctree)/drivers/media/common/tuners +ccflags-y += -I$(srctree)/drivers/media/tuners ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends diff --git a/drivers/media/video/saa7164/Makefile b/drivers/media/video/saa7164/Makefile index d8ed33d6b853..847110c2e14c 100644 --- a/drivers/media/video/saa7164/Makefile +++ b/drivers/media/video/saa7164/Makefile @@ -5,7 +5,7 @@ saa7164-objs := saa7164-cards.o saa7164-core.o saa7164-i2c.o saa7164-dvb.o \ obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o ccflags-y += -I$(srctree)/drivers/media/video -ccflags-y += -I$(srctree)/drivers/media/common/tuners +ccflags-y += -I$(srctree)/drivers/media/tuners ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends diff --git a/drivers/media/video/tlg2300/Makefile b/drivers/media/video/tlg2300/Makefile index 268d8251f0e9..4d660879999f 100644 --- a/drivers/media/video/tlg2300/Makefile +++ b/drivers/media/video/tlg2300/Makefile @@ -3,7 +3,7 @@ poseidon-objs := pd-video.o pd-alsa.o pd-dvb.o pd-radio.o pd-main.o obj-$(CONFIG_VIDEO_TLG2300) += poseidon.o ccflags-y += -Idrivers/media/video -ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/tuners ccflags-y += -Idrivers/media/dvb-core ccflags-y += -Idrivers/media/dvb-frontends diff --git a/drivers/media/video/tm6000/Makefile b/drivers/media/video/tm6000/Makefile index 56cbcba778f6..1feb8c9c816c 100644 --- a/drivers/media/video/tm6000/Makefile +++ b/drivers/media/video/tm6000/Makefile @@ -10,6 +10,6 @@ obj-$(CONFIG_VIDEO_TM6000_ALSA) += tm6000-alsa.o obj-$(CONFIG_VIDEO_TM6000_DVB) += tm6000-dvb.o ccflags-y := -Idrivers/media/video -ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/tuners ccflags-y += -Idrivers/media/dvb-core ccflags-y += -Idrivers/media/dvb-frontends diff --git a/drivers/media/video/usbvision/Makefile b/drivers/media/video/usbvision/Makefile index aea1e3b5f06b..d55c6bd97a35 100644 --- a/drivers/media/video/usbvision/Makefile +++ b/drivers/media/video/usbvision/Makefile @@ -3,4 +3,4 @@ usbvision-objs := usbvision-core.o usbvision-video.o usbvision-i2c.o usbvision- obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o ccflags-y += -Idrivers/media/video -ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/tuners diff --git a/drivers/staging/media/cxd2099/Makefile b/drivers/staging/media/cxd2099/Makefile index eb6bc595f1ac..b2905e65057c 100644 --- a/drivers/staging/media/cxd2099/Makefile +++ b/drivers/staging/media/cxd2099/Makefile @@ -2,4 +2,4 @@ obj-$(CONFIG_DVB_CXD2099) += cxd2099.o ccflags-y += -Idrivers/media/dvb-core/ ccflags-y += -Idrivers/media/dvb-frontends/ -ccflags-y += -Idrivers/media/common/tuners/ +ccflags-y += -Idrivers/media/tuners/ -- cgit 1.4.1 From fccea74ff8b5159935acc7b4b4857ee81ee44661 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 20 Aug 2012 14:48:02 -0300 Subject: [media] Kconfig: merge all customise options into just one Instead of having 3 options to allow customizing the media sub-drivers (tuners, I2C drivers, frontends), merge all of them into just one. That simplifies the life for users, as they can just keep this untouched. Life for developers is also simpler, as there's now just one Kconfig item to remember, for the ancillary sub-drivers providing supports for chips that could change from one board design to another. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 19 +++- drivers/media/common/b2c2/Kconfig | 28 ++--- drivers/media/dvb-frontends/Kconfig | 195 +++++++++++++++------------------ drivers/media/i2c/Kconfig | 21 +--- drivers/media/pci/bt8xx/Kconfig | 24 ++-- drivers/media/pci/cx18/Kconfig | 10 +- drivers/media/pci/cx23885/Kconfig | 34 +++--- drivers/media/pci/cx88/Kconfig | 36 +++--- drivers/media/pci/ddbridge/Kconfig | 10 +- drivers/media/pci/dm1105/Kconfig | 14 +-- drivers/media/pci/mantis/Kconfig | 20 ++-- drivers/media/pci/ngene/Kconfig | 14 +-- drivers/media/pci/saa7134/Kconfig | 40 +++---- drivers/media/pci/saa7146/Kconfig | 8 +- drivers/media/pci/saa7164/Kconfig | 6 +- drivers/media/pci/sta2x11/Kconfig | 2 +- drivers/media/pci/ttpci/Kconfig | 84 +++++++------- drivers/media/pci/zoran/Kconfig | 26 ++--- drivers/media/platform/Kconfig | 2 +- drivers/media/platform/davinci/Kconfig | 4 +- drivers/media/tuners/Kconfig | 88 +++++++-------- drivers/media/usb/au0828/Kconfig | 10 +- drivers/media/usb/cx231xx/Kconfig | 6 +- drivers/media/usb/dvb-usb-v2/Kconfig | 88 +++++++-------- drivers/media/usb/dvb-usb/Kconfig | 148 ++++++++++++------------- drivers/media/usb/em28xx/Kconfig | 28 ++--- drivers/media/usb/pvrusb2/Kconfig | 14 +-- drivers/media/usb/ttusb-budget/Kconfig | 14 +-- drivers/media/usb/usbvision/Kconfig | 2 +- 29 files changed, 488 insertions(+), 507 deletions(-) (limited to 'drivers/media/pci/ngene') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 9c3698ab6132..dd13e3a4c272 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -162,10 +162,27 @@ source "drivers/media/common/Kconfig" # Ancillary drivers (tuners, i2c, frontends) # +config MEDIA_SUBDRV_AUTOSELECT + bool "Autoselect analog and hybrid tuner modules to build" + depends on MEDIA_TUNER + default y + help + By default, a TV driver auto-selects all possible tuners + thar could be used by the driver. + + This is generally the right thing to do, except when there + are strict constraints with regards to the kernel size. + + Use this option with care, as deselecting tuner drivers which + are in fact necessary will result in TV devices which cannot + be tuned due to lack of the tuning driver. + + If unsure say Y. + comment "Media ancillary drivers (tuners, sensors, i2c, frontends)" -source "drivers/media/tuners/Kconfig" source "drivers/media/i2c/Kconfig" +source "drivers/media/tuners/Kconfig" source "drivers/media/dvb-frontends/Kconfig" endif # MEDIA_SUPPORT diff --git a/drivers/media/common/b2c2/Kconfig b/drivers/media/common/b2c2/Kconfig index e270dd847342..29149de66982 100644 --- a/drivers/media/common/b2c2/Kconfig +++ b/drivers/media/common/b2c2/Kconfig @@ -3,20 +3,20 @@ config DVB_B2C2_FLEXCOP depends on DVB_CORE && I2C depends on DVB_B2C2_FLEXCOP_PCI || DVB_B2C2_FLEXCOP_USB default y - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_MT312 if !DVB_FE_CUSTOMISE - select DVB_NXT200X if !DVB_FE_CUSTOMISE - select DVB_STV0297 if !DVB_FE_CUSTOMISE - select DVB_BCM3510 if !DVB_FE_CUSTOMISE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_S5H1420 if !DVB_FE_CUSTOMISE - select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE - select DVB_ISL6421 if !DVB_FE_CUSTOMISE - select DVB_CX24123 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT + select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT + select DVB_MT312 if MEDIA_SUBDRV_AUTOSELECT + select DVB_NXT200X if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT + select DVB_BCM3510 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT + select DVB_S5H1420 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TUNER_ITD1000 if MEDIA_SUBDRV_AUTOSELECT + select DVB_ISL6421 if MEDIA_SUBDRV_AUTOSELECT + select DVB_CX24123 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT + select DVB_TUNER_CX24113 if MEDIA_SUBDRV_AUTOSELECT help Support for the digital TV receiver chip made by B2C2 Inc. included in Technisats PCI cards and USB boxes. diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index a08c2152d0ee..5efec73a32d2 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -1,20 +1,5 @@ -config DVB_FE_CUSTOMISE - bool "Customise the frontend modules to build" - depends on DVB_CORE - depends on EXPERT - default y if EXPERT - help - This allows the user to select/deselect frontend drivers for their - hardware from the build. - - Use this option with care as deselecting frontends which are in fact - necessary will result in DVB devices which cannot be tuned due to lack - of driver support. - - If unsure say N. - menu "Customise DVB Frontends" - visible if DVB_FE_CUSTOMISE + visible if !MEDIA_SUBDRV_AUTOSELECT comment "Multistandard (satellite) frontends" depends on DVB_CORE @@ -22,7 +7,7 @@ comment "Multistandard (satellite) frontends" config DVB_STB0899 tristate "STB0899 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S/S2/DSS Multistandard demodulator. Say Y when you want to support this demodulator based frontends @@ -30,7 +15,7 @@ config DVB_STB0899 config DVB_STB6100 tristate "STB6100 based tuners" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A Silicon tuner from ST used in conjunction with the STB0899 demodulator. Say Y when you want to support this tuner. @@ -38,7 +23,7 @@ config DVB_STB6100 config DVB_STV090x tristate "STV0900/STV0903(A/B) based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators. Say Y when you want to support these frontends. @@ -46,7 +31,7 @@ config DVB_STV090x config DVB_STV6110x tristate "STV6110/(A) based tuners" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A Silicon tuner that supports DVB-S and DVB-S2 modes @@ -56,7 +41,7 @@ comment "Multistandard (cable + terrestrial) frontends" config DVB_DRXK tristate "Micronas DRXK based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Micronas DRX-K DVB-C/T demodulator. @@ -65,7 +50,7 @@ config DVB_DRXK config DVB_TDA18271C2DD tristate "NXP TDA18271C2 silicon tuner" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help NXP TDA18271 silicon tuner. @@ -77,119 +62,119 @@ comment "DVB-S (satellite) frontends" config DVB_CX24110 tristate "Conexant CX24110 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_CX24123 tristate "Conexant CX24123 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_MT312 tristate "Zarlink VP310/MT312/ZL10313 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_ZL10036 tristate "Zarlink ZL10036 silicon tuner" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_ZL10039 tristate "Zarlink ZL10039 silicon tuner" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_S5H1420 tristate "Samsung S5H1420 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_STV0288 tristate "ST STV0288 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_STB6000 tristate "ST STB6000 silicon tuner" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S silicon tuner module. Say Y when you want to support this tuner. config DVB_STV0299 tristate "ST STV0299 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_STV6110 tristate "ST STV6110 silicon tuner" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S silicon tuner module. Say Y when you want to support this tuner. config DVB_STV0900 tristate "ST STV0900 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S/S2 demodulator. Say Y when you want to support this frontend. config DVB_TDA8083 tristate "Philips TDA8083 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_TDA10086 tristate "Philips TDA10086 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_TDA8261 tristate "Philips TDA8261 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_VES1X93 tristate "VLSI VES1893 or VES1993 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_TUNER_ITD1000 tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_TUNER_CX24113 tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S tuner module. Say Y when you want to support this frontend. @@ -197,42 +182,42 @@ config DVB_TUNER_CX24113 config DVB_TDA826X tristate "Philips TDA826X silicon tuner" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S silicon tuner module. Say Y when you want to support this tuner. config DVB_TUA6100 tristate "Infineon TUA6100 PLL" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S PLL chip. config DVB_CX24116 tristate "Conexant CX24116 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S/S2 tuner module. Say Y when you want to support this frontend. config DVB_SI21XX tristate "Silicon Labs SI21XX based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_DS3000 tristate "Montage Tehnology DS3000 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S/S2 tuner module. Say Y when you want to support this frontend. config DVB_MB86A16 tristate "Fujitsu MB86A16 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S/DSS Direct Conversion reveiver. Say Y when you want to support this frontend. @@ -240,7 +225,7 @@ config DVB_MB86A16 config DVB_TDA10071 tristate "NXP TDA10071" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y when you want to support this frontend. @@ -250,7 +235,7 @@ comment "DVB-T (terrestrial) frontends" config DVB_SP8870 tristate "Spase sp8870 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -262,7 +247,7 @@ config DVB_SP8870 config DVB_SP887X tristate "Spase sp887x based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -274,28 +259,28 @@ config DVB_SP887X config DVB_CX22700 tristate "Conexant CX22700 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Say Y when you want to support this frontend. config DVB_CX22702 tristate "Conexant cx22702 demodulator (OFDM)" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Say Y when you want to support this frontend. config DVB_S5H1432 tristate "Samsung s5h1432 demodulator (OFDM)" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Say Y when you want to support this frontend. config DVB_DRXD tristate "Micronas DRXD driver" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -306,14 +291,14 @@ config DVB_DRXD config DVB_L64781 tristate "LSI L64781" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Say Y when you want to support this frontend. config DVB_TDA1004X tristate "Philips TDA10045H/TDA10046H based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -326,28 +311,28 @@ config DVB_TDA1004X config DVB_NXT6000 tristate "NxtWave Communications NXT6000 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Say Y when you want to support this frontend. config DVB_MT352 tristate "Zarlink MT352 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Say Y when you want to support this frontend. config DVB_ZL10353 tristate "Zarlink ZL10353 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Say Y when you want to support this frontend. config DVB_DIB3000MB tristate "DiBcom 3000M-B" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Designed for mobile usage. Say Y when you want to support this frontend. @@ -355,7 +340,7 @@ config DVB_DIB3000MB config DVB_DIB3000MC tristate "DiBcom 3000P/M-C" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Designed for mobile usage. Say Y when you want to support this frontend. @@ -363,7 +348,7 @@ config DVB_DIB3000MC config DVB_DIB7000M tristate "DiBcom 7000MA/MB/PA/PB/MC" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Designed for mobile usage. Say Y when you want to support this frontend. @@ -371,7 +356,7 @@ config DVB_DIB7000M config DVB_DIB7000P tristate "DiBcom 7000PC" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Designed for mobile usage. Say Y when you want to support this frontend. @@ -379,7 +364,7 @@ config DVB_DIB7000P config DVB_DIB9000 tristate "DiBcom 9000" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Designed for mobile usage. Say Y when you want to support this frontend. @@ -387,56 +372,56 @@ config DVB_DIB9000 config DVB_TDA10048 tristate "Philips TDA10048HN based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Say Y when you want to support this frontend. config DVB_AF9013 tristate "Afatech AF9013 demodulator" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y when you want to support this frontend. config DVB_EC100 tristate "E3C EC100" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y when you want to support this frontend. config DVB_HD29L2 tristate "HDIC HD29L2" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y when you want to support this frontend. config DVB_STV0367 tristate "ST STV0367 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T/C tuner module. Say Y when you want to support this frontend. config DVB_CXD2820R tristate "Sony CXD2820R" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y when you want to support this frontend. config DVB_RTL2830 tristate "Realtek RTL2830 DVB-T" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y when you want to support this frontend. config DVB_RTL2832 tristate "Realtek RTL2832 DVB-T" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y when you want to support this frontend. @@ -446,28 +431,28 @@ comment "DVB-C (cable) frontends" config DVB_VES1820 tristate "VLSI VES1820 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-C tuner module. Say Y when you want to support this frontend. config DVB_TDA10021 tristate "Philips TDA10021 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-C tuner module. Say Y when you want to support this frontend. config DVB_TDA10023 tristate "Philips TDA10023 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-C tuner module. Say Y when you want to support this frontend. config DVB_STV0297 tristate "ST STV0297 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-C tuner module. Say Y when you want to support this frontend. @@ -477,7 +462,7 @@ comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends" config DVB_NXT200X tristate "NxtWave Communications NXT2002/NXT2004 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. @@ -491,7 +476,7 @@ config DVB_NXT200X config DVB_OR51211 tristate "Oren OR51211 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help An ATSC 8VSB tuner module. Say Y when you want to support this frontend. @@ -503,7 +488,7 @@ config DVB_OR51211 config DVB_OR51132 tristate "Oren OR51132 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. @@ -518,7 +503,7 @@ config DVB_OR51132 config DVB_BCM3510 tristate "Broadcom BCM3510" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. @@ -526,7 +511,7 @@ config DVB_BCM3510 config DVB_LGDT330X tristate "LG Electronics LGDT3302/LGDT3303 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. @@ -534,7 +519,7 @@ config DVB_LGDT330X config DVB_LGDT3305 tristate "LG Electronics LGDT3304 and LGDT3305 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. @@ -542,7 +527,7 @@ config DVB_LGDT3305 config DVB_LG2160 tristate "LG Electronics LG216x based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help An ATSC/MH demodulator module. Say Y when you want to support this frontend. @@ -550,7 +535,7 @@ config DVB_LG2160 config DVB_S5H1409 tristate "Samsung S5H1409 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. @@ -563,7 +548,7 @@ config DVB_AU8522_DTV tristate "Auvitek AU8522 based DTV demod" depends on DVB_CORE && I2C select DVB_AU8522 - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when you want to enable DTV demodulation support for this frontend. @@ -572,7 +557,7 @@ config DVB_AU8522_V4L tristate "Auvitek AU8522 based ATV demod" depends on VIDEO_V4L2 && I2C select DVB_AU8522 - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when you want to enable ATV demodulation support for this frontend. @@ -580,7 +565,7 @@ config DVB_AU8522_V4L config DVB_S5H1411 tristate "Samsung S5H1411 based" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. @@ -591,7 +576,7 @@ comment "ISDB-T (terrestrial) frontends" config DVB_S921 tristate "Sharp S921 frontend" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module. Say Y when you want to support this frontend. @@ -599,7 +584,7 @@ config DVB_S921 config DVB_DIB8000 tristate "DiBcom 8000MB/MC" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A driver for DiBcom's DiB8000 ISDB-T/ISDB-Tsb demodulator. Say Y when you want to support this frontend. @@ -607,7 +592,7 @@ config DVB_DIB8000 config DVB_MB86A20S tristate "Fujitsu mb86a20s" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator. Say Y when you want to support this frontend. @@ -618,7 +603,7 @@ comment "Digital terrestrial only tuners/PLL" config DVB_PLL tristate "Generic I2C PLL based tuners" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help This module drives a number of tuners based on PLL chips with a common I2C interface. Say Y when you want to support these tuners. @@ -626,7 +611,7 @@ config DVB_PLL config DVB_TUNER_DIB0070 tristate "DiBcom DiB0070 silicon base-band tuner" depends on I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A driver for the silicon baseband tuner DiB0070 from DiBcom. This device is only used inside a SiP called together with a @@ -635,7 +620,7 @@ config DVB_TUNER_DIB0070 config DVB_TUNER_DIB0090 tristate "DiBcom DiB0090 silicon base-band tuner" depends on I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A driver for the silicon baseband tuner DiB0090 from DiBcom. This device is only used inside a SiP called together with a @@ -647,14 +632,14 @@ comment "SEC control devices for DVB-S" config DVB_LNBP21 tristate "LNBP21/LNBH24 SEC controllers" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help An SEC control chips. config DVB_LNBP22 tristate "LNBP22 SEC controllers" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help LNB power supply and control voltage regulator chip with step-up converter @@ -664,33 +649,33 @@ config DVB_LNBP22 config DVB_ISL6405 tristate "ISL6405 SEC controller" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help An SEC control chip. config DVB_ISL6421 tristate "ISL6421 SEC controller" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help An SEC control chip. config DVB_ISL6423 tristate "ISL6423 SEC controller" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A SEC controller chip from Intersil config DVB_A8293 tristate "Allegro A8293" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT config DVB_LGS8GL5 tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DMB-TH tuner module. Say Y when you want to support this frontend. @@ -698,21 +683,21 @@ config DVB_LGS8GXX tristate "Legend Silicon LGS8913/LGS8GL5/LGS8GXX DMB-TH demodulator" depends on DVB_CORE && I2C select FW_LOADER - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DMB-TH tuner module. Say Y when you want to support this frontend. config DVB_ATBM8830 tristate "AltoBeam ATBM8830/8831 DMB-TH demodulator" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DMB-TH tuner module. Say Y when you want to support this frontend. config DVB_TDA665x tristate "TDA665x tuner" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Support for tuner modules based on Philips TDA6650/TDA6651 chips. Say Y when you want to support this chip. @@ -723,14 +708,14 @@ config DVB_TDA665x config DVB_IX2505V tristate "Sharp IX2505V silicon tuner" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_IT913X_FE tristate "it913x frontend and it9137 tuner" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -738,7 +723,7 @@ config DVB_IT913X_FE config DVB_M88RS2000 tristate "M88RS2000 DVB-S demodulator and tuner" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S tuner module. Say Y when you want to support this frontend. @@ -746,7 +731,7 @@ config DVB_M88RS2000 config DVB_AF9033 tristate "Afatech AF9033 DVB-T demodulator" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT comment "Tools to develop new frontends" diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 527430ac06f3..d41dc0aa005e 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -16,21 +16,8 @@ config VIDEO_TVEEPROM if VIDEO_V4L2 -config VIDEO_HELPER_CHIPS_AUTO - bool "Autoselect pertinent encoders/decoders and other helper chips" - default y if !EXPERT - ---help--- - Most video cards may require additional modules to encode or - decode audio/video standards. This option will autoselect - all pertinent modules to each selected video module. - - Unselect this only if you know exactly what you are doing, since - it may break support on some boards. - - In doubt, say Y. - config VIDEO_IR_I2C - tristate "I2C module for IR" if !VIDEO_HELPER_CHIPS_AUTO + tristate "I2C module for IR" if !MEDIA_SUBDRV_AUTOSELECT depends on I2C && RC_CORE default y ---help--- @@ -47,7 +34,7 @@ config VIDEO_IR_I2C # menu "Encoders, decoders, sensors and other helper chips" - visible if !VIDEO_HELPER_CHIPS_AUTO + visible if !MEDIA_SUBDRV_AUTOSELECT comment "Audio decoders, processors and mixers" @@ -561,10 +548,14 @@ config VIDEO_M52790 To compile this driver as a module, choose M here: the module will be called m52790. +endmenu + +menu "Sensors used on soc_camera driver" if SOC_CAMERA source "drivers/media/i2c/soc_camera/Kconfig" endif endmenu + endif diff --git a/drivers/media/pci/bt8xx/Kconfig b/drivers/media/pci/bt8xx/Kconfig index f2667a5cc144..61d09e010814 100644 --- a/drivers/media/pci/bt8xx/Kconfig +++ b/drivers/media/pci/bt8xx/Kconfig @@ -7,10 +7,10 @@ config VIDEO_BT848 depends on RC_CORE select VIDEO_TUNER select VIDEO_TVEEPROM - select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_TDA7432 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_SAA6588 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_TVAUDIO if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_TDA7432 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for BT848 based frame grabber/overlay boards. This includes the Miro, Hauppauge and STB boards. Please read the material in @@ -22,14 +22,14 @@ config VIDEO_BT848 config DVB_BT8XX tristate "DVB/ATSC Support for bt878 based TV cards" depends on DVB_CORE && PCI && I2C && VIDEO_BT848 - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_SP887X if !DVB_FE_CUSTOMISE - select DVB_NXT6000 if !DVB_FE_CUSTOMISE - select DVB_CX24110 if !DVB_FE_CUSTOMISE - select DVB_OR51211 if !DVB_FE_CUSTOMISE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE + select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT + select DVB_SP887X if MEDIA_SUBDRV_AUTOSELECT + select DVB_NXT6000 if MEDIA_SUBDRV_AUTOSELECT + select DVB_CX24110 if MEDIA_SUBDRV_AUTOSELECT + select DVB_OR51211 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT + select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT help Support for PCI cards based on the Bt8xx PCI bridge. Examples are the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards, diff --git a/drivers/media/pci/cx18/Kconfig b/drivers/media/pci/cx18/Kconfig index 53b3c7702573..9a9f765dad45 100644 --- a/drivers/media/pci/cx18/Kconfig +++ b/drivers/media/pci/cx18/Kconfig @@ -8,11 +8,11 @@ config VIDEO_CX18 select VIDEO_TVEEPROM select VIDEO_CX2341X select VIDEO_CS5345 - select DVB_S5H1409 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - select DVB_S5H1411 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE + select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT + select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT ---help--- This is a video4linux driver for Conexant cx23418 based PCI combo video recorder devices. diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig index b391e9bda877..9c6afe922586 100644 --- a/drivers/media/pci/cx23885/Kconfig +++ b/drivers/media/pci/cx23885/Kconfig @@ -11,23 +11,23 @@ config VIDEO_CX23885 select VIDEOBUF_DMA_SG select VIDEO_CX25840 select VIDEO_CX2341X - select DVB_DIB7000P if !DVB_FE_CUSTOMISE - select DVB_S5H1409 if !DVB_FE_CUSTOMISE - select DVB_S5H1411 if !DVB_FE_CUSTOMISE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_TDA10048 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_STV6110 if !DVB_FE_CUSTOMISE - select DVB_CX24116 if !DVB_FE_CUSTOMISE - select DVB_STV0900 if !DVB_FE_CUSTOMISE - select DVB_DS3000 if !DVB_FE_CUSTOMISE - select DVB_STV0367 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE + select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT + select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT + select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT + select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT + select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT + select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT ---help--- This is a video4linux driver for Conexant 23885 based TV cards. diff --git a/drivers/media/pci/cx88/Kconfig b/drivers/media/pci/cx88/Kconfig index 3598dc087b08..d27fccbf03c4 100644 --- a/drivers/media/pci/cx88/Kconfig +++ b/drivers/media/pci/cx88/Kconfig @@ -6,7 +6,7 @@ config VIDEO_CX88 select VIDEOBUF_DMA_SG select VIDEO_TUNER select VIDEO_TVEEPROM - select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_WM8775 if MEDIA_SUBDRV_AUTOSELECT ---help--- This is a video4linux driver for Conexant 2388x based TV cards. @@ -46,23 +46,23 @@ config VIDEO_CX88_DVB tristate "DVB/ATSC Support for cx2388x based TV cards" depends on VIDEO_CX88 && DVB_CORE select VIDEOBUF_DVB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_OR51132 if !DVB_FE_CUSTOMISE - select DVB_CX22702 if !DVB_FE_CUSTOMISE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_NXT200X if !DVB_FE_CUSTOMISE - select DVB_CX24123 if !DVB_FE_CUSTOMISE - select DVB_ISL6421 if !DVB_FE_CUSTOMISE - select DVB_S5H1411 if !DVB_FE_CUSTOMISE - select DVB_CX24116 if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_STV0288 if !DVB_FE_CUSTOMISE - select DVB_STB6000 if !DVB_FE_CUSTOMISE - select DVB_STV0900 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT + select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT + select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT + select DVB_OR51132 if MEDIA_SUBDRV_AUTOSELECT + select DVB_CX22702 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT + select DVB_NXT200X if MEDIA_SUBDRV_AUTOSELECT + select DVB_CX24123 if MEDIA_SUBDRV_AUTOSELECT + select DVB_ISL6421 if MEDIA_SUBDRV_AUTOSELECT + select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT + select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT ---help--- This adds support for DVB/ATSC cards based on the Conexant 2388x chip. diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig index d099e1a12c85..44e5dc15e60a 100644 --- a/drivers/media/pci/ddbridge/Kconfig +++ b/drivers/media/pci/ddbridge/Kconfig @@ -1,11 +1,11 @@ config DVB_DDBRIDGE tristate "Digital Devices bridge support" depends on DVB_CORE && PCI && I2C - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_STV6110x if !DVB_FE_CUSTOMISE - select DVB_STV090x if !DVB_FE_CUSTOMISE - select DVB_DRXK if !DVB_FE_CUSTOMISE - select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE + select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT + select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for cards with the Digital Devices PCI express bridge: - Octopus PCIe Bridge diff --git a/drivers/media/pci/dm1105/Kconfig b/drivers/media/pci/dm1105/Kconfig index f3de0a4d63f2..013df4e015cd 100644 --- a/drivers/media/pci/dm1105/Kconfig +++ b/drivers/media/pci/dm1105/Kconfig @@ -1,13 +1,13 @@ config DVB_DM1105 tristate "SDMC DM1105 based PCI cards" depends on DVB_CORE && PCI && I2C - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_STV0288 if !DVB_FE_CUSTOMISE - select DVB_STB6000 if !DVB_FE_CUSTOMISE - select DVB_CX24116 if !DVB_FE_CUSTOMISE - select DVB_SI21XX if !DVB_FE_CUSTOMISE - select DVB_DS3000 if !DVB_FE_CUSTOMISE + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT + select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT + select DVB_SI21XX if MEDIA_SUBDRV_AUTOSELECT + select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT depends on RC_CORE help Support for cards based on the SDMC DM1105 PCI chip like diff --git a/drivers/media/pci/mantis/Kconfig b/drivers/media/pci/mantis/Kconfig index a13a50503134..d3cc21633b94 100644 --- a/drivers/media/pci/mantis/Kconfig +++ b/drivers/media/pci/mantis/Kconfig @@ -10,15 +10,15 @@ config MANTIS_CORE config DVB_MANTIS tristate "MANTIS based cards" depends on MANTIS_CORE && DVB_CORE && PCI && I2C - select DVB_MB86A16 if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE - select DVB_TDA665x if !DVB_FE_CUSTOMISE - select DVB_TDA10021 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select DVB_MB86A16 if MEDIA_SUBDRV_AUTOSELECT + select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA665x if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA10021 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT select DVB_PLL help Support for PCI cards based on the Mantis PCI bridge. @@ -29,7 +29,7 @@ config DVB_MANTIS config DVB_HOPPER tristate "HOPPER based cards" depends on MANTIS_CORE && DVB_CORE && PCI && I2C - select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT select DVB_PLL help Support for PCI cards based on the Hopper PCI bridge. diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig index 64c84702ba5c..637d506b23c5 100644 --- a/drivers/media/pci/ngene/Kconfig +++ b/drivers/media/pci/ngene/Kconfig @@ -1,13 +1,13 @@ config DVB_NGENE tristate "Micronas nGene support" depends on DVB_CORE && PCI && I2C - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_STV6110x if !DVB_FE_CUSTOMISE - select DVB_STV090x if !DVB_FE_CUSTOMISE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_DRXK if !DVB_FE_CUSTOMISE - select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE + select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT + select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT + select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for Micronas PCI express cards with nGene bridge. diff --git a/drivers/media/pci/saa7134/Kconfig b/drivers/media/pci/saa7134/Kconfig index 39fc0187a747..15b90d6e9130 100644 --- a/drivers/media/pci/saa7134/Kconfig +++ b/drivers/media/pci/saa7134/Kconfig @@ -5,7 +5,7 @@ config VIDEO_SAA7134 select VIDEO_TUNER select VIDEO_TVEEPROM select CRC32 - select VIDEO_SAA6588 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT ---help--- This is a video4linux driver for Philips SAA713x based TV cards. @@ -37,25 +37,25 @@ config VIDEO_SAA7134_DVB tristate "DVB/ATSC Support for saa7134 based TV cards" depends on VIDEO_SAA7134 && DVB_CORE select VIDEOBUF_DVB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_TDA1004X if !DVB_FE_CUSTOMISE - select DVB_NXT200X if !DVB_FE_CUSTOMISE - select DVB_TDA10086 if !DVB_FE_CUSTOMISE - select DVB_TDA826X if !DVB_FE_CUSTOMISE - select DVB_ISL6421 if !DVB_FE_CUSTOMISE - select DVB_ISL6405 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - select DVB_ZL10036 if !DVB_FE_CUSTOMISE - select DVB_MT312 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_LGDT3305 if !DVB_FE_CUSTOMISE - select DVB_TDA10048 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE - select DVB_ZL10039 if !DVB_FE_CUSTOMISE + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT + select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT + select DVB_NXT200X if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT + select DVB_ISL6421 if MEDIA_SUBDRV_AUTOSELECT + select DVB_ISL6405 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA827X if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT + select DVB_ZL10036 if MEDIA_SUBDRV_AUTOSELECT + select DVB_MT312 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT + select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT + select DVB_ZL10039 if MEDIA_SUBDRV_AUTOSELECT ---help--- This adds support for DVB cards based on the Philips saa7134 chip. diff --git a/drivers/media/pci/saa7146/Kconfig b/drivers/media/pci/saa7146/Kconfig index 8923b762bbab..da88b77a916c 100644 --- a/drivers/media/pci/saa7146/Kconfig +++ b/drivers/media/pci/saa7146/Kconfig @@ -26,10 +26,10 @@ config VIDEO_MXB depends on PCI && VIDEO_V4L2 && I2C select VIDEO_SAA7146_VV select VIDEO_TUNER - select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_TEA6420 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_TDA9840 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_TEA6415C if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_TEA6420 if MEDIA_SUBDRV_AUTOSELECT ---help--- This is a video4linux driver for the 'Multimedia eXtension Board' TV card by Siemens-Nixdorf. diff --git a/drivers/media/pci/saa7164/Kconfig b/drivers/media/pci/saa7164/Kconfig index 353263725172..84637965287e 100644 --- a/drivers/media/pci/saa7164/Kconfig +++ b/drivers/media/pci/saa7164/Kconfig @@ -6,9 +6,9 @@ config VIDEO_SAA7164 select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEOBUF_DVB - select DVB_TDA10048 if !DVB_FE_CUSTOMISE - select DVB_S5H1411 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE + select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT + select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT ---help--- This is a video4linux driver for NXP SAA7164 based TV cards. diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig index 04a82cbd7c91..6749f67cab8a 100644 --- a/drivers/media/pci/sta2x11/Kconfig +++ b/drivers/media/pci/sta2x11/Kconfig @@ -1,7 +1,7 @@ config STA2X11_VIP tristate "STA2X11 VIP Video For Linux" depends on STA2X11 - select VIDEO_ADV7180 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT select VIDEOBUF_DMA_CONTIG depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS help diff --git a/drivers/media/pci/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig index 9d83ced69dd6..314e417addae 100644 --- a/drivers/media/pci/ttpci/Kconfig +++ b/drivers/media/pci/ttpci/Kconfig @@ -9,14 +9,14 @@ config DVB_AV7110 select TTPCI_EEPROM select VIDEO_SAA7146_VV depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV - select DVB_VES1820 if !DVB_FE_CUSTOMISE - select DVB_VES1X93 if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_TDA8083 if !DVB_FE_CUSTOMISE - select DVB_SP8870 if !DVB_FE_CUSTOMISE - select DVB_STV0297 if !DVB_FE_CUSTOMISE - select DVB_L64781 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT + select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT + select DVB_SP8870 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT + select DVB_L64781 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT help Support for SAA7146 and AV7110 based DVB cards as produced by Fujitsu-Siemens, Technotrend, Hauppauge and others. @@ -63,19 +63,19 @@ config DVB_BUDGET_CORE config DVB_BUDGET tristate "Budget cards" depends on DVB_BUDGET_CORE && I2C - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_VES1X93 if !DVB_FE_CUSTOMISE - select DVB_VES1820 if !DVB_FE_CUSTOMISE - select DVB_L64781 if !DVB_FE_CUSTOMISE - select DVB_TDA8083 if !DVB_FE_CUSTOMISE - select DVB_S5H1420 if !DVB_FE_CUSTOMISE - select DVB_TDA10086 if !DVB_FE_CUSTOMISE - select DVB_TDA826X if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_TDA1004X if !DVB_FE_CUSTOMISE - select DVB_ISL6423 if !DVB_FE_CUSTOMISE - select DVB_STV090x if !DVB_FE_CUSTOMISE - select DVB_STV6110x if !DVB_FE_CUSTOMISE + select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT + select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT + select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT + select DVB_L64781 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT + select DVB_S5H1420 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT + select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT + select DVB_ISL6423 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT help Support for simple SAA7146 based DVB cards (so called Budget- or Nova-PCI cards) without onboard MPEG2 decoder, and without @@ -89,16 +89,16 @@ config DVB_BUDGET config DVB_BUDGET_CI tristate "Budget cards with onboard CI connector" depends on DVB_BUDGET_CORE && I2C - select DVB_STV0297 if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_TDA1004X if !DVB_FE_CUSTOMISE - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_STV0288 if !DVB_FE_CUSTOMISE - select DVB_STB6000 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE + select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT + select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA827X if MEDIA_SUBDRV_AUTOSELECT depends on RC_CORE help Support for simple SAA7146 based DVB cards @@ -118,14 +118,14 @@ config DVB_BUDGET_AV depends on DVB_BUDGET_CORE && I2C select VIDEO_SAA7146_VV depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_TDA1004X if !DVB_FE_CUSTOMISE - select DVB_TDA10021 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_TDA8261 if !DVB_FE_CUSTOMISE - select DVB_TUA6100 if !DVB_FE_CUSTOMISE + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA10021 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA8261 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TUA6100 if MEDIA_SUBDRV_AUTOSELECT help Support for simple SAA7146 based DVB cards (so called Budget- or Nova-PCI cards) without onboard @@ -140,9 +140,9 @@ config DVB_BUDGET_PATCH tristate "AV7110 cards with Budget Patch" depends on DVB_BUDGET_CORE && I2C depends on DVB_AV7110 - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_VES1X93 if !DVB_FE_CUSTOMISE - select DVB_TDA8083 if !DVB_FE_CUSTOMISE + select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT + select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT help Support for Budget Patch (full TS) modification on SAA7146+AV7110 based cards (DVB-S cards). This diff --git a/drivers/media/pci/zoran/Kconfig b/drivers/media/pci/zoran/Kconfig index fd4120e4c104..a9b231808413 100644 --- a/drivers/media/pci/zoran/Kconfig +++ b/drivers/media/pci/zoran/Kconfig @@ -14,8 +14,8 @@ config VIDEO_ZORAN config VIDEO_ZORAN_DC30 tristate "Pinnacle/Miro DC30(+) support" depends on VIDEO_ZORAN - select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_ADV7175 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_VPX3220 if MEDIA_SUBDRV_AUTOSELECT help Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback card. This also supports really old DC10 cards based on the @@ -32,16 +32,16 @@ config VIDEO_ZORAN_ZR36060 config VIDEO_ZORAN_BUZ tristate "Iomega Buz support" depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_SAA7185 if MEDIA_SUBDRV_AUTOSELECT help Support for the Iomega Buz MJPEG capture/playback card. config VIDEO_ZORAN_DC10 tristate "Pinnacle/Miro DC10(+) support" depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA7110 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_SAA7110 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_ADV7175 if MEDIA_SUBDRV_AUTOSELECT help Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback card. @@ -49,8 +49,8 @@ config VIDEO_ZORAN_DC10 config VIDEO_ZORAN_LML33 tristate "Linux Media Labs LML33 support" depends on VIDEO_ZORAN_ZR36060 - select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_BT819 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_BT856 if MEDIA_SUBDRV_AUTOSELECT help Support for the Linux Media Labs LML33 MJPEG capture/playback card. @@ -58,8 +58,8 @@ config VIDEO_ZORAN_LML33 config VIDEO_ZORAN_LML33R10 tristate "Linux Media Labs LML33R10 support" depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_ADV7170 if MEDIA_SUBDRV_AUTOSELECT help support for the Linux Media Labs LML33R10 MJPEG capture/playback card. @@ -67,8 +67,8 @@ config VIDEO_ZORAN_LML33R10 config VIDEO_ZORAN_AVS6EYES tristate "AverMedia 6 Eyes support (EXPERIMENTAL)" depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL - select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_BT866 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_BT856 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_BT866 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_KS0127 if MEDIA_SUBDRV_AUTOSELECT help Support for the AverMedia 6 Eyes video surveillance card. diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 5955a276f468..d4c034d2bd8d 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -66,7 +66,7 @@ config VIDEO_TIMBERDALE config VIDEO_VINO tristate "SGI Vino Video For Linux" depends on I2C && SGI_IP22 && VIDEO_V4L2 - select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_SAA7191 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to build in support for the Vino video input system found on SGI Indy machines. diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig index 52c5ca68cb3d..78e26d24f637 100644 --- a/drivers/media/platform/davinci/Kconfig +++ b/drivers/media/platform/davinci/Kconfig @@ -3,8 +3,8 @@ config VIDEO_DAVINCI_VPIF_DISPLAY depends on VIDEO_DEV && (MACH_DAVINCI_DM6467_EVM || MACH_DAVINCI_DA850_EVM) select VIDEOBUF2_DMA_CONTIG select VIDEO_DAVINCI_VPIF - select VIDEO_ADV7343 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_THS7303 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_ADV7343 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_THS7303 if MEDIA_SUBDRV_AUTOSELECT help Enables Davinci VPIF module used for display devices. This module is common for following DM6467/DA850/OMAPL138 diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index 94c6ff7a5da3..80238b9063b0 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -18,43 +18,31 @@ config MEDIA_ATTACH If unsure say Y. +# Analog TV tuners, auto-loaded via tuner.ko config MEDIA_TUNER tristate depends on (MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT) && I2C default y - select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT && EXPERIMENTAL - select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE - -config MEDIA_TUNER_CUSTOMISE - bool "Customize analog and hybrid tuner modules to build" - depends on MEDIA_TUNER - default y if EXPERT - help - This allows the user to deselect tuner drivers unnecessary - for their hardware from the build. Use this option with care - as deselecting tuner drivers which are in fact necessary will - result in V4L/DVB devices which cannot be tuned due to lack of - driver support - - If unsure say N. + select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_XC4000 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MT20XX if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TEA5761 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_RADIO_SUPPORT && EXPERIMENTAL + select MEDIA_TUNER_TEA5767 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_RADIO_SUPPORT + select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA9887 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MC44S803 if MEDIA_SUBDRV_AUTOSELECT menu "Customize TV tuners" - visible if MEDIA_TUNER_CUSTOMISE + visible if !MEDIA_SUBDRV_AUTOSELECT depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT config MEDIA_TUNER_SIMPLE tristate "Simple tuner support" depends on MEDIA_SUPPORT && I2C select MEDIA_TUNER_TDA9887 - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y here to include support for various simple tuners. @@ -63,28 +51,28 @@ config MEDIA_TUNER_TDA8290 depends on MEDIA_SUPPORT && I2C select MEDIA_TUNER_TDA827X select MEDIA_TUNER_TDA18271 - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y here to include support for Philips TDA8290+8275(a) tuner. config MEDIA_TUNER_TDA827X tristate "Philips TDA827X silicon tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-T silicon tuner module. Say Y when you want to support this tuner. config MEDIA_TUNER_TDA18271 tristate "NXP TDA18271 silicon tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A silicon tuner module. Say Y when you want to support this tuner. config MEDIA_TUNER_TDA9887 tristate "TDA 9885/6/7 analog IF demodulator" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y here to include support for Philips TDA9885/6/7 analog IF demodulator. @@ -93,70 +81,70 @@ config MEDIA_TUNER_TEA5761 tristate "TEA 5761 radio tuner (EXPERIMENTAL)" depends on MEDIA_SUPPORT && I2C depends on EXPERIMENTAL - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y here to include support for the Philips TEA5761 radio tuner. config MEDIA_TUNER_TEA5767 tristate "TEA 5767 radio tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y here to include support for the Philips TEA5767 radio tuner. config MEDIA_TUNER_MT20XX tristate "Microtune 2032 / 2050 tuners" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y here to include support for the MT2032 / MT2050 tuner. config MEDIA_TUNER_MT2060 tristate "Microtune MT2060 silicon IF tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A driver for the silicon IF tuner MT2060 from Microtune. config MEDIA_TUNER_MT2063 tristate "Microtune MT2063 silicon IF tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A driver for the silicon IF tuner MT2063 from Microtune. config MEDIA_TUNER_MT2266 tristate "Microtune MT2266 silicon tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A driver for the silicon baseband tuner MT2266 from Microtune. config MEDIA_TUNER_MT2131 tristate "Microtune MT2131 silicon tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A driver for the silicon baseband tuner MT2131 from Microtune. config MEDIA_TUNER_QT1010 tristate "Quantek QT1010 silicon tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A driver for the silicon tuner QT1010 from Quantek. config MEDIA_TUNER_XC2028 tristate "XCeive xc2028/xc3028 tuners" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y here to include support for the xc2028/xc3028 tuners. config MEDIA_TUNER_XC5000 tristate "Xceive XC5000 silicon tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A driver for the silicon tuner XC5000 from Xceive. This device is only used inside a SiP called together with a @@ -165,7 +153,7 @@ config MEDIA_TUNER_XC5000 config MEDIA_TUNER_XC4000 tristate "Xceive XC4000 silicon tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A driver for the silicon tuner XC4000 from Xceive. This device is only used inside a SiP called together with a @@ -174,70 +162,70 @@ config MEDIA_TUNER_XC4000 config MEDIA_TUNER_MXL5005S tristate "MaxLinear MSL5005S silicon tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A driver for the silicon tuner MXL5005S from MaxLinear. config MEDIA_TUNER_MXL5007T tristate "MaxLinear MxL5007T silicon tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A driver for the silicon tuner MxL5007T from MaxLinear. config MEDIA_TUNER_MC44S803 tristate "Freescale MC44S803 Low Power CMOS Broadband tuners" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Freescale MC44S803 based tuners config MEDIA_TUNER_MAX2165 tristate "Maxim MAX2165 silicon tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A driver for the silicon tuner MAX2165 from Maxim. config MEDIA_TUNER_TDA18218 tristate "NXP TDA18218 silicon tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help NXP TDA18218 silicon tuner driver. config MEDIA_TUNER_FC0011 tristate "Fitipower FC0011 silicon tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Fitipower FC0011 silicon tuner driver. config MEDIA_TUNER_FC0012 tristate "Fitipower FC0012 silicon tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Fitipower FC0012 silicon tuner driver. config MEDIA_TUNER_FC0013 tristate "Fitipower FC0013 silicon tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Fitipower FC0013 silicon tuner driver. config MEDIA_TUNER_TDA18212 tristate "NXP TDA18212 silicon tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help NXP TDA18212 silicon tuner driver. config MEDIA_TUNER_TUA9001 tristate "Infineon TUA 9001 silicon tuner" depends on MEDIA_SUPPORT && I2C - default m if MEDIA_TUNER_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help Infineon TUA 9001 silicon tuner driver. endmenu diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig index 23f7fd22f0eb..385e557ba910 100644 --- a/drivers/media/usb/au0828/Kconfig +++ b/drivers/media/usb/au0828/Kconfig @@ -6,11 +6,11 @@ config VIDEO_AU0828 select I2C_ALGOBIT select VIDEO_TVEEPROM select VIDEOBUF_VMALLOC - select DVB_AU8522_DTV if !DVB_FE_CUSTOMISE - select DVB_AU8522_V4L if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE + select DVB_AU8522_DTV if MEDIA_SUBDRV_AUTOSELECT + select DVB_AU8522_V4L if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT ---help--- This is a video4linux driver for Auvitek's USB device. diff --git a/drivers/media/usb/cx231xx/Kconfig b/drivers/media/usb/cx231xx/Kconfig index 446f692aabb7..77913dfbd238 100644 --- a/drivers/media/usb/cx231xx/Kconfig +++ b/drivers/media/usb/cx231xx/Kconfig @@ -42,9 +42,9 @@ config VIDEO_CX231XX_DVB tristate "DVB/ATSC Support for Cx231xx based TV cards" depends on VIDEO_CX231XX && DVB_CORE && DVB_CAPTURE_DRIVERS select VIDEOBUF_DVB - select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE - select DVB_MB86A20S if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT + select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT ---help--- This adds support for DVB cards based on the diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 276374fbaf4f..967115104047 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -21,14 +21,14 @@ 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 + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MC44S803 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA18218 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver @@ -36,26 +36,26 @@ 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 + select MEDIA_TUNER_TUA9001 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_FC0011 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA18218 if MEDIA_SUBDRV_AUTOSELECT 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 + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT + select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT + select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT + select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT + select DVB_ISL6423 if MEDIA_SUBDRV_AUTOSELECT + select DVB_CXD2820R if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Anysee E30, Anysee E30 Plus or Anysee E30 C Plus DVB USB2.0 receiver. @@ -63,8 +63,8 @@ config DVB_USB_ANYSEE 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 + select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver. @@ -72,8 +72,8 @@ config DVB_USB_AZ6007 tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support" depends on DVB_USB_V2 select DVB_USB_CYPRESS_FIRMWARE - select DVB_DRXK if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2063 if !DVB_FE_CUSTOMISE + select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the AZ6007 receivers like Terratec H7. @@ -81,7 +81,7 @@ 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 + select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver @@ -89,15 +89,15 @@ 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 + select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT 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 + select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0 receiver with USB ID 0db0:5581. @@ -112,21 +112,21 @@ config DVB_USB_IT913X config DVB_USB_LME2510 tristate "LME DM04/QQBOX DVB-S USB2.0 support" depends on DVB_USB_V2 - select DVB_TDA10086 if !DVB_FE_CUSTOMISE - select DVB_TDA826X if !DVB_FE_CUSTOMISE - select DVB_STV0288 if !DVB_FE_CUSTOMISE - select DVB_IX2505V if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_M88RS2000 if !DVB_FE_CUSTOMISE + select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT + select DVB_IX2505V if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT + select DVB_M88RS2000 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 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 DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LG2160 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TVEEPROM help Say Y here to support the MxL111SF USB2.0 DTV receiver. @@ -136,11 +136,11 @@ config DVB_USB_RTL28XXU depends on DVB_USB_V2 && EXPERIMENTAL select DVB_RTL2830 select DVB_RTL2832 - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_FC0012 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_FC0013 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_FC0012 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_FC0013 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Realtek RTL28xxU DVB USB receiver. diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig index 00173ee15d4a..3c5fff89dbf1 100644 --- a/drivers/media/usb/dvb-usb/Kconfig +++ b/drivers/media/usb/dvb-usb/Kconfig @@ -24,17 +24,17 @@ config DVB_USB_A800 tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)" depends on DVB_USB select DVB_DIB3000MC - select DVB_PLL if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver. config DVB_USB_DIBUSB_MB tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)" depends on DVB_USB - select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT select DVB_DIB3000MB - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT help Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by DiBcom () equipped with a DiB3000M-B demodulator. @@ -55,7 +55,7 @@ config DVB_USB_DIBUSB_MC tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)" depends on DVB_USB select DVB_DIB3000MC - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT help Support for USB2.0 DVB-T receivers based on reference designs made by DiBcom () equipped with a DiB3000M-C/P demodulator. @@ -69,20 +69,20 @@ config DVB_USB_DIBUSB_MC config DVB_USB_DIB0700 tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)" depends on DVB_USB - select DVB_DIB7000P if !DVB_FE_CUSTOMISE - select DVB_DIB7000M if !DVB_FE_CUSTOMISE - select DVB_DIB8000 if !DVB_FE_CUSTOMISE - select DVB_DIB3000MC if !DVB_FE_CUSTOMISE - select DVB_S5H1411 if !DVB_FE_CUSTOMISE - select DVB_LGDT3305 if !DVB_FE_CUSTOMISE - select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE - select DVB_TUNER_DIB0090 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE + select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT + select DVB_DIB7000M if MEDIA_SUBDRV_AUTOSELECT + select DVB_DIB8000 if MEDIA_SUBDRV_AUTOSELECT + select DVB_DIB3000MC if MEDIA_SUBDRV_AUTOSELECT + select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TUNER_DIB0090 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MT2266 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_XC4000 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The USB bridge is also present in devices having the DiB7700 DVB-T-USB @@ -98,29 +98,29 @@ config DVB_USB_DIB0700 config DVB_USB_UMT_010 tristate "HanfTek UMT-010 DVB-T USB2.0 support" depends on DVB_USB - select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT select DVB_DIB3000MC - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT + select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver. config DVB_USB_CXUSB tristate "Conexant USB2.0 hybrid reference design support" depends on DVB_USB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_CX22702 if !DVB_FE_CUSTOMISE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_DIB7000P if !DVB_FE_CUSTOMISE - select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE - select DVB_ATBM8830 if !DVB_FE_CUSTOMISE - select DVB_LGS8GXX if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MAX2165 if !MEDIA_TUNER_CUSTOMISE + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT + select DVB_CX22702 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT + select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT + select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT + select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT + select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT + select DVB_ATBM8830 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LGS8GXX if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MAX2165 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Conexant USB2.0 hybrid reference design. Currently, only DVB and ATSC modes are supported, analog mode @@ -132,11 +132,11 @@ config DVB_USB_CXUSB config DVB_USB_M920X tristate "Uli m920x DVB-T USB2.0 support" depends on DVB_USB - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_TDA1004X if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE + select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA827X if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver. Currently, only devices with a product id of @@ -146,9 +146,9 @@ config DVB_USB_M920X config DVB_USB_DIGITV tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" depends on DVB_USB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_NXT6000 if !DVB_FE_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT + select DVB_NXT6000 if MEDIA_SUBDRV_AUTOSELECT + select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver. @@ -191,17 +191,17 @@ config DVB_USB_NOVA_T_USB2 tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" depends on DVB_USB select DVB_DIB3000MC - select DVB_PLL if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. config DVB_USB_TTUSB2 tristate "Pinnacle 400e DVB-S USB2.0 support" depends on DVB_USB - select DVB_TDA10086 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_TDA826X if !DVB_FE_CUSTOMISE + select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The firmware protocol used by this module is similar to the one used by the @@ -220,16 +220,16 @@ config DVB_USB_DTT200U config DVB_USB_OPERA1 tristate "Opera1 DVB-S USB2.0 receiver" depends on DVB_USB - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Opera DVB-S USB2.0 receiver. config DVB_USB_AF9005 tristate "Afatech AF9005 DVB-T USB1.1 support" depends on DVB_USB && EXPERIMENTAL - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver and the TerraTec Cinergy T USB XE (Rev.1) @@ -245,9 +245,9 @@ config DVB_USB_PCTV452E tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600" depends on DVB_USB select TTPCI_EEPROM - select DVB_LNBP22 if !DVB_FE_CUSTOMISE - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE + select DVB_LNBP22 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT help Support for external USB adapter designed by Pinnacle, shipped under the brand name 'PCTV HDTV Pro USB'. @@ -257,19 +257,19 @@ config DVB_USB_PCTV452E config DVB_USB_DW2102 tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support" depends on DVB_USB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_STV0288 if !DVB_FE_CUSTOMISE - select DVB_STB6000 if !DVB_FE_CUSTOMISE - select DVB_CX24116 if !DVB_FE_CUSTOMISE - select DVB_SI21XX if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select DVB_MT312 if !DVB_FE_CUSTOMISE - select DVB_ZL10039 if !DVB_FE_CUSTOMISE - select DVB_DS3000 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE - select DVB_STV6110 if !DVB_FE_CUSTOMISE - select DVB_STV0900 if !DVB_FE_CUSTOMISE + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT + select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT + select DVB_SI21XX if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT + select DVB_MT312 if MEDIA_SUBDRV_AUTOSELECT + select DVB_ZL10039 if MEDIA_SUBDRV_AUTOSELECT + select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the DvbWorld, TeVii, Prof DVB-S/S2 USB2.0 receivers. @@ -285,8 +285,8 @@ config DVB_USB_CINERGY_T2 config DVB_USB_DTV5100 tristate "AME DTV-5100 USB2.0 DVB-T support" depends on DVB_USB - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver. @@ -299,15 +299,15 @@ config DVB_USB_FRIIO config DVB_USB_AZ6027 tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support" depends on DVB_USB - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE + select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the AZ6027 device config DVB_USB_TECHNISAT_USB2 tristate "Technisat DVB-S/S2 USB2.0 support" depends on DVB_USB - select DVB_STV090x if !DVB_FE_CUSTOMISE - select DVB_STV6110x if !DVB_FE_CUSTOMISE + select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Technisat USB2 DVB-S/S2 device diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig index 928ef0d0429f..7a5bd61bd3bb 100644 --- a/drivers/media/usb/em28xx/Kconfig +++ b/drivers/media/usb/em28xx/Kconfig @@ -4,10 +4,10 @@ config VIDEO_EM28XX select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEOBUF_VMALLOC - select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_MT9V011 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT ---help--- This is a video4linux driver for Empia 28xx based TV cards. @@ -33,16 +33,16 @@ config VIDEO_EM28XX_ALSA config VIDEO_EM28XX_DVB tristate "DVB/ATSC Support for em28xx based TV cards" depends on VIDEO_EM28XX && DVB_CORE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select DVB_S921 if !DVB_FE_CUSTOMISE - select DVB_DRXD if !DVB_FE_CUSTOMISE - select DVB_CXD2820R if !DVB_FE_CUSTOMISE - select DVB_DRXK if !DVB_FE_CUSTOMISE - select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE - select DVB_TDA10071 if !DVB_FE_CUSTOMISE - select DVB_A8293 if !DVB_FE_CUSTOMISE + select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT + select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT + select DVB_S921 if MEDIA_SUBDRV_AUTOSELECT + select DVB_DRXD if MEDIA_SUBDRV_AUTOSELECT + select DVB_CXD2820R if MEDIA_SUBDRV_AUTOSELECT + select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA10071 if MEDIA_SUBDRV_AUTOSELECT + select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT select VIDEOBUF_DVB ---help--- This adds support for DVB cards based on the diff --git a/drivers/media/usb/pvrusb2/Kconfig b/drivers/media/usb/pvrusb2/Kconfig index 25e412ecad2c..32b11c15bb1a 100644 --- a/drivers/media/usb/pvrusb2/Kconfig +++ b/drivers/media/usb/pvrusb2/Kconfig @@ -36,13 +36,13 @@ config VIDEO_PVRUSB2_DVB bool "pvrusb2 ATSC/DVB support (EXPERIMENTAL)" default y depends on VIDEO_PVRUSB2 && DVB_CORE && EXPERIMENTAL - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_S5H1409 if !DVB_FE_CUSTOMISE - select DVB_S5H1411 if !DVB_FE_CUSTOMISE - select DVB_TDA10048 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE + select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT + select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT + select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT ---help--- This option enables a DVB interface for the pvrusb2 driver. diff --git a/drivers/media/usb/ttusb-budget/Kconfig b/drivers/media/usb/ttusb-budget/Kconfig index 2663ae39b886..97bad7da689c 100644 --- a/drivers/media/usb/ttusb-budget/Kconfig +++ b/drivers/media/usb/ttusb-budget/Kconfig @@ -1,13 +1,13 @@ config DVB_TTUSB_BUDGET tristate "Technotrend/Hauppauge Nova-USB devices" depends on DVB_CORE && USB && I2C && PCI - select DVB_CX22700 if !DVB_FE_CUSTOMISE - select DVB_TDA1004X if !DVB_FE_CUSTOMISE - select DVB_VES1820 if !DVB_FE_CUSTOMISE - select DVB_TDA8083 if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_STV0297 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_CX22700 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT + select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT help Support for external USB adapters designed by Technotrend and produced by Hauppauge, shipped under the brand name 'Nova-USB'. diff --git a/drivers/media/usb/usbvision/Kconfig b/drivers/media/usb/usbvision/Kconfig index fc24ef05b3f3..6b6afc5d8f7e 100644 --- a/drivers/media/usb/usbvision/Kconfig +++ b/drivers/media/usb/usbvision/Kconfig @@ -2,7 +2,7 @@ config VIDEO_USBVISION tristate "USB video devices based on Nogatech NT1003/1004/1005" depends on I2C && VIDEO_V4L2 select VIDEO_TUNER - select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT ---help--- There are more than 50 different USB video devices based on NT1003/1004/1005 USB Bridges. This driver enables using those -- cgit 1.4.1