diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2008-05-13 12:17:27 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2008-05-13 12:17:27 +1000 |
commit | 7f55620ac9f1becb9a0b1a932dd21553c2e4e9f4 (patch) | |
tree | 162f1999d73c090e7dc2f2ef60c4387756022a92 /drivers | |
parent | 24aad0ffb944a437cef53b0c2dc395a2a93b0a17 (diff) | |
parent | 647af7de65a7920b4d201ee7e0354dc2e68849f4 (diff) |
Merge commit 'v4l-dvb/stable'
Diffstat (limited to 'drivers')
67 files changed, 6544 insertions, 428 deletions
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig index 5be85ff53e12..394cb050bc77 100644 --- a/drivers/media/common/tuners/Kconfig +++ b/drivers/media/common/tuners/Kconfig @@ -19,9 +19,9 @@ config MEDIA_ATTACH config MEDIA_TUNER tristate - default DVB_CORE || VIDEO_DEV - depends on DVB_CORE || VIDEO_DEV - select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE + default VIDEO_MEDIA && I2C + depends on VIDEO_MEDIA && I2C + select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE && HOTPLUG select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMIZE select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMIZE @@ -46,7 +46,6 @@ if MEDIA_TUNER_CUSTOMIZE config MEDIA_TUNER_SIMPLE tristate "Simple tuner support" - depends on I2C select MEDIA_TUNER_TDA9887 default m if MEDIA_TUNER_CUSTOMIZE help @@ -54,7 +53,6 @@ config MEDIA_TUNER_SIMPLE config MEDIA_TUNER_TDA8290 tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" - depends on I2C select MEDIA_TUNER_TDA827X select MEDIA_TUNER_TDA18271 default m if MEDIA_TUNER_CUSTOMIZE @@ -63,21 +61,18 @@ config MEDIA_TUNER_TDA8290 config MEDIA_TUNER_TDA827X tristate "Philips TDA827X silicon tuner" - depends on DVB_CORE && I2C default m if DVB_FE_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 I2C default m if DVB_FE_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 I2C default m if MEDIA_TUNER_CUSTOMIZE help Say Y here to include support for Philips TDA9885/6/7 @@ -85,67 +80,70 @@ config MEDIA_TUNER_TDA9887 config MEDIA_TUNER_TEA5761 tristate "TEA 5761 radio tuner (EXPERIMENTAL)" - depends on I2C && EXPERIMENTAL + depends on EXPERIMENTAL default m if MEDIA_TUNER_CUSTOMIZE help Say Y here to include support for the Philips TEA5761 radio tuner. config MEDIA_TUNER_TEA5767 tristate "TEA 5767 radio tuner" - depends on I2C default m if MEDIA_TUNER_CUSTOMIZE help Say Y here to include support for the Philips TEA5767 radio tuner. config MEDIA_TUNER_MT20XX tristate "Microtune 2032 / 2050 tuners" - depends on I2C default m if MEDIA_TUNER_CUSTOMIZE help Say Y here to include support for the MT2032 / MT2050 tuner. config MEDIA_TUNER_MT2060 tristate "Microtune MT2060 silicon IF tuner" - depends on I2C default m if DVB_FE_CUSTOMISE help A driver for the silicon IF tuner MT2060 from Microtune. config MEDIA_TUNER_MT2266 tristate "Microtune MT2266 silicon tuner" - depends on I2C default m if DVB_FE_CUSTOMISE help A driver for the silicon baseband tuner MT2266 from Microtune. config MEDIA_TUNER_MT2131 tristate "Microtune MT2131 silicon tuner" - depends on I2C default m if DVB_FE_CUSTOMISE help A driver for the silicon baseband tuner MT2131 from Microtune. config MEDIA_TUNER_QT1010 tristate "Quantek QT1010 silicon tuner" - depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help A driver for the silicon tuner QT1010 from Quantek. config MEDIA_TUNER_XC2028 tristate "XCeive xc2028/xc3028 tuners" - depends on I2C && FW_LOADER + depends on HOTPLUG + select FW_LOADER default m if MEDIA_TUNER_CUSTOMIZE help Say Y here to include support for the xc2028/xc3028 tuners. config MEDIA_TUNER_XC5000 tristate "Xceive XC5000 silicon tuner" - depends on I2C + depends on HOTPLUG + select FW_LOADER default m if DVB_FE_CUSTOMISE help A driver for the silicon tuner XC5000 from Xceive. This device is only used inside a SiP called togther with a demodulator for now. +config MEDIA_TUNER_MXL5005S + tristate "MaxLinear MSL5005S silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon tuner MXL5005S from MaxLinear. + endif # MEDIA_TUNER_CUSTOMIZE diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile index 236d9932fd92..55f7e6706297 100644 --- a/drivers/media/common/tuners/Makefile +++ b/drivers/media/common/tuners/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.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 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c new file mode 100644 index 000000000000..5d05b5390f66 --- /dev/null +++ b/drivers/media/common/tuners/mxl5005s.c @@ -0,0 +1,4110 @@ +/* + MaxLinear MXL5005S VSB/QAM/DVBT tuner driver + + Copyright (C) 2008 MaxLinear + Copyright (C) 2006 Steven Toth <stoth@hauppauge.com> + 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 <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/delay.h> +#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 +} tuner_modu_type; + +/* MXL5005 Tuner Register Struct */ +struct TunerReg { + u16 Reg_Num; /* Tuner Register Address */ + u16 Reg_Val; /* Current sw programmed value waiting to be writen */ +}; + +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 +} MXL5005_ControlName; + +/* + * 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 u32 MXL_GetXtalInt(u32 Xtal_Freq); +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 u32 MXL_GetXtalInt(u32 Xtal_Freq) +{ + if ((Xtal_Freq % 1000000) == 0) + return (Xtal_Freq / 10000); + else + return (((Xtal_Freq / 1000000) + 1)*100); +} + +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 Xtal_Int; + + u32 Fref_TG; + u32 Fvco; + + Xtal_Int = MXL_GetXtalInt(state->Fxtal); + + 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. + * 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->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<<k); + *value = ctrlVal; + return 0; + } + } + + for (i = 0; i < state->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<<k); + *value = ctrlVal; + return 0; + + } + } +#endif + return 1; +} + +static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit, + u8 bitVal) +{ + struct mxl5005s_state *state = fe->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 = sizeof(RegAddr) / sizeof(u8); + + 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 = sizeof(RegAddr) / sizeof(u8); + + 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 = sizeof(RegAddr) / sizeof(u8); + + 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 <stoth@hauppauge.com> + */ +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) +{ + dprintk(1, "%s()\n", __func__); + 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 dvb_frontend_parameters *params) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u32 req_mode, req_bw = 0; + int ret; + + dprintk(1, "%s()\n", __func__); + + if (fe->ops.info.type == FE_ATSC) { + switch (params->u.vsb.modulation) { + case VSB_8: + req_mode = MXL_ATSC; break; + default: + case QAM_64: + case QAM_256: + case QAM_AUTO: + req_mode = MXL_QAM; break; + } + } else + req_mode = MXL_DVBT; + + /* Change tuner for new modulation type if reqd */ + if (req_mode != state->current_mode) { + switch (req_mode) { + case VSB_8: + case QAM_64: + case QAM_256: + case QAM_AUTO: + req_bw = MXL5005S_BANDWIDTH_6MHZ; + break; + default: + /* Assume DVB-T */ + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + req_bw = MXL5005S_BANDWIDTH_6MHZ; + break; + case BANDWIDTH_7_MHZ: + req_bw = MXL5005S_BANDWIDTH_7MHZ; + break; + case BANDWIDTH_AUTO: + case BANDWIDTH_8_MHZ: + req_bw = MXL5005S_BANDWIDTH_8MHZ; + break; + } + } + + 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__, params->frequency); + ret = mxl5005s_SetRfFreqHz(fe, params->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; + state->current_mode = MXL_QAM; + + 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 new file mode 100644 index 000000000000..396db150bf0c --- /dev/null +++ b/drivers/media/common/tuners/mxl5005s.h @@ -0,0 +1,131 @@ +/* + MaxLinear MXL5005S VSB/QAM/DVBT tuner driver + + Copyright (C) 2008 MaxLinear + Copyright (C) 2008 Steven Toth <stoth@hauppauge.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; 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 <linux/i2c.h> +#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; + + /* 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/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c index e27a7620a32f..42b5f5d4bfe6 100644 --- a/drivers/media/common/tuners/tda18271-common.c +++ b/drivers/media/common/tuners/tda18271-common.c @@ -227,9 +227,8 @@ int tda18271_charge_pump_source(struct dvb_frontend *fe, regs[r_cp] &= ~0x20; regs[r_cp] |= ((force & 1) << 5); - tda18271_write_regs(fe, r_cp, 1); - return 0; + return tda18271_write_regs(fe, r_cp, 1); } int tda18271_init_regs(struct dvb_frontend *fe) @@ -487,16 +486,15 @@ int tda18271_set_standby_mode(struct dvb_frontend *fe, struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; - tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt); + 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; - tda18271_write_regs(fe, R_EP3, 1); - - return 0; + return tda18271_write_regs(fe, R_EP3, 1); } /*---------------------------------------------------------------------*/ @@ -510,7 +508,7 @@ int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) u32 div; int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d); - if (ret < 0) + if (tda_fail(ret)) goto fail; regs[R_MPD] = (0x77 & pd); @@ -542,7 +540,7 @@ int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq) u32 div; int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d); - if (ret < 0) + if (tda_fail(ret)) goto fail; regs[R_CPD] = pd; @@ -566,7 +564,7 @@ int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq) u8 val; int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val); - if (ret < 0) + if (tda_fail(ret)) goto fail; regs[R_EP1] &= ~0x07; /* clear bp filter bits */ @@ -583,7 +581,7 @@ int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq) u8 val; int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val); - if (ret < 0) + if (tda_fail(ret)) goto fail; regs[R_EB13] &= ~0x7c; /* clear k & m bits */ @@ -600,7 +598,7 @@ int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq) u8 val; int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val); - if (ret < 0) + if (tda_fail(ret)) goto fail; regs[R_EP2] &= ~0xe0; /* clear rf band bits */ @@ -617,7 +615,7 @@ int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq) u8 val; int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val); - if (ret < 0) + if (tda_fail(ret)) goto fail; regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ @@ -634,7 +632,7 @@ int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq) u8 val; int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val); - if (ret < 0) + if (tda_fail(ret)) goto fail; regs[R_EP5] &= ~0x07; diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c index b262100ae897..89c01fb1f859 100644 --- a/drivers/media/common/tuners/tda18271-fe.c +++ b/drivers/media/common/tuners/tda18271-fe.c @@ -51,6 +51,7 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe, { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; + int ret; u32 N; /* update TV broadcast parameters */ @@ -85,7 +86,9 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe, /* update rf top / if top */ regs[R_EB22] = 0x00; regs[R_EB22] |= map->rfagc_top; - tda18271_write_regs(fe, R_EB22, 1); + ret = tda18271_write_regs(fe, R_EB22, 1); + if (tda_fail(ret)) + goto fail; /* --------------------------------------------------------------- */ @@ -121,7 +124,9 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe, /* agc1 has priority on agc2 */ regs[R_EB1] &= ~0x01; - tda18271_write_regs(fe, R_EB1, 1); + ret = tda18271_write_regs(fe, R_EB1, 1); + if (tda_fail(ret)) + goto fail; /* --------------------------------------------------------------- */ @@ -141,7 +146,9 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe, break; } - tda18271_write_regs(fe, R_TM, 7); + ret = tda18271_write_regs(fe, R_TM, 7); + if (tda_fail(ret)) + goto fail; /* force charge pump source */ charge_pump_source(fe, 1); @@ -158,9 +165,9 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe, regs[R_EP3] &= ~0x04; else regs[R_EP3] |= 0x04; - tda18271_write_regs(fe, R_EP3, 1); - - return 0; + ret = tda18271_write_regs(fe, R_EP3, 1); +fail: + return ret; } static int tda18271_read_thermometer(struct dvb_frontend *fe) @@ -213,11 +220,13 @@ static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe, 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 tm_current, rfcal_comp, approx, i; + int tm_current, rfcal_comp, approx, i, ret; u8 dc_over_dt, rf_tab; /* power up */ - tda18271_set_standby_mode(fe, 0, 0, 0); + 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); @@ -228,8 +237,8 @@ static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe, rf_tab = regs[R_EB14]; i = tda18271_lookup_rf_band(fe, &freq, NULL); - if (i < 0) - return -EINVAL; + if (tda_fail(i)) + return i; if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) { approx = map[i].rf_a1 * @@ -250,35 +259,42 @@ static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe, rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal); regs[R_EB14] = approx + rfcal_comp; - tda18271_write_regs(fe, R_EB14, 1); - - return 0; + 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; - tda18271_write_regs(fe, R_EB12, 1); + 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 */ - tda18271_write_regs(fe, R_EB18, 1); + 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 */ - tda18271_set_standby_mode(fe, 1, 0, 0); + 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 */ - tda18271_write_regs(fe, R_EB21, 3); - - return 0; + ret = tda18271_write_regs(fe, R_EB21, 3); +fail: + return ret; } static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq) @@ -389,7 +405,7 @@ static int tda18271_powerscan(struct dvb_frontend *fe, { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; - int sgn, bcal, count, wait; + int sgn, bcal, count, wait, ret; u8 cid_target; u16 count_limit; u32 freq; @@ -421,7 +437,9 @@ static int tda18271_powerscan(struct dvb_frontend *fe, tda18271_write_regs(fe, R_EP2, 1); /* read power detection info, stored in EB10 */ - tda18271_read_extended(fe); + ret = tda18271_read_extended(fe); + if (tda_fail(ret)) + return ret; /* algorithm initialization */ sgn = 1; @@ -447,7 +465,9 @@ static int tda18271_powerscan(struct dvb_frontend *fe, tda18271_write_regs(fe, R_EP2, 1); /* read power detection info, stored in EB10 */ - tda18271_read_extended(fe); + ret = tda18271_read_extended(fe); + if (tda_fail(ret)) + return ret; count += 200; @@ -478,6 +498,7 @@ 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 */ @@ -489,10 +510,14 @@ static int tda18271_powerscan_init(struct dvb_frontend *fe) /* update IF output level & IF notch frequency */ regs[R_EP4] &= ~0x1c; /* clear if level bits */ - tda18271_write_regs(fe, R_EP3, 2); + ret = tda18271_write_regs(fe, R_EP3, 2); + if (tda_fail(ret)) + goto fail; regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ - tda18271_write_regs(fe, R_EB18, 1); + ret = tda18271_write_regs(fe, R_EB18, 1); + if (tda_fail(ret)) + goto fail; regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */ @@ -500,9 +525,9 @@ static int tda18271_powerscan_init(struct dvb_frontend *fe) regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */ regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */ - tda18271_write_regs(fe, R_EB21, 3); - - return 0; + ret = tda18271_write_regs(fe, R_EB21, 3); +fail: + return ret; } static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) @@ -521,7 +546,7 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) i = tda18271_lookup_rf_band(fe, &freq, NULL); - if (i < 0) + if (tda_fail(i)) return i; rf_default[RF1] = 1000 * map[i].rf1_def; @@ -535,6 +560,8 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) /* 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] = regs[R_EB14]; @@ -575,22 +602,29 @@ 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); - tda18271_powerscan_init(fe); + 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++) + 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); - - return 0; +fail: + return ret; } /* ------------------------------------------------------------------ */ @@ -599,6 +633,7 @@ 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) @@ -607,15 +642,22 @@ static int tda18271c2_rf_cal_init(struct dvb_frontend *fe) if (priv->cal_initialized) return 0; - tda18271_calc_rf_filter_curve(fe); + ret = tda18271_calc_rf_filter_curve(fe); + if (tda_fail(ret)) + goto fail; - tda18271_por(fe); + ret = tda18271_por(fe); + if (tda_fail(ret)) + goto fail; tda_info("tda18271: RF tracking filter calibration complete\n"); priv->cal_initialized = true; - - return 0; + 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, @@ -623,6 +665,7 @@ static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe, { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; + int ret; u32 N = 0; /* calculate bp filter */ @@ -671,7 +714,10 @@ static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe, tda18271_calc_main_pll(fe, N); - tda18271_write_regs(fe, R_EP3, 11); + 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 */ @@ -719,45 +765,56 @@ 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; - tda18271_read_regs(fe); + 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) - tda18271_init_regs(fe); - - return 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); /* power up */ - tda18271_set_standby_mode(fe, 0, 0, 0); + ret = tda18271_set_standby_mode(fe, 0, 0, 0); + if (tda_fail(ret)) + goto fail; /* initialization */ - tda18271_ir_cal_init(fe); + 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 0; + 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); - tda18271_init(fe); + ret = tda18271_init(fe); + if (tda_fail(ret)) + goto fail; mutex_lock(&priv->lock); @@ -769,11 +826,11 @@ static int tda18271_tune(struct dvb_frontend *fe, tda18271c2_rf_tracking_filters_correction(fe, freq); break; } - tda18271_channel_configuration(fe, map, freq, bw); + ret = tda18271_channel_configuration(fe, map, freq, bw); mutex_unlock(&priv->lock); - - return 0; +fail: + return ret; } /* ------------------------------------------------------------------ */ @@ -837,7 +894,7 @@ static int tda18271_set_params(struct dvb_frontend *fe, ret = tda18271_tune(fe, map, freq, bw); - if (ret < 0) + if (tda_fail(ret)) goto fail; priv->frequency = freq; @@ -893,7 +950,7 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe, ret = tda18271_tune(fe, map, freq, 0); - if (ret < 0) + if (tda_fail(ret)) goto fail; priv->frequency = freq; @@ -905,16 +962,17 @@ fail: static int tda18271_sleep(struct dvb_frontend *fe) { struct tda18271_priv *priv = fe->tuner_priv; + int ret; mutex_lock(&priv->lock); /* standby mode w/ slave tuner output * & loop thru & xtal oscillator on */ - tda18271_set_standby_mode(fe, 1, 0, 0); + ret = tda18271_set_standby_mode(fe, 1, 0, 0); mutex_unlock(&priv->lock); - return 0; + return ret; } static int tda18271_release(struct dvb_frontend *fe) @@ -1095,10 +1153,10 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, if (cfg) priv->small_i2c = cfg->small_i2c; - if (tda18271_get_id(fe) < 0) + if (tda_fail(tda18271_get_id(fe))) goto fail; - if (tda18271_assign_map_layout(fe) < 0) + if (tda_fail(tda18271_assign_map_layout(fe))) goto fail; mutex_lock(&priv->lock); diff --git a/drivers/media/common/tuners/tda18271-priv.h b/drivers/media/common/tuners/tda18271-priv.h index 2bc5eb368ea2..81a739365f8c 100644 --- a/drivers/media/common/tuners/tda18271-priv.h +++ b/drivers/media/common/tuners/tda18271-priv.h @@ -153,6 +153,15 @@ extern int tda18271_debug; #define tda_reg(fmt, arg...) dprintk(KERN_DEBUG, DBG_REG, fmt, ##arg) #define tda_cal(fmt, arg...) dprintk(KERN_DEBUG, DBG_CAL, fmt, ##arg) +#define tda_fail(ret) \ +({ \ + int __ret; \ + __ret = (ret < 0); \ + if (__ret) \ + tda_printk(KERN_ERR, "error %d on line %d\n", ret, __LINE__);\ + __ret; \ +}) + /*---------------------------------------------------------------------*/ enum tda18271_map_type { diff --git a/drivers/media/common/tuners/tea5767.c b/drivers/media/common/tuners/tea5767.c index f6e7d7ad8424..1f5646334a8f 100644 --- a/drivers/media/common/tuners/tea5767.c +++ b/drivers/media/common/tuners/tea5767.c @@ -373,14 +373,14 @@ int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) 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; + 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; + return -EINVAL; } /* Status bytes: @@ -390,7 +390,7 @@ int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) */ 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 -EINVAL; } diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index 7b0ea3bdfafb..f9d087669d5d 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -634,7 +634,7 @@ int flexcop_frontend_init(struct flexcop_device *fc) } /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */ - fc->fe = dvb_attach(vp310_mt312_attach, + fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c); if (fc->fe != NULL) { ops = &fc->fe->ops; diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig index d1239b8342f8..7588db1319d0 100644 --- a/drivers/media/dvb/bt8xx/Kconfig +++ b/drivers/media/dvb/bt8xx/Kconfig @@ -1,6 +1,7 @@ config DVB_BT8XX tristate "BT8xx based PCI cards" depends on DVB_CORE && PCI && I2C && VIDEO_BT848 + depends on HOTPLUG # due to FW_LOADER select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_SP887X if !DVB_FE_CUSTOMISE select DVB_NXT6000 if !DVB_FE_CUSTOMISE diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig index 3d778c5aba68..c03513b2ccae 100644 --- a/drivers/media/dvb/cinergyT2/Kconfig +++ b/drivers/media/dvb/cinergyT2/Kconfig @@ -1,6 +1,6 @@ config DVB_CINERGYT2 tristate "Terratec CinergyT2/qanu USB2 DVB-T receiver" - depends on DVB_CORE && USB + depends on DVB_CORE && USB && INPUT help Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 8cbdb0ec67e2..588fbe105c27 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -910,15 +910,21 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) int curdelay = 100000000; int slot; + /* Beware of too high polling frequency, because one polling + * call might take several hundred milliseconds until timeout! + */ for (slot = 0; slot < ca->slot_count; slot++) { switch (ca->slot_info[slot].slot_state) { default: case DVB_CA_SLOTSTATE_NONE: + delay = HZ * 60; /* 60s */ + if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) + delay = HZ * 5; /* 5s */ + break; case DVB_CA_SLOTSTATE_INVALID: - delay = HZ * 60; - if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) { - delay = HZ / 10; - } + delay = HZ * 60; /* 60s */ + if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) + delay = HZ / 10; /* 100ms */ break; case DVB_CA_SLOTSTATE_UNINITIALISED: @@ -926,19 +932,17 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) case DVB_CA_SLOTSTATE_VALIDATE: case DVB_CA_SLOTSTATE_WAITFR: case DVB_CA_SLOTSTATE_LINKINIT: - delay = HZ / 10; + delay = HZ / 10; /* 100ms */ break; case DVB_CA_SLOTSTATE_RUNNING: - delay = HZ * 60; - if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) { - delay = HZ / 10; - } + delay = HZ * 60; /* 60s */ + if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) + delay = HZ / 10; /* 100ms */ if (ca->open) { if ((!ca->slot_info[slot].da_irq_supported) || - (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) { - delay = HZ / 10; - } + (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) + delay = HZ / 10; /* 100ms */ } break; } diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 4c1cff9feb2e..cf4584e48b6d 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -1,6 +1,7 @@ config DVB_USB tristate "Support for various USB DVB devices" depends on DVB_CORE && USB && I2C + depends on HOTPLUG # due to FW_LOADER select FW_LOADER help By enabling this you will be able to choose the various supported diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 6d2384605927..fa7f0c563770 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -30,7 +30,7 @@ config DVB_CX24123 A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_MT312 - tristate "Zarlink VP310/MT312 based" + tristate "Zarlink VP310/MT312/ZL10313 based" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help @@ -97,7 +97,7 @@ comment "DVB-T (terrestrial) frontends" config DVB_SP8870 tristate "Spase sp8870 based" - depends on DVB_CORE && I2C + depends on DVB_CORE && I2C && HOTPLUG default m if DVB_FE_CUSTOMISE select FW_LOADER help @@ -110,7 +110,7 @@ config DVB_SP8870 config DVB_SP887X tristate "Spase sp887x based" - depends on DVB_CORE && I2C + depends on DVB_CORE && I2C && HOTPLUG default m if DVB_FE_CUSTOMISE select FW_LOADER help @@ -135,6 +135,20 @@ config DVB_CX22702 help A DVB-T tuner module. Say Y when you want to support this frontend. +config DVB_DRX397XD + tristate "Micronas DRX3975D/DRX3977D based" + depends on DVB_CORE && I2C && HOTPLUG + default m if DVB_FE_CUSTOMISE + select FW_LOADER + help + A DVB-T tuner module. Say Y when you want to support this frontend. + + TODO: + This driver needs external firmware. Please use the command + "<kerneldir>/Documentation/dvb/get_dvb_firmware drx397xD" to + download/extract them, and then copy them to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + config DVB_L64781 tristate "LSI L64781" depends on DVB_CORE && I2C @@ -144,7 +158,7 @@ config DVB_L64781 config DVB_TDA1004X tristate "Philips TDA10045H/TDA10046H based" - depends on DVB_CORE && I2C + depends on DVB_CORE && I2C && HOTPLUG default m if DVB_FE_CUSTOMISE select FW_LOADER help @@ -211,7 +225,7 @@ config DVB_DIB7000P config DVB_TDA10048 tristate "Philips TDA10048HN based" - depends on DVB_CORE && I2C + depends on DVB_CORE && I2C && HOTPLUG default m if DVB_FE_CUSTOMISE select FW_LOADER help @@ -253,7 +267,7 @@ comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends" config DVB_NXT200X tristate "NxtWave Communications NXT2002/NXT2004 based" - depends on DVB_CORE && I2C + depends on DVB_CORE && I2C && HOTPLUG default m if DVB_FE_CUSTOMISE select FW_LOADER help @@ -268,7 +282,7 @@ config DVB_NXT200X config DVB_OR51211 tristate "Oren OR51211 based" - depends on DVB_CORE && I2C + depends on DVB_CORE && I2C && HOTPLUG default m if DVB_FE_CUSTOMISE select FW_LOADER help @@ -281,7 +295,7 @@ config DVB_OR51211 config DVB_OR51132 tristate "Oren OR51132 based" - depends on DVB_CORE && I2C + depends on DVB_CORE && I2C && HOTPLUG default m if DVB_FE_CUSTOMISE select FW_LOADER help @@ -297,7 +311,7 @@ config DVB_OR51132 config DVB_BCM3510 tristate "Broadcom BCM3510" - depends on DVB_CORE && I2C + depends on DVB_CORE && I2C && HOTPLUG default m if DVB_FE_CUSTOMISE select FW_LOADER help diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index a89dc0fc4c6f..028da55611c0 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_DVB_NXT6000) += nxt6000.o obj-$(CONFIG_DVB_MT352) += mt352.o obj-$(CONFIG_DVB_ZL10353) += zl10353.o obj-$(CONFIG_DVB_CX22702) += cx22702.o +obj-$(CONFIG_DVB_DRX397XD) += drx397xD.o obj-$(CONFIG_DVB_TDA10021) += tda10021.o obj-$(CONFIG_DVB_TDA10023) += tda10023.o obj-$(CONFIG_DVB_STV0297) += stv0297.o diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c new file mode 100644 index 000000000000..d71cce93d08e --- /dev/null +++ b/drivers/media/dvb/frontends/drx397xD.c @@ -0,0 +1,1504 @@ +/* + * Driver for Micronas drx397xD demodulator + * + * Copyright (C) 2007 Henk Vergonet <Henk.Vergonet@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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, see <http://www.gnu.org/licenses/>. + */ + +#define DEBUG /* uncomment if you want debugging output */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/firmware.h> +#include <asm/div64.h> + +#include "dvb_frontend.h" +#include "drx397xD.h" + +static const char mod_name[] = "drx397xD"; + +#define MAX_CLOCK_DRIFT 200 /* maximal 200 PPM allowed */ + +#define F_SET_0D0h 1 +#define F_SET_0D4h 2 + +typedef enum fw_ix { +#define _FW_ENTRY(a, b) b +#include "drx397xD_fw.h" +} fw_ix_t; + +/* chip specifics */ +struct drx397xD_state { + struct i2c_adapter *i2c; + struct dvb_frontend frontend; + struct drx397xD_config config; + fw_ix_t chip_rev; + int flags; + u32 bandwidth_parm; /* internal bandwidth conversions */ + u32 f_osc; /* w90: actual osc frequency [Hz] */ +}; + +/******************************************************************************* + * Firmware + ******************************************************************************/ + +static const char *blob_name[] = { +#define _BLOB_ENTRY(a, b) a +#include "drx397xD_fw.h" +}; + +typedef enum blob_ix { +#define _BLOB_ENTRY(a, b) b +#include "drx397xD_fw.h" +} blob_ix_t; + +static struct { + const char *name; + const struct firmware *file; + rwlock_t lock; + int refcnt; + u8 *data[ARRAY_SIZE(blob_name)]; +} fw[] = { +#define _FW_ENTRY(a, b) { \ + .name = a, \ + .file = 0, \ + .lock = RW_LOCK_UNLOCKED, \ + .refcnt = 0, \ + .data = { } } +#include "drx397xD_fw.h" +}; + +/* use only with writer lock aquired */ +static void _drx_release_fw(struct drx397xD_state *s, fw_ix_t ix) +{ + memset(&fw[ix].data[0], 0, sizeof(fw[0].data)); + if (fw[ix].file) + release_firmware(fw[ix].file); +} + +static void drx_release_fw(struct drx397xD_state *s) +{ + fw_ix_t ix = s->chip_rev; + + pr_debug("%s\n", __FUNCTION__); + + write_lock(&fw[ix].lock); + if (fw[ix].refcnt) { + fw[ix].refcnt--; + if (fw[ix].refcnt == 0) + _drx_release_fw(s, ix); + } + write_unlock(&fw[ix].lock); +} + +static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix) +{ + u8 *data; + size_t size, len; + int i = 0, j, rc = -EINVAL; + + pr_debug("%s\n", __FUNCTION__); + + if (ix < 0 || ix >= ARRAY_SIZE(fw)) + return -EINVAL; + s->chip_rev = ix; + + write_lock(&fw[ix].lock); + if (fw[ix].file) { + rc = 0; + goto exit_ok; + } + memset(&fw[ix].data[0], 0, sizeof(fw[0].data)); + + if (request_firmware(&fw[ix].file, fw[ix].name, &s->i2c->dev) != 0) { + printk(KERN_ERR "%s: Firmware \"%s\" not available\n", + mod_name, fw[ix].name); + rc = -ENOENT; + goto exit_err; + } + + if (!fw[ix].file->data || fw[ix].file->size < 10) + goto exit_corrupt; + + data = fw[ix].file->data; + size = fw[ix].file->size; + + if (data[i++] != 2) /* check firmware version */ + goto exit_corrupt; + + do { + switch (data[i++]) { + case 0x00: /* bytecode */ + if (i >= size) + break; + i += data[i]; + case 0x01: /* reset */ + case 0x02: /* sleep */ + i++; + break; + case 0xfe: /* name */ + len = strnlen(&data[i], size - i); + if (i + len + 1 >= size) + goto exit_corrupt; + if (data[i + len + 1] != 0) + goto exit_corrupt; + for (j = 0; j < ARRAY_SIZE(blob_name); j++) { + if (strcmp(blob_name[j], &data[i]) == 0) { + fw[ix].data[j] = &data[i + len + 1]; + pr_debug("Loading %s\n", blob_name[j]); + } + } + i += len + 1; + break; + case 0xff: /* file terminator */ + if (i == size) { + rc = 0; + goto exit_ok; + } + default: + goto exit_corrupt; + } + } while (i < size); + exit_corrupt: + printk(KERN_ERR "%s: Firmware is corrupt\n", mod_name); + exit_err: + _drx_release_fw(s, ix); + fw[ix].refcnt--; + exit_ok: + fw[ix].refcnt++; + write_unlock(&fw[ix].lock); + return rc; +} + +/******************************************************************************* + * i2c bus IO + ******************************************************************************/ + +static int write_fw(struct drx397xD_state *s, blob_ix_t ix) +{ + struct i2c_msg msg = {.addr = s->config.demod_address,.flags = 0 }; + u8 *data; + int len, rc = 0, i = 0; + + if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) { + pr_debug("%s drx_fw_ix_t out of range\n", __FUNCTION__); + return -EINVAL; + } + pr_debug("%s %s\n", __FUNCTION__, blob_name[ix]); + + read_lock(&fw[s->chip_rev].lock); + data = fw[s->chip_rev].data[ix]; + if (!data) { + rc = -EINVAL; + goto exit_rc; + } + + for (;;) { + switch (data[i++]) { + case 0: /* bytecode */ + len = data[i++]; + msg.len = len; + msg.buf = &data[i]; + if (i2c_transfer(s->i2c, &msg, 1) != 1) { + rc = -EIO; + goto exit_rc; + } + i += len; + break; + case 1: /* reset */ + case 2: /* sleep */ + i++; + break; + default: + goto exit_rc; + } + } + exit_rc: + read_unlock(&fw[s->chip_rev].lock); + return 0; +} + +/* Function is not endian safe, use the RD16 wrapper below */ +static int _read16(struct drx397xD_state *s, u32 i2c_adr) +{ + int rc; + u8 a[4]; + u16 v; + struct i2c_msg msg[2] = { + { + .addr = s->config.demod_address, + .flags = 0, + .buf = a, + .len = sizeof(a) + } + , { + .addr = s->config.demod_address, + .flags = I2C_M_RD, + .buf = (u8 *) & v, + .len = sizeof(v) + } + }; + + *(u32 *) a = i2c_adr; + + rc = i2c_transfer(s->i2c, msg, 2); + if (rc != 2) + return -EIO; + + return le16_to_cpu(v); +} + +/* Function is not endian safe, use the WR16.. wrappers below */ +static int _write16(struct drx397xD_state *s, u32 i2c_adr, u16 val) +{ + u8 a[6]; + int rc; + struct i2c_msg msg = { + .addr = s->config.demod_address, + .flags = 0, + .buf = a, + .len = sizeof(a) + }; + + *(u32 *) a = i2c_adr; + *(u16 *) & a[4] = val; + + rc = i2c_transfer(s->i2c, &msg, 1); + if (rc != 1) + return -EIO; + return 0; +} + +#define WR16(ss,adr, val) \ + _write16(ss, I2C_ADR_C0(adr), cpu_to_le16(val)) +#define WR16_E0(ss,adr, val) \ + _write16(ss, I2C_ADR_E0(adr), cpu_to_le16(val)) +#define RD16(ss,adr) \ + _read16(ss, I2C_ADR_C0(adr)) + +#define EXIT_RC( cmd ) if ( (rc = (cmd)) < 0) goto exit_rc + +/******************************************************************************* + * Tuner callback + ******************************************************************************/ + +static int PLL_Set(struct drx397xD_state *s, + struct dvb_frontend_parameters *fep, int *df_tuner) +{ + struct dvb_frontend *fe = &s->frontend; + u32 f_tuner, f = fep->frequency; + int rc; + + pr_debug("%s\n", __FUNCTION__); + + if ((f > s->frontend.ops.tuner_ops.info.frequency_max) || + (f < s->frontend.ops.tuner_ops.info.frequency_min)) + return -EINVAL; + + *df_tuner = 0; + if (!s->frontend.ops.tuner_ops.set_params || + !s->frontend.ops.tuner_ops.get_frequency) + return -ENOSYS; + + rc = s->frontend.ops.tuner_ops.set_params(fe, fep); + if (rc < 0) + return rc; + + rc = s->frontend.ops.tuner_ops.get_frequency(fe, &f_tuner); + if (rc < 0) + return rc; + + *df_tuner = f_tuner - f; + pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __FUNCTION__, f, + f_tuner); + + return 0; +} + +/******************************************************************************* + * Demodulator helper functions + ******************************************************************************/ + +static int SC_WaitForReady(struct drx397xD_state *s) +{ + int cnt = 1000; + int rc; + + pr_debug("%s\n", __FUNCTION__); + + while (cnt--) { + rc = RD16(s, 0x820043); + if (rc == 0) + return 0; + } + return -1; +} + +static int SC_SendCommand(struct drx397xD_state *s, int cmd) +{ + int rc; + + pr_debug("%s\n", __FUNCTION__); + + WR16(s, 0x820043, cmd); + SC_WaitForReady(s); + rc = RD16(s, 0x820042); + if ((rc & 0xffff) == 0xffff) + return -1; + return 0; +} + +static int HI_Command(struct drx397xD_state *s, u16 cmd) +{ + int rc, cnt = 1000; + + pr_debug("%s\n", __FUNCTION__); + + rc = WR16(s, 0x420032, cmd); + if (rc < 0) + return rc; + + do { + rc = RD16(s, 0x420032); + if (rc == 0) { + rc = RD16(s, 0x420031); + return rc; + } + if (rc < 0) + return rc; + } while (--cnt); + return rc; +} + +static int HI_CfgCommand(struct drx397xD_state *s) +{ + + pr_debug("%s\n", __FUNCTION__); + + WR16(s, 0x420033, 0x3973); + WR16(s, 0x420034, s->config.w50); // code 4, log 4 + WR16(s, 0x420035, s->config.w52); // code 15, log 9 + WR16(s, 0x420036, s->config.demod_address << 1); + WR16(s, 0x420037, s->config.w56); // code (set_i2c ?? initX 1 ), log 1 +// WR16(s, 0x420033, 0x3973); + if ((s->config.w56 & 8) == 0) + return HI_Command(s, 3); + return WR16(s, 0x420032, 0x3); +} + +static const u8 fastIncrDecLUT_15273[] = { + 0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1d, 0x1f +}; + +static const u8 slowIncrDecLUT_15272[] = { + 3, 4, 4, 5, 6 +}; + +static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc) +{ + u16 w06 = agc->w06; + u16 w08 = agc->w08; + u16 w0A = agc->w0A; + u16 w0C = agc->w0C; + int quot, rem, i, rc = -EINVAL; + + pr_debug("%s\n", __FUNCTION__); + + if (agc->w04 > 0x3ff) + goto exit_rc; + + if (agc->d00 == 1) { + EXIT_RC(RD16(s, 0x0c20010)); + rc &= ~0x10; + EXIT_RC(WR16(s, 0x0c20010, rc)); + return WR16(s, 0x0c20030, agc->w04 & 0x7ff); + } + + if (agc->d00 != 0) + goto exit_rc; + if (w0A < w08) + goto exit_rc; + if (w0A > 0x3ff) + goto exit_rc; + if (w0C > 0x3ff) + goto exit_rc; + if (w06 > 0x3ff) + goto exit_rc; + + EXIT_RC(RD16(s, 0x0c20010)); + rc |= 0x10; + EXIT_RC(WR16(s, 0x0c20010, rc)); + + EXIT_RC(WR16(s, 0x0c20025, (w06 >> 1) & 0x1ff)); + EXIT_RC(WR16(s, 0x0c20031, (w0A - w08) >> 1)); + EXIT_RC(WR16(s, 0x0c20032, ((w0A + w08) >> 1) - 0x1ff)); + + quot = w0C / 113; + rem = w0C % 113; + if (quot <= 8) { + quot = 8 - quot; + } else { + quot = 0; + rem += 113; + } + + EXIT_RC(WR16(s, 0x0c20024, quot)); + + i = fastIncrDecLUT_15273[rem / 8]; + EXIT_RC(WR16(s, 0x0c2002d, i)); + EXIT_RC(WR16(s, 0x0c2002e, i)); + + i = slowIncrDecLUT_15272[rem / 28]; + EXIT_RC(WR16(s, 0x0c2002b, i)); + rc = WR16(s, 0x0c2002c, i); + exit_rc: + return rc; +} + +static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc) +{ + u16 w04 = agc->w04; + u16 w06 = agc->w06; + int rc = -1; + + pr_debug("%s %d 0x%x 0x%x\n", __FUNCTION__, agc->d00, w04, w06); + + if (w04 > 0x3ff) + goto exit_rc; + + switch (agc->d00) { + case 1: + if (w04 == 0x3ff) + w04 = 0x400; + + EXIT_RC(WR16(s, 0x0c20036, w04)); + s->config.w9C &= ~2; + EXIT_RC(WR16(s, 0x0c20015, s->config.w9C)); + EXIT_RC(RD16(s, 0x0c20010)); + rc &= 0xbfdf; + EXIT_RC(WR16(s, 0x0c20010, rc)); + EXIT_RC(RD16(s, 0x0c20013)); + rc &= ~2; + break; + case 0: + // loc_8000659 + s->config.w9C &= ~2; + EXIT_RC(WR16(s, 0x0c20015, s->config.w9C)); + EXIT_RC(RD16(s, 0x0c20010)); + rc &= 0xbfdf; + rc |= 0x4000; + EXIT_RC(WR16(s, 0x0c20010, rc)); + EXIT_RC(WR16(s, 0x0c20051, (w06 >> 4) & 0x3f)); + EXIT_RC(RD16(s, 0x0c20013)); + rc &= ~2; + break; + default: + s->config.w9C |= 2; + EXIT_RC(WR16(s, 0x0c20015, s->config.w9C)); + EXIT_RC(RD16(s, 0x0c20010)); + rc &= 0xbfdf; + EXIT_RC(WR16(s, 0x0c20010, rc)); + + EXIT_RC(WR16(s, 0x0c20036, 0)); + + EXIT_RC(RD16(s, 0x0c20013)); + rc |= 2; + } + rc = WR16(s, 0x0c20013, rc); + exit_rc: + return rc; +} + +static int GetLockStatus(struct drx397xD_state *s, int *lockstat) +{ + int rc; + + *lockstat = 0; + + rc = RD16(s, 0x082004b); + if (rc < 0) + return rc; + + if (s->config.d60 != 2) + return 0; + + if ((rc & 7) == 7) + *lockstat |= 1; + if ((rc & 3) == 3) + *lockstat |= 2; + if (rc & 1) + *lockstat |= 4; + return 0; +} + +static int CorrectSysClockDeviation(struct drx397xD_state *s) +{ + int rc = -EINVAL; + int lockstat; + u32 clk, clk_limit; + + pr_debug("%s\n", __FUNCTION__); + + if (s->config.d5C == 0) { + EXIT_RC(WR16(s, 0x08200e8, 0x010)); + EXIT_RC(WR16(s, 0x08200e9, 0x113)); + s->config.d5C = 1; + return rc; + } + if (s->config.d5C != 1) + goto exit_rc; + + rc = RD16(s, 0x0820048); + + rc = GetLockStatus(s, &lockstat); + if (rc < 0) + goto exit_rc; + if ((lockstat & 1) == 0) + goto exit_rc; + + EXIT_RC(WR16(s, 0x0420033, 0x200)); + EXIT_RC(WR16(s, 0x0420034, 0xc5)); + EXIT_RC(WR16(s, 0x0420035, 0x10)); + EXIT_RC(WR16(s, 0x0420036, 0x1)); + EXIT_RC(WR16(s, 0x0420037, 0xa)); + EXIT_RC(HI_Command(s, 6)); + EXIT_RC(RD16(s, 0x0420040)); + clk = rc; + EXIT_RC(RD16(s, 0x0420041)); + clk |= rc << 16; + + if (clk <= 0x26ffff) + goto exit_rc; + if (clk > 0x610000) + goto exit_rc; + + if (!s->bandwidth_parm) + return -EINVAL; + + /* round & convert to Hz */ + clk = ((u64) (clk + 0x800000) * s->bandwidth_parm + (1 << 20)) >> 21; + clk_limit = s->config.f_osc * MAX_CLOCK_DRIFT / 1000; + + if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) { + s->f_osc = clk; + pr_debug("%s: osc %d %d [Hz]\n", __FUNCTION__, + s->config.f_osc * 1000, clk - s->config.f_osc * 1000); + } + rc = WR16(s, 0x08200e8, 0); + exit_rc: + return rc; +} + +static int ConfigureMPEGOutput(struct drx397xD_state *s, int type) +{ + int rc, si, bp; + + pr_debug("%s\n", __FUNCTION__); + + si = s->config.wA0; + if (s->config.w98 == 0) { + si |= 1; + bp = 0; + } else { + si &= ~1; + bp = 0x200; + } + if (s->config.w9A == 0) { + si |= 0x80; + } else { + si &= ~0x80; + } + + EXIT_RC(WR16(s, 0x2150045, 0)); + EXIT_RC(WR16(s, 0x2150010, si)); + EXIT_RC(WR16(s, 0x2150011, bp)); + rc = WR16(s, 0x2150012, (type == 0 ? 0xfff : 0)); + exit_rc: + return rc; +} + +static int drx_tune(struct drx397xD_state *s, + struct dvb_frontend_parameters *fep) +{ + u16 v22 = 0; + u16 v1C = 0; + u16 v1A = 0; + u16 v18 = 0; + u32 edi = 0, ebx = 0, ebp = 0, edx = 0; + u16 v20 = 0, v1E = 0, v16 = 0, v14 = 0, v12 = 0, v10 = 0, v0E = 0; + + int rc, df_tuner; + int a, b, c, d; + pr_debug("%s %d\n", __FUNCTION__, s->config.d60); + + if (s->config.d60 != 2) + goto set_tuner; + rc = CorrectSysClockDeviation(s); + if (rc < 0) + goto set_tuner; + + s->config.d60 = 1; + rc = ConfigureMPEGOutput(s, 0); + if (rc < 0) + goto set_tuner; + set_tuner: + + rc = PLL_Set(s, fep, &df_tuner); + if (rc < 0) { + printk(KERN_ERR "Error in pll_set\n"); + goto exit_rc; + } + msleep(200); + + a = rc = RD16(s, 0x2150016); + if (rc < 0) + goto exit_rc; + b = rc = RD16(s, 0x2150010); + if (rc < 0) + goto exit_rc; + c = rc = RD16(s, 0x2150034); + if (rc < 0) + goto exit_rc; + d = rc = RD16(s, 0x2150035); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x2150014, c); + rc = WR16(s, 0x2150015, d); + rc = WR16(s, 0x2150010, 0); + rc = WR16(s, 0x2150000, 2); + rc = WR16(s, 0x2150036, 0x0fff); + rc = WR16(s, 0x2150016, a); + + rc = WR16(s, 0x2150010, 2); + rc = WR16(s, 0x2150007, 0); + rc = WR16(s, 0x2150000, 1); + rc = WR16(s, 0x2110000, 0); + rc = WR16(s, 0x0800000, 0); + rc = WR16(s, 0x2800000, 0); + rc = WR16(s, 0x2110010, 0x664); + + rc = write_fw(s, DRXD_ResetECRAM); + rc = WR16(s, 0x2110000, 1); + + rc = write_fw(s, DRXD_InitSC); + if (rc < 0) + goto exit_rc; + + rc = SetCfgIfAgc(s, &s->config.ifagc); + if (rc < 0) + goto exit_rc; + + rc = SetCfgRfAgc(s, &s->config.rfagc); + if (rc < 0) + goto exit_rc; + + if (fep->u.ofdm.transmission_mode != TRANSMISSION_MODE_2K) + v22 = 1; + switch (fep->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: + edi = 1; + if (s->chip_rev == DRXD_FW_B1) + break; + + rc = WR16(s, 0x2010010, 0); + if (rc < 0) + break; + v1C = 0x63; + v1A = 0x53; + v18 = 0x43; + break; + default: + edi = 0; + if (s->chip_rev == DRXD_FW_B1) + break; + + rc = WR16(s, 0x2010010, 1); + if (rc < 0) + break; + + v1C = 0x61; + v1A = 0x47; + v18 = 0x41; + } + + switch (fep->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_4: + edi |= 0x0c; + break; + case GUARD_INTERVAL_1_8: + edi |= 0x08; + break; + case GUARD_INTERVAL_1_16: + edi |= 0x04; + break; + case GUARD_INTERVAL_1_32: + break; + default: + v22 |= 2; + } + + ebx = 0; + ebp = 0; + v20 = 0; + v1E = 0; + v16 = 0; + v14 = 0; + v12 = 0; + v10 = 0; + v0E = 0; + + switch (fep->u.ofdm.hierarchy_information) { + case HIERARCHY_1: + edi |= 0x40; + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x1c10047, 1); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x2010012, 1); + if (rc < 0) + goto exit_rc; + ebx = 0x19f; + ebp = 0x1fb; + v20 = 0x0c0; + v1E = 0x195; + v16 = 0x1d6; + v14 = 0x1ef; + v12 = 4; + v10 = 5; + v0E = 5; + break; + case HIERARCHY_2: + edi |= 0x80; + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x1c10047, 2); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x2010012, 2); + if (rc < 0) + goto exit_rc; + ebx = 0x08f; + ebp = 0x12f; + v20 = 0x0c0; + v1E = 0x11e; + v16 = 0x1d6; + v14 = 0x15e; + v12 = 4; + v10 = 5; + v0E = 5; + break; + case HIERARCHY_4: + edi |= 0xc0; + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x1c10047, 3); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x2010012, 3); + if (rc < 0) + goto exit_rc; + ebx = 0x14d; + ebp = 0x197; + v20 = 0x0c0; + v1E = 0x1ce; + v16 = 0x1d6; + v14 = 0x11a; + v12 = 4; + v10 = 6; + v0E = 5; + break; + default: + v22 |= 8; + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x1c10047, 0); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x2010012, 0); + if (rc < 0) + goto exit_rc; + // QPSK QAM16 QAM64 + ebx = 0x19f; // 62 + ebp = 0x1fb; // 15 + v20 = 0x16a; // 62 + v1E = 0x195; // 62 + v16 = 0x1bb; // 15 + v14 = 0x1ef; // 15 + v12 = 5; // 16 + v10 = 5; // 16 + v0E = 5; // 16 + } + + switch (fep->u.ofdm.constellation) { + default: + v22 |= 4; + case QPSK: + if (s->chip_rev == DRXD_FW_B1) + break; + + rc = WR16(s, 0x1c10046, 0); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x2010011, 0); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001a, 0x10); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001b, 0); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001c, 0); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10062, v20); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c1002a, v1C); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10015, v16); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10016, v12); + if (rc < 0) + goto exit_rc; + break; + case QAM_16: + edi |= 0x10; + if (s->chip_rev == DRXD_FW_B1) + break; + + rc = WR16(s, 0x1c10046, 1); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x2010011, 1); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001a, 0x10); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001b, 4); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001c, 0); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10062, v1E); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c1002a, v1A); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10015, v14); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10016, v10); + if (rc < 0) + goto exit_rc; + break; + case QAM_64: + edi |= 0x20; + rc = WR16(s, 0x1c10046, 2); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x2010011, 2); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001a, 0x20); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001b, 8); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001c, 2); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10062, ebx); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c1002a, v18); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10015, ebp); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10016, v0E); + if (rc < 0) + goto exit_rc; + break; + } + + if (s->config.s20d24 == 1) { + rc = WR16(s, 0x2010013, 0); + } else { + rc = WR16(s, 0x2010013, 1); + edi |= 0x1000; + } + + switch (fep->u.ofdm.code_rate_HP) { + default: + v22 |= 0x10; + case FEC_1_2: + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x2090011, 0); + break; + case FEC_2_3: + edi |= 0x200; + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x2090011, 1); + break; + case FEC_3_4: + edi |= 0x400; + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x2090011, 2); + break; + case FEC_5_6: /* 5 */ + edi |= 0x600; + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x2090011, 3); + break; + case FEC_7_8: /* 7 */ + edi |= 0x800; + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x2090011, 4); + break; + }; + if (rc < 0) + goto exit_rc; + + switch (fep->u.ofdm.bandwidth) { + default: + rc = -EINVAL; + goto exit_rc; + case BANDWIDTH_8_MHZ: /* 0 */ + case BANDWIDTH_AUTO: + rc = WR16(s, 0x0c2003f, 0x32); + s->bandwidth_parm = ebx = 0x8b8249; // 9142857 + edx = 0; + break; + case BANDWIDTH_7_MHZ: + rc = WR16(s, 0x0c2003f, 0x3b); + s->bandwidth_parm = ebx = 0x7a1200; // 8000000 + edx = 0x4807; + break; + case BANDWIDTH_6_MHZ: + rc = WR16(s, 0x0c2003f, 0x47); + s->bandwidth_parm = ebx = 0x68a1b6; // 6857142 + edx = 0x0f07; + break; + }; + + if (rc < 0) + goto exit_rc; + + rc = WR16(s, 0x08200ec, edx); + if (rc < 0) + goto exit_rc; + + rc = RD16(s, 0x0820050); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x0820050, rc); + + { + /* Configure bandwidth specific factor */ + ebx = div64_u64(((u64) (s->f_osc) << 21) + (ebx >> 1), + (u64)ebx) - 0x800000; + EXIT_RC(WR16(s, 0x0c50010, ebx & 0xffff)); + EXIT_RC(WR16(s, 0x0c50011, ebx >> 16)); + + /* drx397xD oscillator calibration */ + ebx = div64_u64(((u64) (s->config.f_if + df_tuner) << 28) + + (s->f_osc >> 1), (u64)s->f_osc); + } + ebx &= 0xfffffff; + if (fep->inversion == INVERSION_ON) + ebx = 0x10000000 - ebx; + + EXIT_RC(WR16(s, 0x0c30010, ebx & 0xffff)); + EXIT_RC(WR16(s, 0x0c30011, ebx >> 16)); + + EXIT_RC(WR16(s, 0x0800000, 1)); + EXIT_RC(RD16(s, 0x0800000)); + + + EXIT_RC(SC_WaitForReady(s)); + EXIT_RC(WR16(s, 0x0820042, 0)); + EXIT_RC(WR16(s, 0x0820041, v22)); + EXIT_RC(WR16(s, 0x0820040, edi)); + EXIT_RC(SC_SendCommand(s, 3)); + + rc = RD16(s, 0x0800000); + + SC_WaitForReady(s); + WR16(s, 0x0820042, 0); + WR16(s, 0x0820041, 1); + WR16(s, 0x0820040, 1); + SC_SendCommand(s, 1); + +// rc = WR16(s, 0x2150000, 1); +// if (rc < 0) goto exit_rc; + + rc = WR16(s, 0x2150000, 2); + rc = WR16(s, 0x2150016, a); + rc = WR16(s, 0x2150010, 4); + rc = WR16(s, 0x2150036, 0); + rc = WR16(s, 0x2150000, 1); + s->config.d60 = 2; + exit_rc: + return rc; +} + +/******************************************************************************* + * DVB interface + ******************************************************************************/ + +static int drx397x_init(struct dvb_frontend *fe) +{ + struct drx397xD_state *s = fe->demodulator_priv; + int rc; + + pr_debug("%s\n", __FUNCTION__); + + s->config.rfagc.d00 = 2; /* 0x7c */ + s->config.rfagc.w04 = 0; + s->config.rfagc.w06 = 0x3ff; + + s->config.ifagc.d00 = 0; /* 0x68 */ + s->config.ifagc.w04 = 0; + s->config.ifagc.w06 = 140; + s->config.ifagc.w08 = 0; + s->config.ifagc.w0A = 0x3ff; + s->config.ifagc.w0C = 0x388; + + /* for signal strenght calculations */ + s->config.ss76 = 820; + s->config.ss78 = 2200; + s->config.ss7A = 150; + + /* HI_CfgCommand */ + s->config.w50 = 4; + s->config.w52 = 9; // 0xf; + + s->config.f_if = 42800000; /* d14: intermediate frequency [Hz] */ + s->config.f_osc = 48000; /* s66 : oscillator frequency [kHz] */ + s->config.w92 = 12000; // 20000; + + s->config.w9C = 0x000e; + s->config.w9E = 0x0000; + + /* ConfigureMPEGOutput params */ + s->config.wA0 = 4; + s->config.w98 = 1; // 0; + s->config.w9A = 1; + + /* get chip revision */ + rc = RD16(s, 0x2410019); + if (rc < 0) + return -ENODEV; + + if (rc == 0) { + printk(KERN_INFO "%s: chip revision A2\n", mod_name); + rc = drx_load_fw(s, DRXD_FW_A2); + } else { + + rc = (rc >> 12) - 3; + switch (rc) { + case 1: + s->flags |= F_SET_0D4h; + case 0: + case 4: + s->flags |= F_SET_0D0h; + break; + case 2: + case 5: + break; + case 3: + s->flags |= F_SET_0D4h; + break; + default: + return -ENODEV; + }; + printk(KERN_INFO "%s: chip revision B1.%d\n", mod_name, rc); + rc = drx_load_fw(s, DRXD_FW_B1); + } + if (rc < 0) + goto error; + + rc = WR16(s, 0x0420033, 0x3973); + if (rc < 0) + goto error; + + rc = HI_Command(s, 2); + + msleep(1); + + if (s->chip_rev == DRXD_FW_A2) { + rc = WR16(s, 0x043012d, 0x47F); + if (rc < 0) + goto error; + } + rc = WR16_E0(s, 0x0400000, 0); + if (rc < 0) + goto error; + + if (s->config.w92 > 20000 || s->config.w92 % 4000) { + printk(KERN_ERR "%s: invalid osc frequency\n", mod_name); + rc = -1; + goto error; + } + + rc = WR16(s, 0x2410010, 1); + if (rc < 0) + goto error; + rc = WR16(s, 0x2410011, 0x15); + if (rc < 0) + goto error; + rc = WR16(s, 0x2410012, s->config.w92 / 4000); + if (rc < 0) + goto error; +#ifdef ORIG_FW + rc = WR16(s, 0x2410015, 2); + if (rc < 0) + goto error; +#endif + rc = WR16(s, 0x2410017, 0x3973); + if (rc < 0) + goto error; + + s->f_osc = s->config.f_osc * 1000; /* initial estimator */ + + s->config.w56 = 1; + + rc = HI_CfgCommand(s); + if (rc < 0) + goto error; + + rc = write_fw(s, DRXD_InitAtomicRead); + if (rc < 0) + goto error; + + if (s->chip_rev == DRXD_FW_A2) { + rc = WR16(s, 0x2150013, 0); + if (rc < 0) + goto error; + } + + rc = WR16_E0(s, 0x0400002, 0); + if (rc < 0) + goto error; + rc = WR16(s, 0x0400002, 0); + if (rc < 0) + goto error; + + if (s->chip_rev == DRXD_FW_A2) { + rc = write_fw(s, DRXD_ResetCEFR); + if (rc < 0) + goto error; + } + rc = write_fw(s, DRXD_microcode); + if (rc < 0) + goto error; + + s->config.w9C = 0x0e; + if (s->flags & F_SET_0D0h) { + s->config.w9C = 0; + rc = RD16(s, 0x0c20010); + if (rc < 0) + goto write_DRXD_InitFE_1; + + rc &= ~0x1000; + rc = WR16(s, 0x0c20010, rc); + if (rc < 0) + goto write_DRXD_InitFE_1; + + rc = RD16(s, 0x0c20011); + if (rc < 0) + goto write_DRXD_InitFE_1; + + rc &= ~0x8; + rc = WR16(s, 0x0c20011, rc); + if (rc < 0) + goto write_DRXD_InitFE_1; + + rc = WR16(s, 0x0c20012, 1); + } + + write_DRXD_InitFE_1: + + rc = write_fw(s, DRXD_InitFE_1); + if (rc < 0) + goto error; + + rc = 1; + if (s->chip_rev == DRXD_FW_B1) { + if (s->flags & F_SET_0D0h) + rc = 0; + } else { + if (s->flags & F_SET_0D0h) + rc = 4; + } + + rc = WR16(s, 0x0C20012, rc); + if (rc < 0) + goto error; + + rc = WR16(s, 0x0C20013, s->config.w9E); + if (rc < 0) + goto error; + rc = WR16(s, 0x0C20015, s->config.w9C); + if (rc < 0) + goto error; + + rc = write_fw(s, DRXD_InitFE_2); + if (rc < 0) + goto error; + rc = write_fw(s, DRXD_InitFT); + if (rc < 0) + goto error; + rc = write_fw(s, DRXD_InitCP); + if (rc < 0) + goto error; + rc = write_fw(s, DRXD_InitCE); + if (rc < 0) + goto error; + rc = write_fw(s, DRXD_InitEQ); + if (rc < 0) + goto error; + rc = write_fw(s, DRXD_InitEC); + if (rc < 0) + goto error; + rc = write_fw(s, DRXD_InitSC); + if (rc < 0) + goto error; + + rc = SetCfgIfAgc(s, &s->config.ifagc); + if (rc < 0) + goto error; + + rc = SetCfgRfAgc(s, &s->config.rfagc); + if (rc < 0) + goto error; + + rc = ConfigureMPEGOutput(s, 1); + rc = WR16(s, 0x08201fe, 0x0017); + rc = WR16(s, 0x08201ff, 0x0101); + + s->config.d5C = 0; + s->config.d60 = 1; + s->config.d48 = 1; + error: + return rc; +} + +static int drx397x_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + return 0; +} + +static int drx397x_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct drx397xD_state *s = fe->demodulator_priv; + + s->config.s20d24 = 1; // 0; + return drx_tune(s, params); +} + +static int drx397x_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings + *fe_tune_settings) +{ + fe_tune_settings->min_delay_ms = 10000; + fe_tune_settings->step_size = 0; + fe_tune_settings->max_drift = 0; + return 0; +} + +static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status) +{ + struct drx397xD_state *s = fe->demodulator_priv; + int lockstat; + + GetLockStatus(s, &lockstat); + /* TODO */ +// if (lockstat & 1) +// CorrectSysClockDeviation(s); + + *status = 0; + if (lockstat & 2) { + CorrectSysClockDeviation(s); + ConfigureMPEGOutput(s, 1); + *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI; + } + if (lockstat & 4) { + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + } + + return 0; +} + +static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber) +{ + *ber = 0; + return 0; +} + +static int drx397x_read_snr(struct dvb_frontend *fe, u16 * snr) +{ + *snr = 0; + return 0; +} + +static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 * strength) +{ + struct drx397xD_state *s = fe->demodulator_priv; + int rc; + + if (s->config.ifagc.d00 == 2) { + *strength = 0xffff; + return 0; + } + rc = RD16(s, 0x0c20035); + if (rc < 0) { + *strength = 0; + return 0; + } + rc &= 0x3ff; + /* Signal strength is calculated using the following formula: + * + * a = 2200 * 150 / (2200 + 150); + * a = a * 3300 / (a + 820); + * b = 2200 * 3300 / (2200 + 820); + * c = (((b-a) * rc) >> 10 + a) << 4; + * strength = ~c & 0xffff; + * + * The following does the same but with less rounding errors: + */ + *strength = ~(7720 + (rc * 30744 >> 10)); + return 0; +} + +static int drx397x_read_ucblocks(struct dvb_frontend *fe, + unsigned int *ucblocks) +{ + *ucblocks = 0; + return 0; +} + +static int drx397x_sleep(struct dvb_frontend *fe) +{ + return 0; +} + +static void drx397x_release(struct dvb_frontend *fe) +{ + struct drx397xD_state *s = fe->demodulator_priv; + printk(KERN_INFO "%s: release demodulator\n", mod_name); + if (s) { + drx_release_fw(s); + kfree(s); + } + +} + +static struct dvb_frontend_ops drx397x_ops = { + + .info = { + .name = "Micronas DRX397xD DVB-T Frontend", + .type = FE_OFDM, + .frequency_min = 47125000, + .frequency_max = 855250000, + .frequency_stepsize = 166667, + .frequency_tolerance = 0, + .caps = /* 0x0C01B2EAE */ + FE_CAN_FEC_1_2 | // = 0x2, + FE_CAN_FEC_2_3 | // = 0x4, + FE_CAN_FEC_3_4 | // = 0x8, + FE_CAN_FEC_5_6 | // = 0x20, + FE_CAN_FEC_7_8 | // = 0x80, + FE_CAN_FEC_AUTO | // = 0x200, + FE_CAN_QPSK | // = 0x400, + FE_CAN_QAM_16 | // = 0x800, + FE_CAN_QAM_64 | // = 0x2000, + FE_CAN_QAM_AUTO | // = 0x10000, + FE_CAN_TRANSMISSION_MODE_AUTO | // = 0x20000, + FE_CAN_GUARD_INTERVAL_AUTO | // = 0x80000, + FE_CAN_HIERARCHY_AUTO | // = 0x100000, + FE_CAN_RECOVER | // = 0x40000000, + FE_CAN_MUTE_TS // = 0x80000000 + }, + + .release = drx397x_release, + .init = drx397x_init, + .sleep = drx397x_sleep, + + .set_frontend = drx397x_set_frontend, + .get_tune_settings = drx397x_get_tune_settings, + .get_frontend = drx397x_get_frontend, + + .read_status = drx397x_read_status, + .read_snr = drx397x_read_snr, + .read_signal_strength = drx397x_read_signal_strength, + .read_ber = drx397x_read_ber, + .read_ucblocks = drx397x_read_ucblocks, +}; + +struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config, + struct i2c_adapter *i2c) +{ + struct drx397xD_state *s = NULL; + + /* allocate memory for the internal state */ + s = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL); + if (s == NULL) + goto error; + + /* setup the state */ + s->i2c = i2c; + memcpy(&s->config, config, sizeof(struct drx397xD_config)); + + /* check if the demod is there */ + if (RD16(s, 0x2410019) < 0) + goto error; + + /* create dvb_frontend */ + memcpy(&s->frontend.ops, &drx397x_ops, sizeof(struct dvb_frontend_ops)); + s->frontend.demodulator_priv = s; + + return &s->frontend; + error: + kfree(s); + return NULL; +} + +MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend"); +MODULE_AUTHOR("Henk Vergonet"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(drx397xD_attach); diff --git a/drivers/media/dvb/frontends/drx397xD.h b/drivers/media/dvb/frontends/drx397xD.h new file mode 100644 index 000000000000..ddc7a07971b7 --- /dev/null +++ b/drivers/media/dvb/frontends/drx397xD.h @@ -0,0 +1,130 @@ +/* + * Driver for Micronas DVB-T drx397xD demodulator + * + * Copyright (C) 2007 Henk vergonet <Henk.Vergonet@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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 _DRX397XD_H_INCLUDED +#define _DRX397XD_H_INCLUDED + +#include <linux/dvb/frontend.h> + +#define DRX_F_STEPSIZE 166667 +#define DRX_F_OFFSET 36000000 + +#define I2C_ADR_C0(x) \ +( (u32)cpu_to_le32( \ + (u32)( \ + (((u32)(x) & (u32)0x000000ffUL) ) | \ + (((u32)(x) & (u32)0x0000ff00UL) << 16) | \ + (((u32)(x) & (u32)0x0fff0000UL) >> 8) | \ + ( (u32)0x00c00000UL) \ + )) \ +) + +#define I2C_ADR_E0(x) \ +( (u32)cpu_to_le32( \ + (u32)( \ + (((u32)(x) & (u32)0x000000ffUL) ) | \ + (((u32)(x) & (u32)0x0000ff00UL) << 16) | \ + (((u32)(x) & (u32)0x0fff0000UL) >> 8) | \ + ( (u32)0x00e00000UL) \ + )) \ +) + +struct drx397xD_CfgRfAgc /* 0x7c */ +{ + int d00; /* 2 */ + u16 w04; + u16 w06; +}; + +struct drx397xD_CfgIfAgc /* 0x68 */ +{ + int d00; /* 0 */ + u16 w04; /* 0 */ + u16 w06; + u16 w08; + u16 w0A; + u16 w0C; +}; + +struct drx397xD_s20 { + int d04; + u32 d18; + u32 d1C; + u32 d20; + u32 d14; + u32 d24; + u32 d0C; + u32 d08; +}; + +struct drx397xD_config +{ + /* demodulator's I2C address */ + u8 demod_address; /* 0x0f */ + + struct drx397xD_CfgIfAgc ifagc; /* 0x68 */ + struct drx397xD_CfgRfAgc rfagc; /* 0x7c */ + u32 s20d24; + + /* HI_CfgCommand parameters */ + u16 w50, w52, /* w54, */ w56; + + int d5C; + int d60; + int d48; + int d28; + + u32 f_if; /* d14: intermediate frequency [Hz] */ + /* 36000000 on Cinergy 2400i DT */ + /* 42800000 on Pinnacle Hybrid PRO 330e */ + + u16 f_osc; /* s66: 48000 oscillator frequency [kHz] */ + + u16 w92; /* 20000 */ + + u16 wA0; + u16 w98; + u16 w9A; + + u16 w9C; /* 0xe0 */ + u16 w9E; /* 0x00 */ + + /* used for signal strength calculations in + drx397x_read_signal_strength + */ + u16 ss78; // 2200 + u16 ss7A; // 150 + u16 ss76; // 820 +}; + +#if defined(CONFIG_DVB_DRX397XD) || (defined(CONFIG_DVB_DRX397XD_MODULE) && defined(MODULE)) +extern struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif /* CONFIG_DVB_DRX397XD */ + +#endif /* _DRX397XD_H_INCLUDED */ diff --git a/drivers/media/dvb/frontends/drx397xD_fw.h b/drivers/media/dvb/frontends/drx397xD_fw.h new file mode 100644 index 000000000000..01de02a81cd4 --- /dev/null +++ b/drivers/media/dvb/frontends/drx397xD_fw.h @@ -0,0 +1,40 @@ +/* + * Firmware definitions for Micronas drx397xD + * + * Copyright (C) 2007 Henk Vergonet <Henk.Vergonet@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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, see <http://www.gnu.org/licenses/>. + */ + +#ifdef _FW_ENTRY + _FW_ENTRY("drx397xD.A2.fw", DRXD_FW_A2 = 0 ), + _FW_ENTRY("drx397xD.B1.fw", DRXD_FW_B1 ), +#undef _FW_ENTRY +#endif /* _FW_ENTRY */ + +#ifdef _BLOB_ENTRY + _BLOB_ENTRY("InitAtomicRead", DRXD_InitAtomicRead = 0 ), + _BLOB_ENTRY("InitCE", DRXD_InitCE ), + _BLOB_ENTRY("InitCP", DRXD_InitCP ), + _BLOB_ENTRY("InitEC", DRXD_InitEC ), + _BLOB_ENTRY("InitEQ", DRXD_InitEQ ), + _BLOB_ENTRY("InitFE_1", DRXD_InitFE_1 ), + _BLOB_ENTRY("InitFE_2", DRXD_InitFE_2 ), + _BLOB_ENTRY("InitFT", DRXD_InitFT ), + _BLOB_ENTRY("InitSC", DRXD_InitSC ), + _BLOB_ENTRY("ResetCEFR", DRXD_ResetCEFR ), + _BLOB_ENTRY("ResetECRAM", DRXD_ResetECRAM ), + _BLOB_ENTRY("microcode", DRXD_microcode ), +#undef _BLOB_ENTRY +#endif /* _BLOB_ENTRY */ diff --git a/drivers/media/dvb/frontends/itd1000.c b/drivers/media/dvb/frontends/itd1000.c index 04c562ccf990..600dad6b41ea 100644 --- a/drivers/media/dvb/frontends/itd1000.c +++ b/drivers/media/dvb/frontends/itd1000.c @@ -195,7 +195,7 @@ static void itd1000_set_vco(struct itd1000_state *state, u32 freq_khz) } } -struct { +static const struct { u32 freq; u8 values[10]; /* RFTR, RFST1 - RFST9 */ } itd1000_fre_values[] = { diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index 081ca3398c76..5ac9b15920f8 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -737,7 +737,7 @@ static void mt312_release(struct dvb_frontend *fe) } #define MT312_SYS_CLK 90000000UL /* 90 MHz */ -static struct dvb_frontend_ops vp310_mt312_ops = { +static struct dvb_frontend_ops mt312_ops = { .info = { .name = "Zarlink ???? DVB-S", @@ -776,7 +776,7 @@ static struct dvb_frontend_ops vp310_mt312_ops = { .set_voltage = mt312_set_voltage, }; -struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config, +struct dvb_frontend *mt312_attach(const struct mt312_config *config, struct i2c_adapter *i2c) { struct mt312_state *state = NULL; @@ -795,7 +795,7 @@ struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config, goto error; /* create dvb_frontend */ - memcpy(&state->frontend.ops, &vp310_mt312_ops, + memcpy(&state->frontend.ops, &mt312_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; @@ -827,12 +827,13 @@ error: kfree(state); return NULL; } -EXPORT_SYMBOL(vp310_mt312_attach); +EXPORT_SYMBOL(mt312_attach); module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); MODULE_DESCRIPTION("Zarlink VP310/MT312/ZL10313 DVB-S Demodulator driver"); MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>"); +MODULE_AUTHOR("Matthias Schwarzott <zzam@gentoo.org>"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h index de796eab3911..29e3bb5496b8 100644 --- a/drivers/media/dvb/frontends/mt312.h +++ b/drivers/media/dvb/frontends/mt312.h @@ -37,10 +37,10 @@ struct mt312_config { }; #if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE)) -struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config, +struct dvb_frontend *mt312_attach(const struct mt312_config *config, struct i2c_adapter *i2c); #else -static inline struct dvb_frontend *vp310_mt312_attach( +static inline struct dvb_frontend *mt312_attach( const struct mt312_config *config, struct i2c_adapter *i2c) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index ae882432dd3d..d4339b1b3b68 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -5,6 +5,7 @@ config TTPCI_EEPROM config DVB_AV7110 tristate "AV7110 cards" depends on DVB_CORE && PCI && I2C + depends on HOTPLUG select FW_LOADER if !DVB_AV7110_FIRMWARE select TTPCI_EEPROM select VIDEO_SAA7146_VV @@ -123,6 +124,7 @@ config DVB_BUDGET_AV depends on DVB_BUDGET_CORE && I2C select VIDEO_SAA7146_VV depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV + depends on HOTPLUG # dependency of FW_LOADER select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE diff --git a/drivers/media/dvb/ttusb-dec/Kconfig b/drivers/media/dvb/ttusb-dec/Kconfig index 83611012ef34..0712899e39a4 100644 --- a/drivers/media/dvb/ttusb-dec/Kconfig +++ b/drivers/media/dvb/ttusb-dec/Kconfig @@ -1,6 +1,7 @@ config DVB_TTUSB_DEC tristate "Technotrend/Hauppauge USB DEC devices" depends on DVB_CORE && USB + depends on HOTPLUG # due to FW_LOADER select FW_LOADER select CRC32 help diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index fe743aa7f645..89d8d37838a3 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -44,6 +44,10 @@ config VIDEO_TVEEPROM tristate depends on I2C +config VIDEO_TUNER + tristate + depends on MEDIA_TUNER + # # Multimedia Video device configuration # @@ -690,7 +694,7 @@ config VIDEO_MXB tristate "Siemens-Nixdorf 'Multimedia eXtension Board'" depends on PCI && VIDEO_V4L1 && I2C select VIDEO_SAA7146_VV - select MEDIA_TUNER + select VIDEO_TUNER select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO @@ -906,7 +910,7 @@ config SOC_CAMERA config SOC_CAMERA_MT9M001 tristate "mt9m001 support" - depends on SOC_CAMERA + depends on SOC_CAMERA && I2C select GPIO_PCA953X if MT9M001_PCA9536_SWITCH help This driver supports MT9M001 cameras from Micron, monochrome @@ -921,7 +925,7 @@ config MT9M001_PCA9536_SWITCH config SOC_CAMERA_MT9V022 tristate "mt9v022 support" - depends on SOC_CAMERA + depends on SOC_CAMERA && I2C select GPIO_PCA953X if MT9V022_PCA9536_SWITCH help This driver supports MT9V022 cameras from Micron diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index a352c6e31f0c..dff0d6abe917 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -84,7 +84,7 @@ obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o obj-$(CONFIG_VIDEO_DPC) += dpc7146.o obj-$(CONFIG_TUNER_3036) += tuner-3036.o -obj-$(CONFIG_MEDIA_TUNER) += tuner.o +obj-$(CONFIG_VIDEO_TUNER) += tuner.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig index cab277fafa63..def10d086373 100644 --- a/drivers/media/video/au0828/Kconfig +++ b/drivers/media/video/au0828/Kconfig @@ -1,8 +1,9 @@ config VIDEO_AU0828 tristate "Auvitek AU0828 support" - depends on VIDEO_DEV && I2C && INPUT && DVB_CORE + depends on VIDEO_DEV && I2C && INPUT && DVB_CORE && USB select I2C_ALGOBIT + select VIDEO_TVEEPROM select DVB_AU8522 if !DVB_FE_CUSTOMIZE select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE ---help--- diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig index 7431ef6de9f1..24a34fc1f2b3 100644 --- a/drivers/media/video/bt8xx/Kconfig +++ b/drivers/media/video/bt8xx/Kconfig @@ -1,12 +1,13 @@ config VIDEO_BT848 tristate "BT848 Video For Linux" depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 && INPUT + depends on HOTPLUG # due to FW_LOADER select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX select VIDEOBUF_DMA_SG select VIDEO_IR - select MEDIA_TUNER + select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig index acc4b47f1d1d..5f942690570c 100644 --- a/drivers/media/video/cx18/Kconfig +++ b/drivers/media/video/cx18/Kconfig @@ -1,14 +1,17 @@ config VIDEO_CX18 tristate "Conexant cx23418 MPEG encoder support" depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL + depends on INPUT # due to VIDEO_IR + depends on HOTPLUG # due to FW_LOADER select I2C_ALGOBIT select FW_LOADER select VIDEO_IR - select MEDIA_TUNER + select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X select VIDEO_CS5345 select DVB_S5H1409 + select MEDIA_TUNER_MXL5005S ---help--- This is a video4linux driver for Conexant cx23418 based PCI combo video recorder devices. diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c index f5e3ba1f5354..bf6f7edca887 100644 --- a/drivers/media/video/cx18/cx18-cards.c +++ b/drivers/media/video/cx18/cx18-cards.c @@ -51,7 +51,8 @@ static const struct cx18_card cx18_card_hvr1600_esmt = { .v4l2_capabilities = CX18_CAP_ENCODER, .hw_audio_ctrl = CX18_HW_CX23418, .hw_muxer = CX18_HW_CS5345, - .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER | CX18_HW_CS5345, + .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER | CX18_HW_CS5345 + | CX18_HW_DVB, .video_inputs = { { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 }, { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 }, diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 3f55d47bc4b9..3e9979eff3e0 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -164,16 +164,6 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(CX18_VERSION); -int cx18_waitq(wait_queue_head_t *waitq) -{ - DEFINE_WAIT(wait); - - prepare_to_wait(waitq, &wait, TASK_INTERRUPTIBLE); - schedule(); - finish_wait(waitq, &wait); - return signal_pending(current) ? -EINTR : 0; -} - /* Generic utility functions */ int cx18_msleep_timeout(unsigned int msecs, int intr) { @@ -548,6 +538,7 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev, return 0; } +#ifdef MODULE static u32 cx18_request_module(struct cx18 *cx, u32 hw, const char *name, u32 id) { @@ -560,12 +551,14 @@ static u32 cx18_request_module(struct cx18 *cx, u32 hw, CX18_DEBUG_INFO("Loaded module %s\n", name); return hw; } +#endif static void cx18_load_and_init_modules(struct cx18 *cx) { u32 hw = cx->card->hw_all; int i; +#ifdef MODULE /* load modules */ #ifndef CONFIG_MEDIA_TUNER hw = cx18_request_module(cx, hw, "tuner", CX18_HW_TUNER); @@ -573,6 +566,7 @@ static void cx18_load_and_init_modules(struct cx18 *cx) #ifndef CONFIG_VIDEO_CS5345 hw = cx18_request_module(cx, hw, "cs5345", CX18_HW_CS5345); #endif +#endif /* check which i2c devices are actually found */ for (i = 0; i < 32; i++) { @@ -801,7 +795,7 @@ static int __devinit cx18_probe(struct pci_dev *dev, return 0; free_streams: - cx18_streams_cleanup(cx); + cx18_streams_cleanup(cx, 1); free_irq: free_irq(cx->dev->irq, (void *)cx); free_i2c: @@ -904,7 +898,7 @@ static void cx18_remove(struct pci_dev *pci_dev) cx18_halt_firmware(cx); - cx18_streams_cleanup(cx); + cx18_streams_cleanup(cx, 1); exit_cx18_i2c(cx); diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index 2ee939193bb7..a2a6c58d12fe 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h @@ -444,9 +444,6 @@ extern spinlock_t cx18_cards_lock; /* Return non-zero if a signal is pending */ int cx18_msleep_timeout(unsigned int msecs, int intr); -/* Wait on queue, returns -EINTR if interrupted */ -int cx18_waitq(wait_queue_head_t *waitq); - /* Read Hauppauge eeprom */ struct tveeprom; /* forward reference */ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv); diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c index 65efe69d939a..c9744173f969 100644 --- a/drivers/media/video/cx18/cx18-dvb.c +++ b/drivers/media/video/cx18/cx18-dvb.c @@ -24,25 +24,27 @@ #include "cx18-streams.h" #include "cx18-cards.h" #include "s5h1409.h" - -/* Wait until the MXL500X driver is merged */ -#ifdef HAVE_MXL500X -#include "mxl500x.h" -#endif +#include "mxl5005s.h" DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); #define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000 -#ifdef HAVE_MXL500X -static struct mxl500x_config hauppauge_hvr1600_tuner = { - .delsys = MXL500x_MODE_ATSC, - .octf = MXL500x_OCTF_CH, - .xtal_freq = 16000000, - .iflo_freq = 5380000, - .ref_freq = 322800000, - .rssi_ena = MXL_RSSI_ENABLE, - .addr = 0xC6 >> 1, +static struct mxl5005s_config hauppauge_hvr1600_tuner = { + .i2c_address = 0xC6 >> 1, + .if_freq = IF_FREQ_5380000HZ, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_C_H, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, }; static struct s5h1409_config hauppauge_hvr1600_config = { @@ -55,7 +57,6 @@ static struct s5h1409_config hauppauge_hvr1600_config = { .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK }; -#endif static int dvb_register(struct cx18_stream *stream); @@ -252,21 +253,18 @@ static int dvb_register(struct cx18_stream *stream) int ret = 0; switch (cx->card->type) { -/* Wait until the MXL500X driver is merged */ -#ifdef HAVE_MXL500X case CX18_CARD_HVR_1600_ESMT: case CX18_CARD_HVR_1600_SAMSUNG: dvb->fe = dvb_attach(s5h1409_attach, &hauppauge_hvr1600_config, &cx->i2c_adap[0]); if (dvb->fe != NULL) { - dvb_attach(mxl500x_attach, dvb->fe, - &hauppauge_hvr1600_tuner, - &cx->i2c_adap[0]); + dvb_attach(mxl5005s_attach, dvb->fe, + &cx->i2c_adap[0], + &hauppauge_hvr1600_tuner); ret = 0; } break; -#endif default: /* No Digital Tv Support */ break; diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index 69303065a294..91eff6e671a7 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c @@ -39,7 +39,7 @@ associated VBI streams are also automatically claimed. Possible error returns: -EBUSY if someone else has claimed the stream or 0 on success. */ -int cx18_claim_stream(struct cx18_open_id *id, int type) +static int cx18_claim_stream(struct cx18_open_id *id, int type) { struct cx18 *cx = id->cx; struct cx18_stream *s = &cx->streams[type]; @@ -87,7 +87,7 @@ int cx18_claim_stream(struct cx18_open_id *id, int type) /* This function releases a previously claimed stream. It will take into account associated VBI streams. */ -void cx18_release_stream(struct cx18_stream *s) +static void cx18_release_stream(struct cx18_stream *s) { struct cx18 *cx = s->cx; struct cx18_stream *s_vbi; diff --git a/drivers/media/video/cx18/cx18-fileops.h b/drivers/media/video/cx18/cx18-fileops.h index 16cdafbd24c5..46da0282fc7d 100644 --- a/drivers/media/video/cx18/cx18-fileops.h +++ b/drivers/media/video/cx18/cx18-fileops.h @@ -34,12 +34,3 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end); void cx18_mute(struct cx18 *cx); void cx18_unmute(struct cx18 *cx); -/* Utilities */ - -/* Try to claim a stream for the filehandle. Return 0 on success, - -EBUSY if stream already claimed. Once a stream is claimed, it - remains claimed until the associated filehandle is closed. */ -int cx18_claim_stream(struct cx18_open_id *id, int type); - -/* Release a previously claimed stream. */ -void cx18_release_stream(struct cx18_stream *s); diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c index 18c88d1e4833..4f08a4058d1a 100644 --- a/drivers/media/video/cx18/cx18-i2c.c +++ b/drivers/media/video/cx18/cx18-i2c.c @@ -25,6 +25,7 @@ #include "cx18-cards.h" #include "cx18-gpio.h" #include "cx18-av-core.h" +#include "cx18-i2c.h" #include <media/ir-kbd-i2c.h> diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c index 65af1bb507ca..6990b77c6200 100644 --- a/drivers/media/video/cx18/cx18-queue.c +++ b/drivers/media/video/cx18/cx18-queue.c @@ -26,17 +26,6 @@ #include "cx18-queue.h" #include "cx18-scb.h" -int cx18_buf_copy_from_user(struct cx18_stream *s, struct cx18_buffer *buf, - const char __user *src, int copybytes) -{ - if (s->buf_size - buf->bytesused < copybytes) - copybytes = s->buf_size - buf->bytesused; - if (copy_from_user(buf->buf + buf->bytesused, src, copybytes)) - return -EFAULT; - buf->bytesused += copybytes; - return copybytes; -} - void cx18_buf_swap(struct cx18_buffer *buf) { int i; @@ -159,8 +148,9 @@ static void cx18_queue_move_buf(struct cx18_stream *s, struct cx18_queue *from, -ENOMEM is returned if the buffers could not be obtained, 0 if all buffers where obtained from the 'from' list and if non-zero then the number of stolen buffers is returned. */ -int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from, - struct cx18_queue *steal, struct cx18_queue *to, int needed_bytes) +static int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from, + struct cx18_queue *steal, struct cx18_queue *to, + int needed_bytes) { unsigned long flags; int rc = 0; @@ -239,12 +229,12 @@ int cx18_stream_alloc(struct cx18_stream *s) /* allocate stream buffers. Initially all buffers are in q_free. */ for (i = 0; i < s->buffers; i++) { - struct cx18_buffer *buf = - kzalloc(sizeof(struct cx18_buffer), GFP_KERNEL); + struct cx18_buffer *buf = kzalloc(sizeof(struct cx18_buffer), + GFP_KERNEL|__GFP_NOWARN); if (buf == NULL) break; - buf->buf = kmalloc(s->buf_size, GFP_KERNEL); + buf->buf = kmalloc(s->buf_size, GFP_KERNEL|__GFP_NOWARN); if (buf->buf == NULL) { kfree(buf); break; diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h index f86c8a6fa6e7..91423b9863a4 100644 --- a/drivers/media/video/cx18/cx18-queue.h +++ b/drivers/media/video/cx18/cx18-queue.h @@ -39,8 +39,6 @@ static inline void cx18_buf_sync_for_device(struct cx18_stream *s, s->buf_size, s->dma); } -int cx18_buf_copy_from_user(struct cx18_stream *s, struct cx18_buffer *buf, - const char __user *src, int copybytes); void cx18_buf_swap(struct cx18_buffer *buf); /* cx18_queue utility functions */ @@ -48,8 +46,6 @@ void cx18_queue_init(struct cx18_queue *q); void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, struct cx18_queue *q); struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q); -int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from, - struct cx18_queue *steal, struct cx18_queue *to, int needed_bytes); struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id, u32 bytesused); void cx18_flush_queues(struct cx18_stream *s); diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index afb141b2027a..4ca9d847f1b1 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -218,7 +218,7 @@ int cx18_streams_setup(struct cx18 *cx) return 0; /* One or more streams could not be initialized. Clean 'em all up. */ - cx18_streams_cleanup(cx); + cx18_streams_cleanup(cx, 0); return -ENOMEM; } @@ -296,12 +296,12 @@ int cx18_streams_register(struct cx18 *cx) return 0; /* One or more streams could not be initialized. Clean 'em all up. */ - cx18_streams_cleanup(cx); + cx18_streams_cleanup(cx, 1); return -ENOMEM; } /* Unregister v4l2 devices */ -void cx18_streams_cleanup(struct cx18 *cx) +void cx18_streams_cleanup(struct cx18 *cx, int unregister) { struct video_device *vdev; int type; @@ -319,8 +319,11 @@ void cx18_streams_cleanup(struct cx18 *cx) cx18_stream_free(&cx->streams[type]); - /* Unregister device */ - video_unregister_device(vdev); + /* Unregister or release device */ + if (unregister) + video_unregister_device(vdev); + else + video_device_release(vdev); } } diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h index 8c7ba7d2fa79..f327e947b24f 100644 --- a/drivers/media/video/cx18/cx18-streams.h +++ b/drivers/media/video/cx18/cx18-streams.h @@ -24,7 +24,7 @@ u32 cx18_find_handle(struct cx18 *cx); int cx18_streams_setup(struct cx18 *cx); int cx18_streams_register(struct cx18 *cx); -void cx18_streams_cleanup(struct cx18 *cx); +void cx18_streams_cleanup(struct cx18 *cx, int unregister); /* Capture related */ int cx18_start_v4l2_encode_stream(struct cx18_stream *s); diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index cadf936c3673..7bf14c9a15c7 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -1,18 +1,20 @@ config VIDEO_CX23885 tristate "Conexant cx23885 (2388x successor) support" depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT + depends on HOTPLUG # due to FW_LOADER select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select MEDIA_TUNER + select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR select VIDEOBUF_DVB select VIDEO_CX25840 + select VIDEO_CX2341X + select DVB_DIB7000P if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MT2131 if !DVB_FE_CUSTOMISE select DVB_S5H1409 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_PLL if !DVB_FE_CUSTOMISE select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 6ebf58724a01..20e05f230546 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -200,6 +200,10 @@ struct cx23885_subid cx23885_subids[] = { .card = CX23885_BOARD_HAUPPAUGE_HVR1200, }, { .subvendor = 0x0070, + .subdevice = 0x71d3, + .card = CX23885_BOARD_HAUPPAUGE_HVR1200, + }, { + .subvendor = 0x0070, .subdevice = 0x8101, .card = CX23885_BOARD_HAUPPAUGE_HVR1700, }, { @@ -245,6 +249,33 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) /* Make sure we support the board model */ switch (tv.model) { + case 71009: + /* WinTV-HVR1200 (PCIe, Retail, full height) + * DVB-T and basic analog */ + case 71359: + /* WinTV-HVR1200 (PCIe, OEM, half height) + * DVB-T and basic analog */ + case 71439: + /* WinTV-HVR1200 (PCIe, OEM, half height) + * DVB-T and basic analog */ + case 71449: + /* WinTV-HVR1200 (PCIe, OEM, full height) + * DVB-T and basic analog */ + case 71939: + /* WinTV-HVR1200 (PCIe, OEM, half height) + * DVB-T and basic analog */ + case 71949: + /* WinTV-HVR1200 (PCIe, OEM, full height) + * DVB-T and basic analog */ + case 71959: + /* WinTV-HVR1200 (PCIe, OEM, full height) + * DVB-T and basic analog */ + case 71979: + /* WinTV-HVR1200 (PCIe, OEM, half height) + * DVB-T and basic analog */ + case 71999: + /* WinTV-HVR1200 (PCIe, OEM, full height) + * DVB-T and basic analog */ case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */ case 77001: /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC and Basic analog */ case 77011: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */ @@ -263,8 +294,11 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) case 80019: /* WinTV-HVR1400 (Express Card, Retail, IR, * DVB-T and Basic analog */ + case 81509: + /* WinTV-HVR1700 (PCIe, OEM, No IR, half height) + * DVB-T and MPEG2 HW Encoder */ case 81519: - /* WinTV-HVR1700 (PCIe, Retail, No IR, half height, + /* WinTV-HVR1700 (PCIe, OEM, No IR, full height) * DVB-T and MPEG2 HW Encoder */ break; default: diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index f05649727b60..47e3f9e035f9 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -37,7 +37,6 @@ #include "lgdt330x.h" #include "xc5000.h" #include "tda10048.h" -#include "dvb-pll.h" #include "tuner-xc2028.h" #include "tuner-simple.h" #include "dib7000p.h" diff --git a/drivers/media/video/cx25840/Kconfig b/drivers/media/video/cx25840/Kconfig index 7cf29a03ed63..448f4cd0ce34 100644 --- a/drivers/media/video/cx25840/Kconfig +++ b/drivers/media/video/cx25840/Kconfig @@ -1,6 +1,7 @@ config VIDEO_CX25840 tristate "Conexant CX2584x audio/video decoders" depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on HOTPLUG # due to FW_LOADER select FW_LOADER ---help--- Support for the Conexant CX2584x audio/video decoders. diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index b0d7d6a7a4cc..10e20d8196dc 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -2,10 +2,9 @@ config VIDEO_CX88 tristate "Conexant 2388x (bt878 successor) support" depends on VIDEO_DEV && PCI && I2C && INPUT select I2C_ALGOBIT - select FW_LOADER select VIDEO_BTCX select VIDEOBUF_DMA_SG - select MEDIA_TUNER + select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO @@ -34,8 +33,9 @@ config VIDEO_CX88_ALSA config VIDEO_CX88_BLACKBIRD tristate "Blackbird MPEG encoder support (cx2388x + cx23416)" - depends on VIDEO_CX88 + depends on VIDEO_CX88 && HOTPLUG select VIDEO_CX2341X + select FW_LOADER ---help--- This adds support for MPEG encoder cards based on the Blackbird reference design, using the Conexant 2388x diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 1c7fe6862a60..75e2e58349ef 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -509,9 +509,6 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev) if (!fe) { printk(KERN_ERR "%s/2: xc3028 attach failed\n", dev->core->name); - dvb_frontend_detach(dev->dvb.frontend); - dvb_unregister_frontend(dev->dvb.frontend); - dev->dvb.frontend = NULL; return -EINVAL; } @@ -523,20 +520,23 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev) static int dvb_register(struct cx8802_dev *dev) { + struct cx88_core *core = dev->core; + /* init struct videobuf_dvb */ - dev->dvb.name = dev->core->name; + dev->dvb.name = core->name; dev->ts_gen_cntrl = 0x0c; /* init frontend */ - switch (dev->core->boardnr) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_DVB_T1: dev->dvb.frontend = dvb_attach(cx22702_attach, &connexant_refboard_config, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - &dev->core->i2c_adap, - DVB_PLL_THOMSON_DTT759X); + if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, + 0x61, &core->i2c_adap, + DVB_PLL_THOMSON_DTT759X)) + goto frontend_detach; } break; case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1: @@ -545,11 +545,12 @@ static int dvb_register(struct cx8802_dev *dev) case CX88_BOARD_WINFAST_DTV1000: dev->dvb.frontend = dvb_attach(cx22702_attach, &connexant_refboard_config, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60, - &dev->core->i2c_adap, - DVB_PLL_THOMSON_DTT7579); + if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, + 0x60, &core->i2c_adap, + DVB_PLL_THOMSON_DTT7579)) + goto frontend_detach; } break; case CX88_BOARD_WINFAST_DTV2000H: @@ -559,29 +560,32 @@ static int dvb_register(struct cx8802_dev *dev) case CX88_BOARD_HAUPPAUGE_HVR3000: dev->dvb.frontend = dvb_attach(cx22702_attach, &hauppauge_hvr_config, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(simple_tuner_attach, dev->dvb.frontend, - &dev->core->i2c_adap, 0x61, - TUNER_PHILIPS_FMD1216ME_MK3); + if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_PHILIPS_FMD1216ME_MK3)) + goto frontend_detach; } break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: dev->dvb.frontend = dvb_attach(mt352_attach, &dvico_fusionhdtv, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60, - NULL, DVB_PLL_THOMSON_DTT7579); + if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, + 0x60, NULL, DVB_PLL_THOMSON_DTT7579)) + goto frontend_detach; break; } /* ZL10353 replaces MT352 on later cards */ dev->dvb.frontend = dvb_attach(zl10353_attach, &dvico_fusionhdtv_plus_v1_1, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60, - NULL, DVB_PLL_THOMSON_DTT7579); + if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, + 0x60, NULL, DVB_PLL_THOMSON_DTT7579)) + goto frontend_detach; } break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL: @@ -589,28 +593,31 @@ static int dvb_register(struct cx8802_dev *dev) * compatible, with a slightly different MT352 AGC gain. */ dev->dvb.frontend = dvb_attach(mt352_attach, &dvico_fusionhdtv_dual, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - NULL, DVB_PLL_THOMSON_DTT7579); + if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, + 0x61, NULL, DVB_PLL_THOMSON_DTT7579)) + goto frontend_detach; break; } /* ZL10353 replaces MT352 on later cards */ dev->dvb.frontend = dvb_attach(zl10353_attach, &dvico_fusionhdtv_plus_v1_1, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - NULL, DVB_PLL_THOMSON_DTT7579); + if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, + 0x61, NULL, DVB_PLL_THOMSON_DTT7579)) + goto frontend_detach; } break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: dev->dvb.frontend = dvb_attach(mt352_attach, &dvico_fusionhdtv, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - NULL, DVB_PLL_LG_Z201); + if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, + 0x61, NULL, DVB_PLL_LG_Z201)) + goto frontend_detach; } break; case CX88_BOARD_KWORLD_DVB_T: @@ -618,10 +625,11 @@ static int dvb_register(struct cx8802_dev *dev) case CX88_BOARD_ADSTECH_DVB_T_PCI: dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_config, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - NULL, DVB_PLL_UNKNOWN_1); + if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, + 0x61, NULL, DVB_PLL_UNKNOWN_1)) + goto frontend_detach; } break; case CX88_BOARD_DNTV_LIVE_DVB_T_PRO: @@ -630,32 +638,35 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config, &dev->vp3054->adap); if (dev->dvb.frontend != NULL) { - dvb_attach(simple_tuner_attach, dev->dvb.frontend, - &dev->core->i2c_adap, 0x61, - TUNER_PHILIPS_FMD1216ME_MK3); + if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_PHILIPS_FMD1216ME_MK3)) + goto frontend_detach; } #else - printk(KERN_ERR "%s/2: built without vp3054 support\n", dev->core->name); + printk(KERN_ERR "%s/2: built without vp3054 support\n", + core->name); #endif break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID: dev->dvb.frontend = dvb_attach(zl10353_attach, &dvico_fusionhdtv_hybrid, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(simple_tuner_attach, dev->dvb.frontend, - &dev->core->i2c_adap, 0x61, - TUNER_THOMSON_FE6600); + if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_THOMSON_FE6600)) + goto frontend_detach; } break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO: dev->dvb.frontend = dvb_attach(zl10353_attach, &dvico_fusionhdtv_xc3028, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend == NULL) dev->dvb.frontend = dvb_attach(mt352_attach, &dvico_fusionhdtv_mt352_xc3028, - &dev->core->i2c_adap); + &core->i2c_adap); /* * On this board, the demod provides the I2C bus pullup. * We must not permit gate_ctrl to be performed, or @@ -668,19 +679,18 @@ static int dvb_register(struct cx8802_dev *dev) break; case CX88_BOARD_PCHDTV_HD3000: dev->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(simple_tuner_attach, dev->dvb.frontend, - &dev->core->i2c_adap, 0x61, - TUNER_THOMSON_DTT761X); + if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_THOMSON_DTT761X)) + goto frontend_detach; } break; case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: dev->ts_gen_cntrl = 0x08; - { - /* Do a hardware reset of chip before using it. */ - struct cx88_core *core = dev->core; + /* Do a hardware reset of chip before using it. */ cx_clear(MO_GP0_IO, 1); mdelay(100); cx_set(MO_GP0_IO, 1); @@ -690,139 +700,138 @@ static int dvb_register(struct cx8802_dev *dev) fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set; dev->dvb.frontend = dvb_attach(lgdt330x_attach, &fusionhdtv_3_gold, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(simple_tuner_attach, dev->dvb.frontend, - &dev->core->i2c_adap, 0x61, - TUNER_MICROTUNE_4042FI5); - } + if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_MICROTUNE_4042FI5)) + goto frontend_detach; } break; case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T: dev->ts_gen_cntrl = 0x08; - { - /* Do a hardware reset of chip before using it. */ - struct cx88_core *core = dev->core; + /* Do a hardware reset of chip before using it. */ cx_clear(MO_GP0_IO, 1); mdelay(100); cx_set(MO_GP0_IO, 9); mdelay(200); dev->dvb.frontend = dvb_attach(lgdt330x_attach, &fusionhdtv_3_gold, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(simple_tuner_attach, dev->dvb.frontend, - &dev->core->i2c_adap, 0x61, - TUNER_THOMSON_DTT761X); - } + if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_THOMSON_DTT761X)) + goto frontend_detach; } break; case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: dev->ts_gen_cntrl = 0x08; - { - /* Do a hardware reset of chip before using it. */ - struct cx88_core *core = dev->core; + /* Do a hardware reset of chip before using it. */ cx_clear(MO_GP0_IO, 1); mdelay(100); cx_set(MO_GP0_IO, 1); mdelay(200); dev->dvb.frontend = dvb_attach(lgdt330x_attach, &fusionhdtv_5_gold, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(simple_tuner_attach, dev->dvb.frontend, - &dev->core->i2c_adap, 0x61, - TUNER_LG_TDVS_H06XF); - dvb_attach(tda9887_attach, dev->dvb.frontend, - &dev->core->i2c_adap, 0x43); - } + if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_LG_TDVS_H06XF)) + goto frontend_detach; + if (!dvb_attach(tda9887_attach, dev->dvb.frontend, + &core->i2c_adap, 0x43)) + goto frontend_detach; } break; case CX88_BOARD_PCHDTV_HD5500: dev->ts_gen_cntrl = 0x08; - { - /* Do a hardware reset of chip before using it. */ - struct cx88_core *core = dev->core; + /* Do a hardware reset of chip before using it. */ cx_clear(MO_GP0_IO, 1); mdelay(100); cx_set(MO_GP0_IO, 1); mdelay(200); dev->dvb.frontend = dvb_attach(lgdt330x_attach, &pchdtv_hd5500, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(simple_tuner_attach, dev->dvb.frontend, - &dev->core->i2c_adap, 0x61, - TUNER_LG_TDVS_H06XF); - dvb_attach(tda9887_attach, dev->dvb.frontend, - &dev->core->i2c_adap, 0x43); - } + if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_LG_TDVS_H06XF)) + goto frontend_detach; + if (!dvb_attach(tda9887_attach, dev->dvb.frontend, + &core->i2c_adap, 0x43)) + goto frontend_detach; } break; case CX88_BOARD_ATI_HDTVWONDER: dev->dvb.frontend = dvb_attach(nxt200x_attach, &ati_hdtvwonder, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(simple_tuner_attach, dev->dvb.frontend, - &dev->core->i2c_adap, 0x61, - TUNER_PHILIPS_TUV1236D); + if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_PHILIPS_TUV1236D)) + goto frontend_detach; } break; case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: dev->dvb.frontend = dvb_attach(cx24123_attach, &hauppauge_novas_config, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend) { - dvb_attach(isl6421_attach, dev->dvb.frontend, - &dev->core->i2c_adap, 0x08, 0x00, 0x00); + if (!dvb_attach(isl6421_attach, dev->dvb.frontend, + &core->i2c_adap, 0x08, 0x00, 0x00)) + goto frontend_detach; } break; case CX88_BOARD_KWORLD_DVBS_100: dev->dvb.frontend = dvb_attach(cx24123_attach, &kworld_dvbs_100_config, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend) { - dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage; + core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage; dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage; } break; case CX88_BOARD_GENIATECH_DVBS: dev->dvb.frontend = dvb_attach(cx24123_attach, &geniatech_dvbs_config, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend) { - dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage; + core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage; dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; } break; case CX88_BOARD_PINNACLE_PCTV_HD_800i: dev->dvb.frontend = dvb_attach(s5h1409_attach, &pinnacle_pctv_hd_800i_config, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { /* tuner_config.video_dev must point to * i2c_adap.algo_data */ pinnacle_pctv_hd_800i_tuner_config.priv = - dev->core->i2c_adap.algo_data; - dvb_attach(xc5000_attach, dev->dvb.frontend, - &dev->core->i2c_adap, - &pinnacle_pctv_hd_800i_tuner_config); + core->i2c_adap.algo_data; + if (!dvb_attach(xc5000_attach, dev->dvb.frontend, + &core->i2c_adap, + &pinnacle_pctv_hd_800i_tuner_config)) + goto frontend_detach; } break; case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: dev->dvb.frontend = dvb_attach(s5h1409_attach, &dvico_hdtv5_pci_nano_config, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { struct dvb_frontend *fe; struct xc2028_config cfg = { - .i2c_adap = &dev->core->i2c_adap, + .i2c_adap = &core->i2c_adap, .i2c_addr = 0x61, .callback = cx88_pci_nano_callback, }; @@ -841,50 +850,51 @@ static int dvb_register(struct cx8802_dev *dev) case CX88_BOARD_PINNACLE_HYBRID_PCTV: dev->dvb.frontend = dvb_attach(zl10353_attach, &cx88_geniatech_x8000_mt, - &dev->core->i2c_adap); + &core->i2c_adap); if (attach_xc3028(0x61, dev) < 0) - return -EINVAL; + goto frontend_detach; break; case CX88_BOARD_GENIATECH_X8000_MT: dev->ts_gen_cntrl = 0x00; dev->dvb.frontend = dvb_attach(zl10353_attach, &cx88_geniatech_x8000_mt, - &dev->core->i2c_adap); + &core->i2c_adap); if (attach_xc3028(0x61, dev) < 0) - return -EINVAL; + goto frontend_detach; break; case CX88_BOARD_KWORLD_ATSC_120: dev->dvb.frontend = dvb_attach(s5h1409_attach, &kworld_atsc_120_config, - &dev->core->i2c_adap); + &core->i2c_adap); if (attach_xc3028(0x61, dev) < 0) - return -EINVAL; + goto frontend_detach; break; case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: dev->dvb.frontend = dvb_attach(s5h1411_attach, &dvico_fusionhdtv7_config, - &dev->core->i2c_adap); + &core->i2c_adap); if (dev->dvb.frontend != NULL) { /* tuner_config.video_dev must point to * i2c_adap.algo_data */ dvico_fusionhdtv7_tuner_config.priv = - dev->core->i2c_adap.algo_data; - dvb_attach(xc5000_attach, dev->dvb.frontend, - &dev->core->i2c_adap, - &dvico_fusionhdtv7_tuner_config); + core->i2c_adap.algo_data; + if (!dvb_attach(xc5000_attach, dev->dvb.frontend, + &core->i2c_adap, + &dvico_fusionhdtv7_tuner_config)) + goto frontend_detach; } break; default: printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", - dev->core->name); + core->name); break; } if (NULL == dev->dvb.frontend) { printk(KERN_ERR "%s/2: frontend initialization failed\n", - dev->core->name); + core->name); return -EINVAL; } @@ -892,11 +902,18 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl; /* Put the analog decoder in standby to keep it quiet */ - cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); + cx88_call_i2c_clients(core, TUNER_SET_STANDBY, NULL); /* register everything */ return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev, adapter_nr); + +frontend_detach: + if (dev->dvb.frontend) { + dvb_frontend_detach(dev->dvb.frontend); + dev->dvb.frontend = NULL; + } + return -EINVAL; } /* ----------------------------------------------------------- */ diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig index c7c2896bbd8b..16a5af30e9d1 100644 --- a/drivers/media/video/em28xx/Kconfig +++ b/drivers/media/video/em28xx/Kconfig @@ -1,7 +1,7 @@ config VIDEO_EM28XX tristate "Empia EM28xx USB video capture support" depends on VIDEO_DEV && I2C && INPUT - select MEDIA_TUNER + select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR select VIDEOBUF_VMALLOC @@ -35,7 +35,6 @@ config VIDEO_EM28XX_DVB select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE select VIDEOBUF_DVB - select FW_LOADER ---help--- This adds support for DVB cards based on the Empiatech em28xx chips. diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 50ccf3771204..3e4f3c7e92e7 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -420,7 +420,13 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, { USB_DEVICE(0x2040, 0x6502), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, - { USB_DEVICE(0x2040, 0x6513), + { USB_DEVICE(0x2040, 0x6513), /* HCW HVR-980 */ + .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, + { USB_DEVICE(0x2040, 0x6517), /* HP HVR-950 */ + .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, + { USB_DEVICE(0x2040, 0x651b), /* RP HVR-950 */ + .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, + { USB_DEVICE(0x2040, 0x651f), /* HCW HVR-850 */ .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, { USB_DEVICE(0x0ccd, 0x0042), .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS }, diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index 7df81575b7f2..8cf4983f0039 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -251,7 +251,6 @@ static int attach_xc3028(u8 addr, struct em28xx *dev) printk(KERN_ERR "%s/2: xc3028 attach failed\n", dev->name); dvb_frontend_detach(dev->dvb->frontend); - dvb_unregister_frontend(dev->dvb->frontend); dev->dvb->frontend = NULL; return -EINVAL; } diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index eec115bf9517..5d7ee8fcdd50 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -1,10 +1,12 @@ config VIDEO_IVTV tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support" depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL + depends on INPUT # due to VIDEO_IR + depends on HOTPLUG # due to FW_LOADER select I2C_ALGOBIT select FW_LOADER select VIDEO_IR - select MEDIA_TUNER + select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X select VIDEO_CX25840 diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c index 8c02fa661591..c7e449f6397b 100644 --- a/drivers/media/video/ivtv/ivtv-controls.c +++ b/drivers/media/video/ivtv/ivtv-controls.c @@ -181,12 +181,12 @@ static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fm return 0; } /* Need sliced data for mpeg insertion */ - if (get_service_set(itv->vbi.sliced_in) == 0) { + if (ivtv_get_service_set(itv->vbi.sliced_in) == 0) { if (itv->is_60hz) itv->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525; else itv->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625; - expand_service_set(itv->vbi.sliced_in, itv->is_50hz); + ivtv_expand_service_set(itv->vbi.sliced_in, itv->is_50hz); } return 0; } diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index ed020f722b05..797e636771da 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -853,6 +853,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev, return 0; } +#ifdef MODULE static u32 ivtv_request_module(struct ivtv *itv, u32 hw, const char *name, u32 id) { @@ -865,12 +866,14 @@ static u32 ivtv_request_module(struct ivtv *itv, u32 hw, IVTV_DEBUG_INFO("Loaded module %s\n", name); return hw; } +#endif static void ivtv_load_and_init_modules(struct ivtv *itv) { u32 hw = itv->card->hw_all; unsigned i; +#ifdef MODULE /* load modules */ #ifndef CONFIG_MEDIA_TUNER hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER); @@ -911,6 +914,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) #ifndef CONFIG_VIDEO_M52790 hw = ivtv_request_module(itv, hw, "m52790", IVTV_HW_M52790); #endif +#endif /* check which i2c devices are actually found */ for (i = 0; i < 32; i++) { @@ -1228,7 +1232,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, return 0; free_streams: - ivtv_streams_cleanup(itv); + ivtv_streams_cleanup(itv, 1); free_irq: free_irq(itv->dev->irq, (void *)itv); free_i2c: @@ -1373,7 +1377,7 @@ static void ivtv_remove(struct pci_dev *pci_dev) flush_workqueue(itv->irq_work_queues); destroy_workqueue(itv->irq_work_queues); - ivtv_streams_cleanup(itv); + ivtv_streams_cleanup(itv, 1); ivtv_udma_free(itv); exit_ivtv_i2c(itv); diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index d508b5d0538c..26cc0f6699fd 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -38,7 +38,7 @@ #include <linux/dvb/audio.h> #include <linux/i2c-id.h> -u16 service2vbi(int type) +u16 ivtv_service2vbi(int type) { switch (type) { case V4L2_SLICED_TELETEXT_B: @@ -88,7 +88,7 @@ static u16 select_service_from_set(int field, int line, u16 set, int is_pal) return 0; } -void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) +void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) { u16 set = fmt->service_set; int f, l; @@ -115,7 +115,7 @@ static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) return set != 0; } -u16 get_service_set(struct v4l2_sliced_vbi_format *fmt) +u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt) { int f, l; u16 set = 0; @@ -466,7 +466,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625; vbifmt->service_lines[0][16] = V4L2_SLICED_VPS; } - vbifmt->service_set = get_service_set(vbifmt); + vbifmt->service_set = ivtv_get_service_set(vbifmt); break; } @@ -481,12 +481,12 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) { vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; - expand_service_set(vbifmt, itv->is_50hz); + ivtv_expand_service_set(vbifmt, itv->is_50hz); break; } itv->video_dec_func(itv, VIDIOC_G_FMT, fmt); - vbifmt->service_set = get_service_set(vbifmt); + vbifmt->service_set = ivtv_get_service_set(vbifmt); break; } case V4L2_BUF_TYPE_VBI_OUTPUT: @@ -640,9 +640,9 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); if (vbifmt->service_set) - expand_service_set(vbifmt, itv->is_50hz); + ivtv_expand_service_set(vbifmt, itv->is_50hz); set = check_service_set(vbifmt, itv->is_50hz); - vbifmt->service_set = get_service_set(vbifmt); + vbifmt->service_set = ivtv_get_service_set(vbifmt); if (!set_fmt) return 0; diff --git a/drivers/media/video/ivtv/ivtv-ioctl.h b/drivers/media/video/ivtv/ivtv-ioctl.h index a03351b6853d..4e67f0ed1fc0 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.h +++ b/drivers/media/video/ivtv/ivtv-ioctl.h @@ -21,9 +21,9 @@ #ifndef IVTV_IOCTL_H #define IVTV_IOCTL_H -u16 service2vbi(int type); -void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); -u16 get_service_set(struct v4l2_sliced_vbi_format *fmt); +u16 ivtv_service2vbi(int type); +void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); +u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt); int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg); diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c index 3e1deec67a5e..fc8b1eaa333b 100644 --- a/drivers/media/video/ivtv/ivtv-queue.c +++ b/drivers/media/video/ivtv/ivtv-queue.c @@ -203,14 +203,14 @@ int ivtv_stream_alloc(struct ivtv_stream *s) s->dma != PCI_DMA_NONE ? "DMA " : "", s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); - s->sg_pending = kzalloc(SGsize, GFP_KERNEL); + s->sg_pending = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN); if (s->sg_pending == NULL) { IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name); return -ENOMEM; } s->sg_pending_size = 0; - s->sg_processing = kzalloc(SGsize, GFP_KERNEL); + s->sg_processing = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN); if (s->sg_processing == NULL) { IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name); kfree(s->sg_pending); @@ -219,7 +219,8 @@ int ivtv_stream_alloc(struct ivtv_stream *s) } s->sg_processing_size = 0; - s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL); + s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element), + GFP_KERNEL|__GFP_NOWARN); if (s->sg_dma == NULL) { IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name); kfree(s->sg_pending); @@ -235,11 +236,12 @@ int ivtv_stream_alloc(struct ivtv_stream *s) /* allocate stream buffers. Initially all buffers are in q_free. */ for (i = 0; i < s->buffers; i++) { - struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer), GFP_KERNEL); + struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer), + GFP_KERNEL|__GFP_NOWARN); if (buf == NULL) break; - buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL); + buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL|__GFP_NOWARN); if (buf->buf == NULL) { kfree(buf); break; diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 4ab8d36831ba..c47c2b945147 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -244,7 +244,7 @@ int ivtv_streams_setup(struct ivtv *itv) return 0; /* One or more streams could not be initialized. Clean 'em all up. */ - ivtv_streams_cleanup(itv); + ivtv_streams_cleanup(itv, 0); return -ENOMEM; } @@ -304,12 +304,12 @@ int ivtv_streams_register(struct ivtv *itv) return 0; /* One or more streams could not be initialized. Clean 'em all up. */ - ivtv_streams_cleanup(itv); + ivtv_streams_cleanup(itv, 1); return -ENOMEM; } /* Unregister v4l2 devices */ -void ivtv_streams_cleanup(struct ivtv *itv) +void ivtv_streams_cleanup(struct ivtv *itv, int unregister) { int type; @@ -322,8 +322,11 @@ void ivtv_streams_cleanup(struct ivtv *itv) continue; ivtv_stream_free(&itv->streams[type]); - /* Unregister device */ - video_unregister_device(vdev); + /* Unregister or release device */ + if (unregister) + video_unregister_device(vdev); + else + video_device_release(vdev); } } diff --git a/drivers/media/video/ivtv/ivtv-streams.h b/drivers/media/video/ivtv/ivtv-streams.h index 3d76a415fbd8..a653a5136417 100644 --- a/drivers/media/video/ivtv/ivtv-streams.h +++ b/drivers/media/video/ivtv/ivtv-streams.h @@ -23,7 +23,7 @@ int ivtv_streams_setup(struct ivtv *itv); int ivtv_streams_register(struct ivtv *itv); -void ivtv_streams_cleanup(struct ivtv *itv); +void ivtv_streams_cleanup(struct ivtv *itv, int unregister); /* Capture related */ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s); diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c index c151bcf5519a..71798f0da27f 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.c +++ b/drivers/media/video/ivtv/ivtv-vbi.c @@ -169,7 +169,8 @@ static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp) linemask[0] |= (1 << l); else linemask[1] |= (1 << (l - 32)); - dst[sd + 12 + line * 43] = service2vbi(itv->vbi.sliced_data[i].id); + dst[sd + 12 + line * 43] = + ivtv_service2vbi(itv->vbi.sliced_data[i].id); memcpy(dst + sd + 12 + line * 43 + 1, itv->vbi.sliced_data[i].data, 42); line++; } diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 62f70bd5e3cb..a9417f6e4087 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -908,7 +908,7 @@ static void ivtv_yuv_init(struct ivtv *itv) } /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */ - yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL); + yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN); if (yi->blanking_ptr) { yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE); } else { diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index df789f683e63..73be154f7f05 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -948,7 +948,8 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) } /* Allocate the pseudo palette */ - oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); + oi->ivtvfb_info.pseudo_palette = + kmalloc(sizeof(u32) * 16, GFP_KERNEL|__GFP_NOWARN); if (!oi->ivtvfb_info.pseudo_palette) { IVTVFB_ERR("abort, unable to alloc pseudo pallete\n"); @@ -1056,7 +1057,8 @@ static int ivtvfb_init_card(struct ivtv *itv) return -EBUSY; } - itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC); + itv->osd_info = kzalloc(sizeof(struct osd_info), + GFP_ATOMIC|__GFP_NOWARN); if (itv->osd_info == NULL) { IVTVFB_ERR("Failed to allocate memory for osd_info\n"); return -ENOMEM; diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 179e47049a45..ee43499544c1 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -12,15 +12,12 @@ #include <linux/slab.h> #include <linux/i2c.h> #include <linux/log2.h> +#include <linux/gpio.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> #include <media/soc_camera.h> -#ifdef CONFIG_MT9M001_PCA9536_SWITCH -#include <asm/gpio.h> -#endif - /* mt9m001 i2c address 0x5d * The platform has to define i2c_board_info * and call i2c_register_board_info() */ diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index d1391ac55096..1658fe590392 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -13,15 +13,12 @@ #include <linux/i2c.h> #include <linux/delay.h> #include <linux/log2.h> +#include <linux/gpio.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> #include <media/soc_camera.h> -#ifdef CONFIG_MT9M001_PCA9536_SWITCH -#include <asm/gpio.h> -#endif - /* mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c * The platform has to define i2c_board_info * and call i2c_register_board_info() */ @@ -91,7 +88,7 @@ static const struct soc_camera_data_format mt9v022_monochrome_formats[] = { struct mt9v022 { struct i2c_client *client; struct soc_camera_device icd; - int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ + int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ int switch_gpio; u16 chip_control; unsigned char datawidth; diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig index 9620c67fae77..e2a7a508c2e9 100644 --- a/drivers/media/video/pvrusb2/Kconfig +++ b/drivers/media/video/pvrusb2/Kconfig @@ -1,8 +1,9 @@ config VIDEO_PVRUSB2 tristate "Hauppauge WinTV-PVR USB2 support" depends on VIDEO_V4L2 && I2C + depends on HOTPLUG # due to FW_LOADER select FW_LOADER - select MEDIA_TUNER + select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X select VIDEO_SAA711X diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 40e4c3bd2cb9..83f076abce35 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -3,7 +3,7 @@ config VIDEO_SAA7134 depends on VIDEO_DEV && PCI && I2C && INPUT select VIDEOBUF_DMA_SG select VIDEO_IR - select MEDIA_TUNER + select VIDEO_TUNER select VIDEO_TVEEPROM select CRC32 ---help--- @@ -27,6 +27,7 @@ config VIDEO_SAA7134_ALSA config VIDEO_SAA7134_DVB tristate "DVB/ATSC Support for saa7134 based TV cards" depends on VIDEO_SAA7134 && DVB_CORE + depends on HOTPLUG # due to FW_LOADER select VIDEOBUF_DVB select FW_LOADER select DVB_PLL if !DVB_FE_CUSTOMISE diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 2d16be2259db..469f93aac008 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -538,19 +538,23 @@ static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe) return 0; } -static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config *cdec_conf, - struct tda827x_config *tuner_conf) +static int configure_tda827x_fe(struct saa7134_dev *dev, + struct tda1004x_config *cdec_conf, + struct tda827x_config *tuner_conf) { dev->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap); if (dev->dvb.frontend) { if (cdec_conf->i2c_gate) dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; - if (dvb_attach(tda827x_attach, dev->dvb.frontend, cdec_conf->tuner_address, - &dev->i2c_adap, tuner_conf) == NULL) { - wprintk("no tda827x tuner found at addr: %02x\n", + if (dvb_attach(tda827x_attach, dev->dvb.frontend, + cdec_conf->tuner_address, + &dev->i2c_adap, tuner_conf)) + return 0; + + wprintk("no tda827x tuner found at addr: %02x\n", cdec_conf->tuner_address); - } } + return -EINVAL; } /* ------------------------------------------------------------------ */ @@ -997,7 +1001,9 @@ static int dvb_init(struct saa7134_dev *dev) break; case SAA7134_BOARD_FLYDVBTDUO: case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS: - configure_tda827x_fe(dev, &tda827x_lifeview_config, &tda827x_cfg_0); + if (configure_tda827x_fe(dev, &tda827x_lifeview_config, + &tda827x_cfg_0) < 0) + goto dettach_frontend; break; case SAA7134_BOARD_PHILIPS_EUROPA: case SAA7134_BOARD_VIDEOMATE_DVBT_300: @@ -1022,36 +1028,52 @@ static int dvb_init(struct saa7134_dev *dev) } break; case SAA7134_BOARD_KWORLD_DVBT_210: - configure_tda827x_fe(dev, &kworld_dvb_t_210_config, &tda827x_cfg_2); + if (configure_tda827x_fe(dev, &kworld_dvb_t_210_config, + &tda827x_cfg_2) < 0) + goto dettach_frontend; break; case SAA7134_BOARD_PHILIPS_TIGER: - configure_tda827x_fe(dev, &philips_tiger_config, &tda827x_cfg_0); + if (configure_tda827x_fe(dev, &philips_tiger_config, + &tda827x_cfg_0) < 0) + goto dettach_frontend; break; case SAA7134_BOARD_PINNACLE_PCTV_310i: - configure_tda827x_fe(dev, &pinnacle_pctv_310i_config, &tda827x_cfg_1); + if (configure_tda827x_fe(dev, &pinnacle_pctv_310i_config, + &tda827x_cfg_1) < 0) + goto dettach_frontend; break; case SAA7134_BOARD_HAUPPAUGE_HVR1110: - configure_tda827x_fe(dev, &hauppauge_hvr_1110_config, &tda827x_cfg_1); + if (configure_tda827x_fe(dev, &hauppauge_hvr_1110_config, + &tda827x_cfg_1) < 0) + goto dettach_frontend; break; case SAA7134_BOARD_ASUSTeK_P7131_DUAL: - configure_tda827x_fe(dev, &asus_p7131_dual_config, &tda827x_cfg_0); + if (configure_tda827x_fe(dev, &asus_p7131_dual_config, + &tda827x_cfg_0) < 0) + goto dettach_frontend; break; case SAA7134_BOARD_FLYDVBT_LR301: - configure_tda827x_fe(dev, &tda827x_lifeview_config, &tda827x_cfg_0); + if (configure_tda827x_fe(dev, &tda827x_lifeview_config, + &tda827x_cfg_0) < 0) + goto dettach_frontend; break; case SAA7134_BOARD_FLYDVB_TRIO: - if(! use_frontend) { /* terrestrial */ - configure_tda827x_fe(dev, &lifeview_trio_config, &tda827x_cfg_0); + if (!use_frontend) { /* terrestrial */ + if (configure_tda827x_fe(dev, &lifeview_trio_config, + &tda827x_cfg_0) < 0) + goto dettach_frontend; } else { /* satellite */ dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap); if (dev->dvb.frontend) { if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63, &dev->i2c_adap, 0) == NULL) { wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__); + goto dettach_frontend; } if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap, 0x08, 0, 0) == NULL) { wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__); + goto dettach_frontend; } } } @@ -1067,15 +1089,20 @@ static int dvb_init(struct saa7134_dev *dev) &ads_duo_cfg) == NULL) { wprintk("no tda827x tuner found at addr: %02x\n", ads_tech_duo_config.tuner_address); + goto dettach_frontend; } } break; case SAA7134_BOARD_TEVION_DVBT_220RF: - configure_tda827x_fe(dev, &tevion_dvbt220rf_config, &tda827x_cfg_0); + if (configure_tda827x_fe(dev, &tevion_dvbt220rf_config, + &tda827x_cfg_0) < 0) + goto dettach_frontend; break; case SAA7134_BOARD_MEDION_MD8800_QUADRO: if (!use_frontend) { /* terrestrial */ - configure_tda827x_fe(dev, &md8800_dvbt_config, &tda827x_cfg_0); + if (configure_tda827x_fe(dev, &md8800_dvbt_config, + &tda827x_cfg_0) < 0) + goto dettach_frontend; } else { /* satellite */ dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap); @@ -1086,16 +1113,20 @@ static int dvb_init(struct saa7134_dev *dev) struct i2c_msg msg = {.addr = 0x08, .flags = 0, .len = 1}; if (dvb_attach(tda826x_attach, dev->dvb.frontend, - 0x60, &dev->i2c_adap, 0) == NULL) + 0x60, &dev->i2c_adap, 0) == NULL) { wprintk("%s: Medion Quadro, no tda826x " "found !\n", __func__); + goto dettach_frontend; + } if (dev_id != 0x08) { /* we need to open the i2c gate (we know it exists) */ fe->ops.i2c_gate_ctrl(fe, 1); if (dvb_attach(isl6405_attach, fe, - &dev->i2c_adap, 0x08, 0, 0) == NULL) + &dev->i2c_adap, 0x08, 0, 0) == NULL) { wprintk("%s: Medion Quadro, no ISL6405 " "found !\n", __func__); + goto dettach_frontend; + } if (dev_id == 0x07) { /* fire up the 2nd section of the LNB supply since we can't do this from the other section */ @@ -1117,19 +1148,17 @@ static int dvb_init(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180: dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180, &dev->i2c_adap); - if (dev->dvb.frontend) { + if (dev->dvb.frontend) dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, NULL, DVB_PLL_TDHU2); - } break; case SAA7134_BOARD_KWORLD_ATSC110: dev->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110, &dev->i2c_adap); - if (dev->dvb.frontend) { + if (dev->dvb.frontend) dvb_attach(simple_tuner_attach, dev->dvb.frontend, &dev->i2c_adap, 0x61, TUNER_PHILIPS_TUV1236D); - } break; case SAA7134_BOARD_FLYDVBS_LR300: dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, @@ -1138,10 +1167,12 @@ static int dvb_init(struct saa7134_dev *dev) if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60, &dev->i2c_adap, 0) == NULL) { wprintk("%s: No tda826x found!\n", __func__); + goto dettach_frontend; } if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap, 0x08, 0, 0) == NULL) { wprintk("%s: No ISL6421 found!\n", __func__); + goto dettach_frontend; } } break; @@ -1168,43 +1199,65 @@ static int dvb_init(struct saa7134_dev *dev) } break; case SAA7134_BOARD_CINERGY_HT_PCMCIA: - configure_tda827x_fe(dev, &cinergy_ht_config, &tda827x_cfg_0); + if (configure_tda827x_fe(dev, &cinergy_ht_config, + &tda827x_cfg_0) < 0) + goto dettach_frontend; break; case SAA7134_BOARD_CINERGY_HT_PCI: - configure_tda827x_fe(dev, &cinergy_ht_pci_config, &tda827x_cfg_0); + if (configure_tda827x_fe(dev, &cinergy_ht_pci_config, + &tda827x_cfg_0) < 0) + goto dettach_frontend; break; case SAA7134_BOARD_PHILIPS_TIGER_S: - configure_tda827x_fe(dev, &philips_tiger_s_config, &tda827x_cfg_2); + if (configure_tda827x_fe(dev, &philips_tiger_s_config, + &tda827x_cfg_2) < 0) + goto dettach_frontend; break; case SAA7134_BOARD_ASUS_P7131_4871: - configure_tda827x_fe(dev, &asus_p7131_4871_config, &tda827x_cfg_2); + if (configure_tda827x_fe(dev, &asus_p7131_4871_config, + &tda827x_cfg_2) < 0) + goto dettach_frontend; break; case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: - configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config, &tda827x_cfg_2); + if (configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config, + &tda827x_cfg_2) < 0) + goto dettach_frontend; break; case SAA7134_BOARD_AVERMEDIA_SUPER_007: - configure_tda827x_fe(dev, &avermedia_super_007_config, &tda827x_cfg_0); + if (configure_tda827x_fe(dev, &avermedia_super_007_config, + &tda827x_cfg_0) < 0) + goto dettach_frontend; break; case SAA7134_BOARD_TWINHAN_DTV_DVB_3056: - configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config, &tda827x_cfg_2_sw42); + if (configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config, + &tda827x_cfg_2_sw42) < 0) + goto dettach_frontend; break; case SAA7134_BOARD_PHILIPS_SNAKE: dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap); if (dev->dvb.frontend) { if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60, - &dev->i2c_adap, 0) == NULL) + &dev->i2c_adap, 0) == NULL) { wprintk("%s: No tda826x found!\n", __func__); + goto dettach_frontend; + } if (dvb_attach(lnbp21_attach, dev->dvb.frontend, - &dev->i2c_adap, 0, 0) == NULL) + &dev->i2c_adap, 0, 0) == NULL) { wprintk("%s: No lnbp21 found!\n", __func__); + goto dettach_frontend; + } } break; case SAA7134_BOARD_CREATIX_CTX953: - configure_tda827x_fe(dev, &md8800_dvbt_config, &tda827x_cfg_0); + if (configure_tda827x_fe(dev, &md8800_dvbt_config, + &tda827x_cfg_0) < 0) + goto dettach_frontend; break; case SAA7134_BOARD_MSI_TVANYWHERE_AD11: - configure_tda827x_fe(dev, &philips_tiger_s_config, &tda827x_cfg_2); + if (configure_tda827x_fe(dev, &philips_tiger_s_config, + &tda827x_cfg_2) < 0) + goto dettach_frontend; break; case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: dev->dvb.frontend = dvb_attach(mt352_attach, @@ -1218,16 +1271,20 @@ static int dvb_init(struct saa7134_dev *dev) if (dev->dvb.frontend) { struct dvb_frontend *fe; if (dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60, - &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) + &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) { wprintk("%s: MD7134 DVB-S, no SD1878 " "found !\n", __func__); + goto dettach_frontend; + } /* we need to open the i2c gate (we know it exists) */ fe = dev->dvb.frontend; fe->ops.i2c_gate_ctrl(fe, 1); if (dvb_attach(isl6405_attach, fe, - &dev->i2c_adap, 0x08, 0, 0) == NULL) + &dev->i2c_adap, 0x08, 0, 0) == NULL) { wprintk("%s: MD7134 DVB-S, no ISL6405 " "found !\n", __func__); + goto dettach_frontend; + } fe->ops.i2c_gate_ctrl(fe, 0); dev->original_set_voltage = fe->ops.set_voltage; fe->ops.set_voltage = md8800_set_voltage; @@ -1254,10 +1311,7 @@ static int dvb_init(struct saa7134_dev *dev) if (!fe) { printk(KERN_ERR "%s/2: xc3028 attach failed\n", dev->name); - dvb_frontend_detach(dev->dvb.frontend); - dvb_unregister_frontend(dev->dvb.frontend); - dev->dvb.frontend = NULL; - return -1; + goto dettach_frontend; } } @@ -1282,6 +1336,12 @@ static int dvb_init(struct saa7134_dev *dev) dev->dvb.frontend->ops.tuner_ops.sleep(dev->dvb.frontend); } return ret; + +dettach_frontend: + dvb_frontend_detach(dev->dvb.frontend); + dev->dvb.frontend = NULL; + + return -1; } static int dvb_fini(struct saa7134_dev *dev) diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index 9276ed997388..b12c60cf5a09 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -30,6 +30,7 @@ #include <linux/kref.h> #include <linux/usb.h> +#include <linux/mm.h> #include <linux/vmalloc.h> #include <linux/videodev2.h> #include <media/v4l2-common.h> @@ -245,6 +246,8 @@ static int stk_initialise(struct stk_camera *dev) return -1; } +#ifdef CONFIG_VIDEO_V4L1_COMPAT + /* sysfs functions */ /*FIXME cleanup this */ @@ -350,6 +353,10 @@ static void stk_remove_sysfs_files(struct video_device *vdev) video_device_remove_file(vdev, &dev_attr_vflip); } +#else +#define stk_create_sysfs_files(a) +#define stk_remove_sysfs_files(a) +#endif /* *********************************************** */ /* diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 6bf104ea051d..4ca686fad557 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -40,11 +40,11 @@ typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ if (__a) { \ __r = (int) __a(ARGS); \ + symbol_put(FUNCTION); \ } else { \ printk(KERN_ERR "TUNER: Unable to find " \ "symbol "#FUNCTION"()\n"); \ } \ - symbol_put(FUNCTION); \ __r; \ }) @@ -340,16 +340,6 @@ static void tuner_i2c_address_check(struct tuner *t) tuner_warn("====================== WARNING! ======================\n"); } -static void attach_tda829x(struct tuner *t) -{ - struct tda829x_config cfg = { - .lna_cfg = t->config, - .tuner_callback = t->tuner_callback, - }; - dvb_attach(tda829x_attach, - &t->fe, t->i2c->adapter, t->i2c->addr, &cfg); -} - static struct xc5000_config xc5000_cfg; static void set_type(struct i2c_client *c, unsigned int type, @@ -385,12 +375,19 @@ static void set_type(struct i2c_client *c, unsigned int type, switch (t->type) { case TUNER_MT2032: - dvb_attach(microtune_attach, - &t->fe, t->i2c->adapter, t->i2c->addr); + if (!dvb_attach(microtune_attach, + &t->fe, t->i2c->adapter, t->i2c->addr)) + goto attach_failed; break; case TUNER_PHILIPS_TDA8290: { - attach_tda829x(t); + struct tda829x_config cfg = { + .lna_cfg = t->config, + .tuner_callback = t->tuner_callback, + }; + if (!dvb_attach(tda829x_attach, &t->fe, t->i2c->adapter, + t->i2c->addr, &cfg)) + goto attach_failed; break; } case TUNER_TEA5767: @@ -441,8 +438,9 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } case TUNER_TDA9887: - dvb_attach(tda9887_attach, - &t->fe, t->i2c->adapter, t->i2c->addr); + if (!dvb_attach(tda9887_attach, + &t->fe, t->i2c->adapter, t->i2c->addr)) + goto attach_failed; break; case TUNER_XC5000: { @@ -1167,7 +1165,7 @@ static int tuner_probe(struct i2c_client *client, /* If chip is not tda8290, don't register. since it can be tda9887*/ if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter, - t->i2c->addr) == 0) { + t->i2c->addr) >= 0) { tuner_dbg("tda829x detected\n"); } else { /* Default is being tda9887 */ @@ -1181,7 +1179,7 @@ static int tuner_probe(struct i2c_client *client, case 0x60: if (tuner_symbol_probe(tea5767_autodetection, t->i2c->adapter, t->i2c->addr) - != EINVAL) { + >= 0) { t->type = TUNER_TEA5767; t->mode_mask = T_RADIO; t->mode = T_STANDBY; diff --git a/drivers/media/video/usbvision/Kconfig b/drivers/media/video/usbvision/Kconfig index 74e1d3075a20..fc24ef05b3f3 100644 --- a/drivers/media/video/usbvision/Kconfig +++ b/drivers/media/video/usbvision/Kconfig @@ -1,7 +1,7 @@ config VIDEO_USBVISION tristate "USB video devices based on Nogatech NT1003/1004/1005" depends on I2C && VIDEO_V4L2 - select MEDIA_TUNER + select VIDEO_TUNER select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO ---help--- There are more than 50 different USB video devices based on |