Path: blob/master/drivers/media/dvb/frontends/dib0090.c
15112 views
/*1* Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner.2*3* Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/)4*5* This program is free software; you can redistribute it and/or6* modify it under the terms of the GNU General Public License as7* published by the Free Software Foundation; either version 2 of the8* License, or (at your option) any later version.9*10* This program is distributed in the hope that it will be useful, but11* WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13*14* GNU General Public License for more details.15*16* You should have received a copy of the GNU General Public License17* along with this program; if not, write to the Free Software18* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.19*20*21* This code is more or less generated from another driver, please22* excuse some codingstyle oddities.23*24*/2526#include <linux/kernel.h>27#include <linux/slab.h>28#include <linux/i2c.h>2930#include "dvb_frontend.h"3132#include "dib0090.h"33#include "dibx000_common.h"3435static int debug;36module_param(debug, int, 0644);37MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");3839#define dprintk(args...) do { \40if (debug) { \41printk(KERN_DEBUG "DiB0090: "); \42printk(args); \43printk("\n"); \44} \45} while (0)4647#define CONFIG_SYS_DVBT48#define CONFIG_SYS_ISDBT49#define CONFIG_BAND_CBAND50#define CONFIG_BAND_VHF51#define CONFIG_BAND_UHF52#define CONFIG_DIB0090_USE_PWM_AGC5354#define EN_LNA0 0x800055#define EN_LNA1 0x400056#define EN_LNA2 0x200057#define EN_LNA3 0x100058#define EN_MIX0 0x080059#define EN_MIX1 0x040060#define EN_MIX2 0x020061#define EN_MIX3 0x010062#define EN_IQADC 0x004063#define EN_PLL 0x002064#define EN_TX 0x001065#define EN_BB 0x000866#define EN_LO 0x000467#define EN_BIAS 0x00016869#define EN_IQANA 0x000270#define EN_DIGCLK 0x0080 /* not in the 0x24 reg, only in 0x1b */71#define EN_CRYSTAL 0x00027273#define EN_UHF 0x22E974#define EN_VHF 0x44E975#define EN_LBD 0x11E976#define EN_SBD 0x44E977#define EN_CAB 0x88E97879/* Calibration defines */80#define DC_CAL 0x181#define WBD_CAL 0x282#define TEMP_CAL 0x483#define CAPTRIM_CAL 0x88485#define KROSUS_PLL_LOCKED 0x80086#define KROSUS 0x28788/* Use those defines to identify SOC version */89#define SOC 0x0290#define SOC_7090_P1G_11R1 0x8291#define SOC_7090_P1G_21R1 0x8a92#define SOC_8090_P1G_11R1 0x8693#define SOC_8090_P1G_21R1 0x8e9495/* else use thos ones to check */96#define P1A_B 0x097#define P1C 0x198#define P1D_E_F 0x399#define P1G 0x7100#define P1G_21R2 0xf101102#define MP001 0x1 /* Single 9090/8096 */103#define MP005 0x4 /* Single Sband */104#define MP008 0x6 /* Dual diversity VHF-UHF-LBAND */105#define MP009 0x7 /* Dual diversity 29098 CBAND-UHF-LBAND-SBAND */106107#define pgm_read_word(w) (*w)108109struct dc_calibration;110111struct dib0090_tuning {112u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */113u8 switch_trim;114u8 lna_tune;115u16 lna_bias;116u16 v2i;117u16 mix;118u16 load;119u16 tuner_enable;120};121122struct dib0090_pll {123u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */124u8 vco_band;125u8 hfdiv_code;126u8 hfdiv;127u8 topresc;128};129130struct dib0090_identity {131u8 version;132u8 product;133u8 p1g;134u8 in_soc;135};136137struct dib0090_state {138struct i2c_adapter *i2c;139struct dvb_frontend *fe;140const struct dib0090_config *config;141142u8 current_band;143enum frontend_tune_state tune_state;144u32 current_rf;145146u16 wbd_offset;147s16 wbd_target; /* in dB */148149s16 rf_gain_limit; /* take-over-point: where to split between bb and rf gain */150s16 current_gain; /* keeps the currently programmed gain */151u8 agc_step; /* new binary search */152153u16 gain[2]; /* for channel monitoring */154155const u16 *rf_ramp;156const u16 *bb_ramp;157158/* for the software AGC ramps */159u16 bb_1_def;160u16 rf_lt_def;161u16 gain_reg[4];162163/* for the captrim/dc-offset search */164s8 step;165s16 adc_diff;166s16 min_adc_diff;167168s8 captrim;169s8 fcaptrim;170171const struct dc_calibration *dc;172u16 bb6, bb7;173174const struct dib0090_tuning *current_tune_table_index;175const struct dib0090_pll *current_pll_table_index;176177u8 tuner_is_tuned;178u8 agc_freeze;179180struct dib0090_identity identity;181182u32 rf_request;183u8 current_standard;184185u8 calibrate;186u32 rest;187u16 bias;188s16 temperature;189190u8 wbd_calibration_gain;191const struct dib0090_wbd_slope *current_wbd_table;192u16 wbdmux;193194/* for the I2C transfer */195struct i2c_msg msg[2];196u8 i2c_write_buffer[3];197u8 i2c_read_buffer[2];198};199200struct dib0090_fw_state {201struct i2c_adapter *i2c;202struct dvb_frontend *fe;203struct dib0090_identity identity;204const struct dib0090_config *config;205206/* for the I2C transfer */207struct i2c_msg msg;208u8 i2c_write_buffer[2];209u8 i2c_read_buffer[2];210};211212static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)213{214state->i2c_write_buffer[0] = reg;215216memset(state->msg, 0, 2 * sizeof(struct i2c_msg));217state->msg[0].addr = state->config->i2c_address;218state->msg[0].flags = 0;219state->msg[0].buf = state->i2c_write_buffer;220state->msg[0].len = 1;221state->msg[1].addr = state->config->i2c_address;222state->msg[1].flags = I2C_M_RD;223state->msg[1].buf = state->i2c_read_buffer;224state->msg[1].len = 2;225226if (i2c_transfer(state->i2c, state->msg, 2) != 2) {227printk(KERN_WARNING "DiB0090 I2C read failed\n");228return 0;229}230231return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];232}233234static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)235{236state->i2c_write_buffer[0] = reg & 0xff;237state->i2c_write_buffer[1] = val >> 8;238state->i2c_write_buffer[2] = val & 0xff;239240memset(state->msg, 0, sizeof(struct i2c_msg));241state->msg[0].addr = state->config->i2c_address;242state->msg[0].flags = 0;243state->msg[0].buf = state->i2c_write_buffer;244state->msg[0].len = 3;245246if (i2c_transfer(state->i2c, state->msg, 1) != 1) {247printk(KERN_WARNING "DiB0090 I2C write failed\n");248return -EREMOTEIO;249}250return 0;251}252253static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)254{255state->i2c_write_buffer[0] = reg;256257memset(&state->msg, 0, sizeof(struct i2c_msg));258state->msg.addr = reg;259state->msg.flags = I2C_M_RD;260state->msg.buf = state->i2c_read_buffer;261state->msg.len = 2;262if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {263printk(KERN_WARNING "DiB0090 I2C read failed\n");264return 0;265}266return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];267}268269static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)270{271state->i2c_write_buffer[0] = val >> 8;272state->i2c_write_buffer[1] = val & 0xff;273274memset(&state->msg, 0, sizeof(struct i2c_msg));275state->msg.addr = reg;276state->msg.flags = 0;277state->msg.buf = state->i2c_write_buffer;278state->msg.len = 2;279if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {280printk(KERN_WARNING "DiB0090 I2C write failed\n");281return -EREMOTEIO;282}283return 0;284}285286#define HARD_RESET(state) do { if (cfg->reset) { if (cfg->sleep) cfg->sleep(fe, 0); msleep(10); cfg->reset(fe, 1); msleep(10); cfg->reset(fe, 0); msleep(10); } } while (0)287#define ADC_TARGET -220288#define GAIN_ALPHA 5289#define WBD_ALPHA 6290#define LPF 100291static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, u8 c)292{293do {294dib0090_write_reg(state, r++, *b++);295} while (--c);296}297298static int dib0090_identify(struct dvb_frontend *fe)299{300struct dib0090_state *state = fe->tuner_priv;301u16 v;302struct dib0090_identity *identity = &state->identity;303304v = dib0090_read_reg(state, 0x1a);305306identity->p1g = 0;307identity->in_soc = 0;308309dprintk("Tuner identification (Version = 0x%04x)", v);310311/* without PLL lock info */312v &= ~KROSUS_PLL_LOCKED;313314identity->version = v & 0xff;315identity->product = (v >> 8) & 0xf;316317if (identity->product != KROSUS)318goto identification_error;319320if ((identity->version & 0x3) == SOC) {321identity->in_soc = 1;322switch (identity->version) {323case SOC_8090_P1G_11R1:324dprintk("SOC 8090 P1-G11R1 Has been detected");325identity->p1g = 1;326break;327case SOC_8090_P1G_21R1:328dprintk("SOC 8090 P1-G21R1 Has been detected");329identity->p1g = 1;330break;331case SOC_7090_P1G_11R1:332dprintk("SOC 7090 P1-G11R1 Has been detected");333identity->p1g = 1;334break;335case SOC_7090_P1G_21R1:336dprintk("SOC 7090 P1-G21R1 Has been detected");337identity->p1g = 1;338break;339default:340goto identification_error;341}342} else {343switch ((identity->version >> 5) & 0x7) {344case MP001:345dprintk("MP001 : 9090/8096");346break;347case MP005:348dprintk("MP005 : Single Sband");349break;350case MP008:351dprintk("MP008 : diversity VHF-UHF-LBAND");352break;353case MP009:354dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND");355break;356default:357goto identification_error;358}359360switch (identity->version & 0x1f) {361case P1G_21R2:362dprintk("P1G_21R2 detected");363identity->p1g = 1;364break;365case P1G:366dprintk("P1G detected");367identity->p1g = 1;368break;369case P1D_E_F:370dprintk("P1D/E/F detected");371break;372case P1C:373dprintk("P1C detected");374break;375case P1A_B:376dprintk("P1-A/B detected: driver is deactivated - not available");377goto identification_error;378break;379default:380goto identification_error;381}382}383384return 0;385386identification_error:387return -EIO;388}389390static int dib0090_fw_identify(struct dvb_frontend *fe)391{392struct dib0090_fw_state *state = fe->tuner_priv;393struct dib0090_identity *identity = &state->identity;394395u16 v = dib0090_fw_read_reg(state, 0x1a);396identity->p1g = 0;397identity->in_soc = 0;398399dprintk("FE: Tuner identification (Version = 0x%04x)", v);400401/* without PLL lock info */402v &= ~KROSUS_PLL_LOCKED;403404identity->version = v & 0xff;405identity->product = (v >> 8) & 0xf;406407if (identity->product != KROSUS)408goto identification_error;409410if ((identity->version & 0x3) == SOC) {411identity->in_soc = 1;412switch (identity->version) {413case SOC_8090_P1G_11R1:414dprintk("SOC 8090 P1-G11R1 Has been detected");415identity->p1g = 1;416break;417case SOC_8090_P1G_21R1:418dprintk("SOC 8090 P1-G21R1 Has been detected");419identity->p1g = 1;420break;421case SOC_7090_P1G_11R1:422dprintk("SOC 7090 P1-G11R1 Has been detected");423identity->p1g = 1;424break;425case SOC_7090_P1G_21R1:426dprintk("SOC 7090 P1-G21R1 Has been detected");427identity->p1g = 1;428break;429default:430goto identification_error;431}432} else {433switch ((identity->version >> 5) & 0x7) {434case MP001:435dprintk("MP001 : 9090/8096");436break;437case MP005:438dprintk("MP005 : Single Sband");439break;440case MP008:441dprintk("MP008 : diversity VHF-UHF-LBAND");442break;443case MP009:444dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND");445break;446default:447goto identification_error;448}449450switch (identity->version & 0x1f) {451case P1G_21R2:452dprintk("P1G_21R2 detected");453identity->p1g = 1;454break;455case P1G:456dprintk("P1G detected");457identity->p1g = 1;458break;459case P1D_E_F:460dprintk("P1D/E/F detected");461break;462case P1C:463dprintk("P1C detected");464break;465case P1A_B:466dprintk("P1-A/B detected: driver is deactivated - not available");467goto identification_error;468break;469default:470goto identification_error;471}472}473474return 0;475476identification_error:477return -EIO;;478}479480static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)481{482struct dib0090_state *state = fe->tuner_priv;483u16 PllCfg, i, v;484485HARD_RESET(state);486487dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);488dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */489490if (!cfg->in_soc) {491/* adcClkOutRatio=8->7, release reset */492dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0);493if (cfg->clkoutdrive != 0)494dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)495| (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));496else497dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)498| (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));499}500501/* Read Pll current config * */502PllCfg = dib0090_read_reg(state, 0x21);503504/** Reconfigure PLL if current setting is different from default setting **/505if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && (!cfg->in_soc)506&& !cfg->io.pll_bypass) {507508/* Set Bypass mode */509PllCfg |= (1 << 15);510dib0090_write_reg(state, 0x21, PllCfg);511512/* Set Reset Pll */513PllCfg &= ~(1 << 13);514dib0090_write_reg(state, 0x21, PllCfg);515516/*** Set new Pll configuration in bypass and reset state ***/517PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);518dib0090_write_reg(state, 0x21, PllCfg);519520/* Remove Reset Pll */521PllCfg |= (1 << 13);522dib0090_write_reg(state, 0x21, PllCfg);523524/*** Wait for PLL lock ***/525i = 100;526do {527v = !!(dib0090_read_reg(state, 0x1a) & 0x800);528if (v)529break;530} while (--i);531532if (i == 0) {533dprintk("Pll: Unable to lock Pll");534return;535}536537/* Finally Remove Bypass mode */538PllCfg &= ~(1 << 15);539dib0090_write_reg(state, 0x21, PllCfg);540}541542if (cfg->io.pll_bypass) {543PllCfg |= (cfg->io.pll_bypass << 15);544dib0090_write_reg(state, 0x21, PllCfg);545}546}547548static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)549{550struct dib0090_fw_state *state = fe->tuner_priv;551u16 PllCfg;552u16 v;553int i;554555dprintk("fw reset digital");556HARD_RESET(state);557558dib0090_fw_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);559dib0090_fw_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */560561dib0090_fw_write_reg(state, 0x20,562((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (cfg->data_tx_drv << 4) | cfg->ls_cfg_pad_drv);563564v = (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 9) | (0 << 8) | (cfg->clkouttobamse << 4) | (0 << 2) | (0);565if (cfg->clkoutdrive != 0)566v |= cfg->clkoutdrive << 5;567else568v |= 7 << 5;569570v |= 2 << 10;571dib0090_fw_write_reg(state, 0x23, v);572573/* Read Pll current config * */574PllCfg = dib0090_fw_read_reg(state, 0x21);575576/** Reconfigure PLL if current setting is different from default setting **/577if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && !cfg->io.pll_bypass) {578579/* Set Bypass mode */580PllCfg |= (1 << 15);581dib0090_fw_write_reg(state, 0x21, PllCfg);582583/* Set Reset Pll */584PllCfg &= ~(1 << 13);585dib0090_fw_write_reg(state, 0x21, PllCfg);586587/*** Set new Pll configuration in bypass and reset state ***/588PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);589dib0090_fw_write_reg(state, 0x21, PllCfg);590591/* Remove Reset Pll */592PllCfg |= (1 << 13);593dib0090_fw_write_reg(state, 0x21, PllCfg);594595/*** Wait for PLL lock ***/596i = 100;597do {598v = !!(dib0090_fw_read_reg(state, 0x1a) & 0x800);599if (v)600break;601} while (--i);602603if (i == 0) {604dprintk("Pll: Unable to lock Pll");605return -EIO;606}607608/* Finally Remove Bypass mode */609PllCfg &= ~(1 << 15);610dib0090_fw_write_reg(state, 0x21, PllCfg);611}612613if (cfg->io.pll_bypass) {614PllCfg |= (cfg->io.pll_bypass << 15);615dib0090_fw_write_reg(state, 0x21, PllCfg);616}617618return dib0090_fw_identify(fe);619}620621static int dib0090_wakeup(struct dvb_frontend *fe)622{623struct dib0090_state *state = fe->tuner_priv;624if (state->config->sleep)625state->config->sleep(fe, 0);626627/* enable dataTX in case we have been restarted in the wrong moment */628dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));629return 0;630}631632static int dib0090_sleep(struct dvb_frontend *fe)633{634struct dib0090_state *state = fe->tuner_priv;635if (state->config->sleep)636state->config->sleep(fe, 1);637return 0;638}639640void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)641{642struct dib0090_state *state = fe->tuner_priv;643if (fast)644dib0090_write_reg(state, 0x04, 0);645else646dib0090_write_reg(state, 0x04, 1);647}648649EXPORT_SYMBOL(dib0090_dcc_freq);650651static const u16 bb_ramp_pwm_normal_socs[] = {652550, /* max BB gain in 10th of dB */653(1 << 9) | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */654440,655(4 << 9) | 0, /* BB_RAMP3 = 26dB */656(0 << 9) | 208, /* BB_RAMP4 */657(4 << 9) | 208, /* BB_RAMP5 = 29dB */658(0 << 9) | 440, /* BB_RAMP6 */659};660661static const u16 rf_ramp_pwm_cband_7090[] = {662280, /* max RF gain in 10th of dB */66318, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */664504, /* ramp_max = maximum X used on the ramp */665(29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */666(0 << 10) | 504, /* RF_RAMP6, LNA 1 */667(60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */668(0 << 10) | 364, /* RF_RAMP8, LNA 2 */669(34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */670(0 << 10) | 228, /* GAIN_4_2, LNA 3 */671(37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */672(0 << 10) | 109, /* RF_RAMP4, LNA 4 */673};674675static const u16 rf_ramp_pwm_cband_8090[] = {676345, /* max RF gain in 10th of dB */67729, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */6781000, /* ramp_max = maximum X used on the ramp */679(35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */680(0 << 10) | 1000, /* RF_RAMP4, LNA 1 */681(58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */682(0 << 10) | 772, /* RF_RAMP6, LNA 2 */683(27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */684(0 << 10) | 496, /* RF_RAMP8, LNA 3 */685(40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */686(0 << 10) | 200, /* GAIN_4_2, LNA 4 */687};688689static const u16 rf_ramp_pwm_uhf_7090[] = {690407, /* max RF gain in 10th of dB */69113, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */692529, /* ramp_max = maximum X used on the ramp */693(23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */694(0 << 10) | 176, /* RF_RAMP4, LNA 1 */695(63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */696(0 << 10) | 529, /* RF_RAMP6, LNA 2 */697(48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */698(0 << 10) | 400, /* RF_RAMP8, LNA 3 */699(29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */700(0 << 10) | 316, /* GAIN_4_2, LNA 4 */701};702703static const u16 rf_ramp_pwm_uhf_8090[] = {704388, /* max RF gain in 10th of dB */70526, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */7061008, /* ramp_max = maximum X used on the ramp */707(11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */708(0 << 10) | 369, /* RF_RAMP4, LNA 1 */709(41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */710(0 << 10) | 1008, /* RF_RAMP6, LNA 2 */711(27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */712(0 << 10) | 809, /* RF_RAMP8, LNA 3 */713(14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */714(0 << 10) | 659, /* GAIN_4_2, LNA 4 */715};716717static const u16 rf_ramp_pwm_cband[] = {7180, /* max RF gain in 10th of dB */7190, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */7200, /* ramp_max = maximum X used on the ramp */721(0 << 10) | 0, /* 0x2c, LNA 1 = 0dB */722(0 << 10) | 0, /* 0x2d, LNA 1 */723(0 << 10) | 0, /* 0x2e, LNA 2 = 0dB */724(0 << 10) | 0, /* 0x2f, LNA 2 */725(0 << 10) | 0, /* 0x30, LNA 3 = 0dB */726(0 << 10) | 0, /* 0x31, LNA 3 */727(0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */728(0 << 10) | 0, /* GAIN_4_2, LNA 4 */729};730731static const u16 rf_ramp_vhf[] = {732412, /* max RF gain in 10th of dB */733132, 307, 127, /* LNA1, 13.2dB */734105, 412, 255, /* LNA2, 10.5dB */73550, 50, 127, /* LNA3, 5dB */736125, 175, 127, /* LNA4, 12.5dB */7370, 0, 127, /* CBAND, 0dB */738};739740static const u16 rf_ramp_uhf[] = {741412, /* max RF gain in 10th of dB */742132, 307, 127, /* LNA1 : total gain = 13.2dB, point on the ramp where this amp is full gain, value to write to get full gain */743105, 412, 255, /* LNA2 : 10.5 dB */74450, 50, 127, /* LNA3 : 5.0 dB */745125, 175, 127, /* LNA4 : 12.5 dB */7460, 0, 127, /* CBAND : 0.0 dB */747};748749static const u16 rf_ramp_cband_broadmatching[] = /* for p1G only */750{751314, /* Calibrated at 200MHz order has been changed g4-g3-g2-g1 */75284, 314, 127, /* LNA1 */75380, 230, 255, /* LNA2 */75480, 150, 127, /* LNA3 It was measured 12dB, do not lock if 120 */75570, 70, 127, /* LNA4 */7560, 0, 127, /* CBAND */757};758759static const u16 rf_ramp_cband[] = {760332, /* max RF gain in 10th of dB */761132, 252, 127, /* LNA1, dB */76280, 332, 255, /* LNA2, dB */7630, 0, 127, /* LNA3, dB */7640, 0, 127, /* LNA4, dB */765120, 120, 127, /* LT1 CBAND */766};767768static const u16 rf_ramp_pwm_vhf[] = {769404, /* max RF gain in 10th of dB */77025, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */7711011, /* ramp_max = maximum X used on the ramp */772(6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */773(0 << 10) | 756, /* 0x2d, LNA 1 */774(16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */775(0 << 10) | 1011, /* 0x2f, LNA 2 */776(16 << 10) | 290, /* 0x30, LNA 3 = 5dB */777(0 << 10) | 417, /* 0x31, LNA 3 */778(7 << 10) | 0, /* GAIN_4_1, LNA 4 = 12.5dB */779(0 << 10) | 290, /* GAIN_4_2, LNA 4 */780};781782static const u16 rf_ramp_pwm_uhf[] = {783404, /* max RF gain in 10th of dB */78425, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */7851011, /* ramp_max = maximum X used on the ramp */786(6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */787(0 << 10) | 756, /* 0x2d, LNA 1 */788(16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */789(0 << 10) | 1011, /* 0x2f, LNA 2 */790(16 << 10) | 0, /* 0x30, LNA 3 = 5dB */791(0 << 10) | 127, /* 0x31, LNA 3 */792(7 << 10) | 127, /* GAIN_4_1, LNA 4 = 12.5dB */793(0 << 10) | 417, /* GAIN_4_2, LNA 4 */794};795796static const u16 bb_ramp_boost[] = {797550, /* max BB gain in 10th of dB */798260, 260, 26, /* BB1, 26dB */799290, 550, 29, /* BB2, 29dB */800};801802static const u16 bb_ramp_pwm_normal[] = {803500, /* max RF gain in 10th of dB */8048, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */805400,806(2 << 9) | 0, /* 0x35 = 21dB */807(0 << 9) | 168, /* 0x36 */808(2 << 9) | 168, /* 0x37 = 29dB */809(0 << 9) | 400, /* 0x38 */810};811812struct slope {813s16 range;814s16 slope;815};816static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val)817{818u8 i;819u16 rest;820u16 ret = 0;821for (i = 0; i < num; i++) {822if (val > slopes[i].range)823rest = slopes[i].range;824else825rest = val;826ret += (rest * slopes[i].slope) / slopes[i].range;827val -= rest;828}829return ret;830}831832static const struct slope dib0090_wbd_slopes[3] = {833{66, 120}, /* -64,-52: offset - 65 */834{600, 170}, /* -52,-35: 65 - 665 */835{170, 250}, /* -45,-10: 665 - 835 */836};837838static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd)839{840wbd &= 0x3ff;841if (wbd < state->wbd_offset)842wbd = 0;843else844wbd -= state->wbd_offset;845/* -64dB is the floor */846return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd);847}848849static void dib0090_wbd_target(struct dib0090_state *state, u32 rf)850{851u16 offset = 250;852853/* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */854855if (state->current_band == BAND_VHF)856offset = 650;857#ifndef FIRMWARE_FIREFLY858if (state->current_band == BAND_VHF)859offset = state->config->wbd_vhf_offset;860if (state->current_band == BAND_CBAND)861offset = state->config->wbd_cband_offset;862#endif863864state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset);865dprintk("wbd-target: %d dB", (u32) state->wbd_target);866}867868static const int gain_reg_addr[4] = {8690x08, 0x0a, 0x0f, 0x01870};871872static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force)873{874u16 rf, bb, ref;875u16 i, v, gain_reg[4] = { 0 }, gain;876const u16 *g;877878if (top_delta < -511)879top_delta = -511;880if (top_delta > 511)881top_delta = 511;882883if (force) {884top_delta *= (1 << WBD_ALPHA);885gain_delta *= (1 << GAIN_ALPHA);886}887888if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit)) /* overflow */889state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;890else891state->rf_gain_limit += top_delta;892893if (state->rf_gain_limit < 0) /*underflow */894state->rf_gain_limit = 0;895896/* use gain as a temporary variable and correct current_gain */897gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA;898if (gain_delta >= ((s16) gain - state->current_gain)) /* overflow */899state->current_gain = gain;900else901state->current_gain += gain_delta;902/* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */903if (state->current_gain < 0)904state->current_gain = 0;905906/* now split total gain to rf and bb gain */907gain = state->current_gain >> GAIN_ALPHA;908909/* requested gain is bigger than rf gain limit - ACI/WBD adjustment */910if (gain > (state->rf_gain_limit >> WBD_ALPHA)) {911rf = state->rf_gain_limit >> WBD_ALPHA;912bb = gain - rf;913if (bb > state->bb_ramp[0])914bb = state->bb_ramp[0];915} else { /* high signal level -> all gains put on RF */916rf = gain;917bb = 0;918}919920state->gain[0] = rf;921state->gain[1] = bb;922923/* software ramp */924/* Start with RF gains */925g = state->rf_ramp + 1; /* point on RF LNA1 max gain */926ref = rf;927for (i = 0; i < 7; i++) { /* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */928if (g[0] == 0 || ref < (g[1] - g[0])) /* if total gain of the current amp is null or this amp is not concerned because it starts to work from an higher gain value */929v = 0; /* force the gain to write for the current amp to be null */930else if (ref >= g[1]) /* Gain to set is higher than the high working point of this amp */931v = g[2]; /* force this amp to be full gain */932else /* compute the value to set to this amp because we are somewhere in his range */933v = ((ref - (g[1] - g[0])) * g[2]) / g[0];934935if (i == 0) /* LNA 1 reg mapping */936gain_reg[0] = v;937else if (i == 1) /* LNA 2 reg mapping */938gain_reg[0] |= v << 7;939else if (i == 2) /* LNA 3 reg mapping */940gain_reg[1] = v;941else if (i == 3) /* LNA 4 reg mapping */942gain_reg[1] |= v << 7;943else if (i == 4) /* CBAND LNA reg mapping */944gain_reg[2] = v | state->rf_lt_def;945else if (i == 5) /* BB gain 1 reg mapping */946gain_reg[3] = v << 3;947else if (i == 6) /* BB gain 2 reg mapping */948gain_reg[3] |= v << 8;949950g += 3; /* go to next gain bloc */951952/* When RF is finished, start with BB */953if (i == 4) {954g = state->bb_ramp + 1; /* point on BB gain 1 max gain */955ref = bb;956}957}958gain_reg[3] |= state->bb_1_def;959gain_reg[3] |= ((bb % 10) * 100) / 125;960961#ifdef DEBUG_AGC962dprintk("GA CALC: DB: %3d(rf) + %3d(bb) = %3d gain_reg[0]=%04x gain_reg[1]=%04x gain_reg[2]=%04x gain_reg[0]=%04x", rf, bb, rf + bb,963gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]);964#endif965966/* Write the amplifier regs */967for (i = 0; i < 4; i++) {968v = gain_reg[i];969if (force || state->gain_reg[i] != v) {970state->gain_reg[i] = v;971dib0090_write_reg(state, gain_reg_addr[i], v);972}973}974}975976static void dib0090_set_boost(struct dib0090_state *state, int onoff)977{978state->bb_1_def &= 0xdfff;979state->bb_1_def |= onoff << 13;980}981982static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg)983{984state->rf_ramp = cfg;985}986987static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg)988{989state->rf_ramp = cfg;990991dib0090_write_reg(state, 0x2a, 0xffff);992993dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a));994995dib0090_write_regs(state, 0x2c, cfg + 3, 6);996dib0090_write_regs(state, 0x3e, cfg + 9, 2);997}998999static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg)1000{1001state->bb_ramp = cfg;1002dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */1003}10041005static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)1006{1007state->bb_ramp = cfg;10081009dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */10101011dib0090_write_reg(state, 0x33, 0xffff);1012dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33));1013dib0090_write_regs(state, 0x35, cfg + 3, 4);1014}10151016void dib0090_pwm_gain_reset(struct dvb_frontend *fe)1017{1018struct dib0090_state *state = fe->tuner_priv;1019/* reset the AGC */10201021if (state->config->use_pwm_agc) {1022#ifdef CONFIG_BAND_SBAND1023if (state->current_band == BAND_SBAND) {1024dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband);1025dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost);1026} else1027#endif1028#ifdef CONFIG_BAND_CBAND1029if (state->current_band == BAND_CBAND) {1030if (state->identity.in_soc) {1031dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);1032if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)1033dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090);1034else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)1035dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090);1036} else {1037dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband);1038dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);1039}1040} else1041#endif1042#ifdef CONFIG_BAND_VHF1043if (state->current_band == BAND_VHF) {1044if (state->identity.in_soc) {1045dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);1046} else {1047dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf);1048dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);1049}1050} else1051#endif1052{1053if (state->identity.in_soc) {1054if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)1055dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_8090);1056else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)1057dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_7090);1058dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);1059} else {1060dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf);1061dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);1062}1063}10641065if (state->rf_ramp[0] != 0)1066dib0090_write_reg(state, 0x32, (3 << 11));1067else1068dib0090_write_reg(state, 0x32, (0 << 11));10691070dib0090_write_reg(state, 0x04, 0x01);1071dib0090_write_reg(state, 0x39, (1 << 10));1072}1073}10741075EXPORT_SYMBOL(dib0090_pwm_gain_reset);10761077static u32 dib0090_get_slow_adc_val(struct dib0090_state *state)1078{1079u16 adc_val = dib0090_read_reg(state, 0x1d);1080if (state->identity.in_soc)1081adc_val >>= 2;1082return adc_val;1083}10841085int dib0090_gain_control(struct dvb_frontend *fe)1086{1087struct dib0090_state *state = fe->tuner_priv;1088enum frontend_tune_state *tune_state = &state->tune_state;1089int ret = 10;10901091u16 wbd_val = 0;1092u8 apply_gain_immediatly = 1;1093s16 wbd_error = 0, adc_error = 0;10941095if (*tune_state == CT_AGC_START) {1096state->agc_freeze = 0;1097dib0090_write_reg(state, 0x04, 0x0);10981099#ifdef CONFIG_BAND_SBAND1100if (state->current_band == BAND_SBAND) {1101dib0090_set_rframp(state, rf_ramp_sband);1102dib0090_set_bbramp(state, bb_ramp_boost);1103} else1104#endif1105#ifdef CONFIG_BAND_VHF1106if (state->current_band == BAND_VHF && !state->identity.p1g) {1107dib0090_set_rframp(state, rf_ramp_vhf);1108dib0090_set_bbramp(state, bb_ramp_boost);1109} else1110#endif1111#ifdef CONFIG_BAND_CBAND1112if (state->current_band == BAND_CBAND && !state->identity.p1g) {1113dib0090_set_rframp(state, rf_ramp_cband);1114dib0090_set_bbramp(state, bb_ramp_boost);1115} else1116#endif1117if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) {1118dib0090_set_rframp(state, rf_ramp_cband_broadmatching);1119dib0090_set_bbramp(state, bb_ramp_boost);1120} else {1121dib0090_set_rframp(state, rf_ramp_uhf);1122dib0090_set_bbramp(state, bb_ramp_boost);1123}11241125dib0090_write_reg(state, 0x32, 0);1126dib0090_write_reg(state, 0x39, 0);11271128dib0090_wbd_target(state, state->current_rf);11291130state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;1131state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA;11321133*tune_state = CT_AGC_STEP_0;1134} else if (!state->agc_freeze) {1135s16 wbd = 0, i, cnt;11361137int adc;1138wbd_val = dib0090_get_slow_adc_val(state);11391140if (*tune_state == CT_AGC_STEP_0)1141cnt = 5;1142else1143cnt = 1;11441145for (i = 0; i < cnt; i++) {1146wbd_val = dib0090_get_slow_adc_val(state);1147wbd += dib0090_wbd_to_db(state, wbd_val);1148}1149wbd /= cnt;1150wbd_error = state->wbd_target - wbd;11511152if (*tune_state == CT_AGC_STEP_0) {1153if (wbd_error < 0 && state->rf_gain_limit > 0 && !state->identity.p1g) {1154#ifdef CONFIG_BAND_CBAND1155/* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */1156u8 ltg2 = (state->rf_lt_def >> 10) & 0x7;1157if (state->current_band == BAND_CBAND && ltg2) {1158ltg2 >>= 1;1159state->rf_lt_def &= ltg2 << 10; /* reduce in 3 steps from 7 to 0 */1160}1161#endif1162} else {1163state->agc_step = 0;1164*tune_state = CT_AGC_STEP_1;1165}1166} else {1167/* calc the adc power */1168adc = state->config->get_adc_power(fe);1169adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21; /* included in [0:-700] */11701171adc_error = (s16) (((s32) ADC_TARGET) - adc);1172#ifdef CONFIG_STANDARD_DAB1173if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB)1174adc_error -= 10;1175#endif1176#ifdef CONFIG_STANDARD_DVBT1177if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT &&1178(state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16))1179adc_error += 60;1180#endif1181#ifdef CONFIG_SYS_ISDBT1182if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) && (((state->fe->dtv_property_cache.layer[0].segment_count >11830)1184&&1185((state->fe->dtv_property_cache.layer[0].modulation ==1186QAM_64)1187|| (state->fe->dtv_property_cache.1188layer[0].modulation == QAM_16)))1189||1190((state->fe->dtv_property_cache.layer[1].segment_count >11910)1192&&1193((state->fe->dtv_property_cache.layer[1].modulation ==1194QAM_64)1195|| (state->fe->dtv_property_cache.1196layer[1].modulation == QAM_16)))1197||1198((state->fe->dtv_property_cache.layer[2].segment_count >11990)1200&&1201((state->fe->dtv_property_cache.layer[2].modulation ==1202QAM_64)1203|| (state->fe->dtv_property_cache.1204layer[2].modulation == QAM_16)))1205)1206)1207adc_error += 60;1208#endif12091210if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */1211if (ABS(adc_error) < 50 || state->agc_step++ > 5) {12121213#ifdef CONFIG_STANDARD_DAB1214if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) {1215dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63)); /* cap value = 63 : narrow BB filter : Fc = 1.8MHz */1216dib0090_write_reg(state, 0x04, 0x0);1217} else1218#endif1219{1220dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32));1221dib0090_write_reg(state, 0x04, 0x01); /*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */1222}12231224*tune_state = CT_AGC_STOP;1225}1226} else {1227/* everything higher than or equal to CT_AGC_STOP means tracking */1228ret = 100; /* 10ms interval */1229apply_gain_immediatly = 0;1230}1231}1232#ifdef DEBUG_AGC1233dprintk1234("tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm",1235(u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val,1236(u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA));1237#endif1238}12391240/* apply gain */1241if (!state->agc_freeze)1242dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly);1243return ret;1244}12451246EXPORT_SYMBOL(dib0090_gain_control);12471248void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)1249{1250struct dib0090_state *state = fe->tuner_priv;1251if (rf)1252*rf = state->gain[0];1253if (bb)1254*bb = state->gain[1];1255if (rf_gain_limit)1256*rf_gain_limit = state->rf_gain_limit;1257if (rflt)1258*rflt = (state->rf_lt_def >> 10) & 0x7;1259}12601261EXPORT_SYMBOL(dib0090_get_current_gain);12621263u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)1264{1265struct dib0090_state *state = fe->tuner_priv;1266u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000;1267s32 current_temp = state->temperature;1268s32 wbd_thot, wbd_tcold;1269const struct dib0090_wbd_slope *wbd = state->current_wbd_table;12701271while (f_MHz > wbd->max_freq)1272wbd++;12731274dprintk("using wbd-table-entry with max freq %d", wbd->max_freq);12751276if (current_temp < 0)1277current_temp = 0;1278if (current_temp > 128)1279current_temp = 128;12801281state->wbdmux &= ~(7 << 13);1282if (wbd->wbd_gain != 0)1283state->wbdmux |= (wbd->wbd_gain << 13);1284else1285state->wbdmux |= (4 << 13);12861287dib0090_write_reg(state, 0x10, state->wbdmux);12881289wbd_thot = wbd->offset_hot - (((u32) wbd->slope_hot * f_MHz) >> 6);1290wbd_tcold = wbd->offset_cold - (((u32) wbd->slope_cold * f_MHz) >> 6);12911292wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7;12931294state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold);1295dprintk("wbd-target: %d dB", (u32) state->wbd_target);1296dprintk("wbd offset applied is %d", wbd_tcold);12971298return state->wbd_offset + wbd_tcold;1299}13001301EXPORT_SYMBOL(dib0090_get_wbd_offset);13021303static const u16 dib0090_defaults[] = {1304130525, 0x01,13060x0000,13070x99a0,13080x6008,13090x0000,13100x8bcb,13110x0000,13120x0405,13130x0000,13140x0000,13150x0000,13160xb802,13170x0300,13180x2d12,13190xbac0,13200x7c00,13210xdbb9,13220x0954,13230x0743,13240x8000,13250x0001,13260x0040,13270x0100,13280x0000,13290xe910,13300x149e,133113321, 0x1c,13330xff2d,133413351, 0x39,13360x0000,133713382, 0x1e,13390x07FF,13400x0007,134113421, 0x24,1343EN_UHF | EN_CRYSTAL,134413452, 0x3c,13460x3ff,13470x111,134801349};13501351static const u16 dib0090_p1g_additionnal_defaults[] = {13521, 0x05,13530xabcd,135413551, 0x11,13560x00b4,135713581, 0x1c,13590xfffd,136013611, 0x40,13620x108,136301364};13651366static void dib0090_set_default_config(struct dib0090_state *state, const u16 * n)1367{1368u16 l, r;13691370l = pgm_read_word(n++);1371while (l) {1372r = pgm_read_word(n++);1373do {1374dib0090_write_reg(state, r, pgm_read_word(n++));1375r++;1376} while (--l);1377l = pgm_read_word(n++);1378}1379}13801381#define CAP_VALUE_MIN (u8) 91382#define CAP_VALUE_MAX (u8) 401383#define HR_MIN (u8) 251384#define HR_MAX (u8) 401385#define POLY_MIN (u8) 01386#define POLY_MAX (u8) 813871388void dib0090_set_EFUSE(struct dib0090_state *state)1389{1390u8 c, h, n;1391u16 e2, e4;1392u16 cal;13931394e2 = dib0090_read_reg(state, 0x26);1395e4 = dib0090_read_reg(state, 0x28);13961397if ((state->identity.version == P1D_E_F) ||1398(state->identity.version == P1G) || (e2 == 0xffff)) {13991400dib0090_write_reg(state, 0x22, 0x10);1401cal = (dib0090_read_reg(state, 0x22) >> 6) & 0x3ff;14021403if ((cal < 670) || (cal == 1023))1404cal = 850;1405n = 165 - ((cal * 10)>>6) ;1406e2 = e4 = (3<<12) | (34<<6) | (n);1407}14081409if (e2 != e4)1410e2 &= e4; /* Remove the redundancy */14111412if (e2 != 0xffff) {1413c = e2 & 0x3f;1414n = (e2 >> 12) & 0xf;1415h = (e2 >> 6) & 0x3f;14161417if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN))1418c = 32;1419if ((h >= HR_MAX) || (h <= HR_MIN))1420h = 34;1421if ((n >= POLY_MAX) || (n <= POLY_MIN))1422n = 3;14231424dib0090_write_reg(state, 0x13, (h << 10)) ;1425e2 = (n<<11) | ((h>>2)<<6) | (c);1426dib0090_write_reg(state, 0x2, e2) ; /* Load the BB_2 */1427}1428}14291430static int dib0090_reset(struct dvb_frontend *fe)1431{1432struct dib0090_state *state = fe->tuner_priv;14331434dib0090_reset_digital(fe, state->config);1435if (dib0090_identify(fe) < 0)1436return -EIO;14371438#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT1439if (!(state->identity.version & 0x1)) /* it is P1B - reset is already done */1440return 0;1441#endif14421443if (!state->identity.in_soc) {1444if ((dib0090_read_reg(state, 0x1a) >> 5) & 0x2)1445dib0090_write_reg(state, 0x1b, (EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL));1446else1447dib0090_write_reg(state, 0x1b, (EN_DIGCLK | EN_PLL | EN_CRYSTAL));1448}14491450dib0090_set_default_config(state, dib0090_defaults);14511452if (state->identity.in_soc)1453dib0090_write_reg(state, 0x18, 0x2910); /* charge pump current = 0 */14541455if (state->identity.p1g)1456dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults);14571458/* Update the efuse : Only available for KROSUS > P1C and SOC as well*/1459if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc))1460dib0090_set_EFUSE(state);14611462/* Congigure in function of the crystal */1463if (state->config->io.clock_khz >= 24000)1464dib0090_write_reg(state, 0x14, 1);1465else1466dib0090_write_reg(state, 0x14, 2);1467dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1);14681469state->calibrate = DC_CAL | WBD_CAL | TEMP_CAL; /* enable iq-offset-calibration and wbd-calibration when tuning next time */14701471return 0;1472}14731474#define steps(u) (((u) > 15) ? ((u)-16) : (u))1475#define INTERN_WAIT 101476static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state)1477{1478int ret = INTERN_WAIT * 10;14791480switch (*tune_state) {1481case CT_TUNER_STEP_2:1482/* Turns to positive */1483dib0090_write_reg(state, 0x1f, 0x7);1484*tune_state = CT_TUNER_STEP_3;1485break;14861487case CT_TUNER_STEP_3:1488state->adc_diff = dib0090_read_reg(state, 0x1d);14891490/* Turns to negative */1491dib0090_write_reg(state, 0x1f, 0x4);1492*tune_state = CT_TUNER_STEP_4;1493break;14941495case CT_TUNER_STEP_4:1496state->adc_diff -= dib0090_read_reg(state, 0x1d);1497*tune_state = CT_TUNER_STEP_5;1498ret = 0;1499break;15001501default:1502break;1503}15041505return ret;1506}15071508struct dc_calibration {1509u8 addr;1510u8 offset;1511u8 pga:1;1512u16 bb1;1513u8 i:1;1514};15151516static const struct dc_calibration dc_table[] = {1517/* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */1518{0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1},1519{0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0},1520/* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */1521{0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1},1522{0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0},1523{0},1524};15251526static const struct dc_calibration dc_p1g_table[] = {1527/* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */1528/* addr ; trim reg offset ; pga ; CTRL_BB1 value ; i or q */1529{0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1},1530{0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0},1531/* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */1532{0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1},1533{0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0},1534{0},1535};15361537static void dib0090_set_trim(struct dib0090_state *state)1538{1539u16 *val;15401541if (state->dc->addr == 0x07)1542val = &state->bb7;1543else1544val = &state->bb6;15451546*val &= ~(0x1f << state->dc->offset);1547*val |= state->step << state->dc->offset;15481549dib0090_write_reg(state, state->dc->addr, *val);1550}15511552static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)1553{1554int ret = 0;1555u16 reg;15561557switch (*tune_state) {1558case CT_TUNER_START:1559dprintk("Start DC offset calibration");15601561/* force vcm2 = 0.8V */1562state->bb6 = 0;1563state->bb7 = 0x040d;15641565/* the LNA AND LO are off */1566reg = dib0090_read_reg(state, 0x24) & 0x0ffb; /* shutdown lna and lo */1567dib0090_write_reg(state, 0x24, reg);15681569state->wbdmux = dib0090_read_reg(state, 0x10);1570dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3);1571dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));15721573state->dc = dc_table;15741575if (state->identity.p1g)1576state->dc = dc_p1g_table;1577*tune_state = CT_TUNER_STEP_0;15781579/* fall through */15801581case CT_TUNER_STEP_0:1582dprintk("Sart/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q");1583dib0090_write_reg(state, 0x01, state->dc->bb1);1584dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7));15851586state->step = 0;1587state->min_adc_diff = 1023;1588*tune_state = CT_TUNER_STEP_1;1589ret = 50;1590break;15911592case CT_TUNER_STEP_1:1593dib0090_set_trim(state);1594*tune_state = CT_TUNER_STEP_2;1595break;15961597case CT_TUNER_STEP_2:1598case CT_TUNER_STEP_3:1599case CT_TUNER_STEP_4:1600ret = dib0090_get_offset(state, tune_state);1601break;16021603case CT_TUNER_STEP_5: /* found an offset */1604dprintk("adc_diff = %d, current step= %d", (u32) state->adc_diff, state->step);1605if (state->step == 0 && state->adc_diff < 0) {1606state->min_adc_diff = -1023;1607dprintk("Change of sign of the minimum adc diff");1608}16091610dprintk("adc_diff = %d, min_adc_diff = %d current_step = %d", state->adc_diff, state->min_adc_diff, state->step);16111612/* first turn for this frequency */1613if (state->step == 0) {1614if (state->dc->pga && state->adc_diff < 0)1615state->step = 0x10;1616if (state->dc->pga == 0 && state->adc_diff > 0)1617state->step = 0x10;1618}16191620/* Look for a change of Sign in the Adc_diff.min_adc_diff is used to STORE the setp N-1 */1621if ((state->adc_diff & 0x8000) == (state->min_adc_diff & 0x8000) && steps(state->step) < 15) {1622/* stop search when the delta the sign is changing and Steps =15 and Step=0 is force for continuance */1623state->step++;1624state->min_adc_diff = state->adc_diff;1625*tune_state = CT_TUNER_STEP_1;1626} else {1627/* the minimum was what we have seen in the step before */1628if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) {1629dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step", state->adc_diff, state->min_adc_diff);1630state->step--;1631}16321633dib0090_set_trim(state);1634dprintk("BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->dc->addr, state->adc_diff, state->step);16351636state->dc++;1637if (state->dc->addr == 0) /* done */1638*tune_state = CT_TUNER_STEP_6;1639else1640*tune_state = CT_TUNER_STEP_0;16411642}1643break;16441645case CT_TUNER_STEP_6:1646dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008);1647dib0090_write_reg(state, 0x1f, 0x7);1648*tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */1649state->calibrate &= ~DC_CAL;1650default:1651break;1652}1653return ret;1654}16551656static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)1657{1658u8 wbd_gain;1659const struct dib0090_wbd_slope *wbd = state->current_wbd_table;16601661switch (*tune_state) {1662case CT_TUNER_START:1663while (state->current_rf / 1000 > wbd->max_freq)1664wbd++;1665if (wbd->wbd_gain != 0)1666wbd_gain = wbd->wbd_gain;1667else {1668wbd_gain = 4;1669#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND)1670if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND))1671wbd_gain = 2;1672#endif1673}16741675if (wbd_gain == state->wbd_calibration_gain) { /* the WBD calibration has already been done */1676*tune_state = CT_TUNER_START;1677state->calibrate &= ~WBD_CAL;1678return 0;1679}16801681dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3));16821683dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1)));1684*tune_state = CT_TUNER_STEP_0;1685state->wbd_calibration_gain = wbd_gain;1686return 90; /* wait for the WBDMUX to switch and for the ADC to sample */16871688case CT_TUNER_STEP_0:1689state->wbd_offset = dib0090_get_slow_adc_val(state);1690dprintk("WBD calibration offset = %d", state->wbd_offset);1691*tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */1692state->calibrate &= ~WBD_CAL;1693break;16941695default:1696break;1697}1698return 0;1699}17001701static void dib0090_set_bandwidth(struct dib0090_state *state)1702{1703u16 tmp;17041705if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000)1706tmp = (3 << 14);1707else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000)1708tmp = (2 << 14);1709else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000)1710tmp = (1 << 14);1711else1712tmp = (0 << 14);17131714state->bb_1_def &= 0x3fff;1715state->bb_1_def |= tmp;17161717dib0090_write_reg(state, 0x01, state->bb_1_def); /* be sure that we have the right bb-filter */17181719dib0090_write_reg(state, 0x03, 0x6008); /* = 0x6008 : vcm3_trim = 1 ; filter2_gm1_trim = 8 ; filter2_cutoff_freq = 0 */1720dib0090_write_reg(state, 0x04, 0x1); /* 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast */1721if (state->identity.in_soc) {1722dib0090_write_reg(state, 0x05, 0x9bcf); /* attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 1 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 15 */1723} else {1724dib0090_write_reg(state, 0x02, (5 << 11) | (8 << 6) | (22 & 0x3f)); /* 22 = cap_value */1725dib0090_write_reg(state, 0x05, 0xabcd); /* = 0xabcd : attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 2 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 13 */1726}1727}17281729static const struct dib0090_pll dib0090_pll_table[] = {1730#ifdef CONFIG_BAND_CBAND1731{56000, 0, 9, 48, 6},1732{70000, 1, 9, 48, 6},1733{87000, 0, 8, 32, 4},1734{105000, 1, 8, 32, 4},1735{115000, 0, 7, 24, 6},1736{140000, 1, 7, 24, 6},1737{170000, 0, 6, 16, 4},1738#endif1739#ifdef CONFIG_BAND_VHF1740{200000, 1, 6, 16, 4},1741{230000, 0, 5, 12, 6},1742{280000, 1, 5, 12, 6},1743{340000, 0, 4, 8, 4},1744{380000, 1, 4, 8, 4},1745{450000, 0, 3, 6, 6},1746#endif1747#ifdef CONFIG_BAND_UHF1748{580000, 1, 3, 6, 6},1749{700000, 0, 2, 4, 4},1750{860000, 1, 2, 4, 4},1751#endif1752#ifdef CONFIG_BAND_LBAND1753{1800000, 1, 0, 2, 4},1754#endif1755#ifdef CONFIG_BAND_SBAND1756{2900000, 0, 14, 1, 4},1757#endif1758};17591760static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = {17611762#ifdef CONFIG_BAND_CBAND1763{184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},1764{227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB},1765{380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB},1766#endif1767#ifdef CONFIG_BAND_UHF1768{520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1769{550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1770{650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1771{750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1772{850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1773{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1774#endif1775#ifdef CONFIG_BAND_LBAND1776{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},1777{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},1778{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},1779#endif1780#ifdef CONFIG_BAND_SBAND1781{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},1782{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},1783#endif1784};17851786static const struct dib0090_tuning dib0090_tuning_table[] = {17871788#ifdef CONFIG_BAND_CBAND1789{170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},1790#endif1791#ifdef CONFIG_BAND_VHF1792{184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},1793{227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},1794{380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},1795#endif1796#ifdef CONFIG_BAND_UHF1797{520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1798{550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1799{650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1800{750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1801{850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1802{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1803#endif1804#ifdef CONFIG_BAND_LBAND1805{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},1806{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},1807{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},1808#endif1809#ifdef CONFIG_BAND_SBAND1810{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},1811{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},1812#endif1813};18141815static const struct dib0090_tuning dib0090_p1g_tuning_table[] = {1816#ifdef CONFIG_BAND_CBAND1817{170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB},1818#endif1819#ifdef CONFIG_BAND_VHF1820{184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},1821{227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},1822{380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},1823#endif1824#ifdef CONFIG_BAND_UHF1825{510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1826{540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1827{600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1828{630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1829{680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1830{720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1831{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1832#endif1833#ifdef CONFIG_BAND_LBAND1834{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},1835{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},1836{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},1837#endif1838#ifdef CONFIG_BAND_SBAND1839{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},1840{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},1841#endif1842};18431844static const struct dib0090_pll dib0090_p1g_pll_table[] = {1845#ifdef CONFIG_BAND_CBAND1846{57000, 0, 11, 48, 6},1847{70000, 1, 11, 48, 6},1848{86000, 0, 10, 32, 4},1849{105000, 1, 10, 32, 4},1850{115000, 0, 9, 24, 6},1851{140000, 1, 9, 24, 6},1852{170000, 0, 8, 16, 4},1853#endif1854#ifdef CONFIG_BAND_VHF1855{200000, 1, 8, 16, 4},1856{230000, 0, 7, 12, 6},1857{280000, 1, 7, 12, 6},1858{340000, 0, 6, 8, 4},1859{380000, 1, 6, 8, 4},1860{455000, 0, 5, 6, 6},1861#endif1862#ifdef CONFIG_BAND_UHF1863{580000, 1, 5, 6, 6},1864{680000, 0, 4, 4, 4},1865{860000, 1, 4, 4, 4},1866#endif1867#ifdef CONFIG_BAND_LBAND1868{1800000, 1, 2, 2, 4},1869#endif1870#ifdef CONFIG_BAND_SBAND1871{2900000, 0, 1, 1, 6},1872#endif1873};18741875static const struct dib0090_tuning dib0090_p1g_tuning_table_fm_vhf_on_cband[] = {1876#ifdef CONFIG_BAND_CBAND1877{184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},1878{227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},1879{380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},1880#endif1881#ifdef CONFIG_BAND_UHF1882{520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1883{550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1884{650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1885{750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1886{850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1887{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},1888#endif1889#ifdef CONFIG_BAND_LBAND1890{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},1891{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},1892{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},1893#endif1894#ifdef CONFIG_BAND_SBAND1895{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},1896{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},1897#endif1898};18991900static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = {1901#ifdef CONFIG_BAND_CBAND1902{300000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},1903{380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},1904{570000, 4, 10, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},1905{858000, 4, 5, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},1906#endif1907};19081909static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state)1910{1911int ret = 0;1912u16 lo4 = 0xe900;19131914s16 adc_target;1915u16 adc;1916s8 step_sign;1917u8 force_soft_search = 0;19181919if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)1920force_soft_search = 1;19211922if (*tune_state == CT_TUNER_START) {1923dprintk("Start Captrim search : %s", (force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO");1924dib0090_write_reg(state, 0x10, 0x2B1);1925dib0090_write_reg(state, 0x1e, 0x0032);19261927if (!state->tuner_is_tuned) {1928/* prepare a complete captrim */1929if (!state->identity.p1g || force_soft_search)1930state->step = state->captrim = state->fcaptrim = 64;19311932state->current_rf = state->rf_request;1933} else { /* we are already tuned to this frequency - the configuration is correct */1934if (!state->identity.p1g || force_soft_search) {1935/* do a minimal captrim even if the frequency has not changed */1936state->step = 4;1937state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f;1938}1939}1940state->adc_diff = 3000;1941*tune_state = CT_TUNER_STEP_0;19421943} else if (*tune_state == CT_TUNER_STEP_0) {1944if (state->identity.p1g && !force_soft_search) {1945u8 ratio = 31;19461947dib0090_write_reg(state, 0x40, (3 << 7) | (ratio << 2) | (1 << 1) | 1);1948dib0090_read_reg(state, 0x40);1949ret = 50;1950} else {1951state->step /= 2;1952dib0090_write_reg(state, 0x18, lo4 | state->captrim);19531954if (state->identity.in_soc)1955ret = 25;1956}1957*tune_state = CT_TUNER_STEP_1;19581959} else if (*tune_state == CT_TUNER_STEP_1) {1960if (state->identity.p1g && !force_soft_search) {1961dib0090_write_reg(state, 0x40, 0x18c | (0 << 1) | 0);1962dib0090_read_reg(state, 0x40);19631964state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F;1965dprintk("***Final Captrim= 0x%x", state->fcaptrim);1966*tune_state = CT_TUNER_STEP_3;19671968} else {1969/* MERGE for all krosus before P1G */1970adc = dib0090_get_slow_adc_val(state);1971dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024);19721973if (state->rest == 0 || state->identity.in_soc) { /* Just for 8090P SOCS where auto captrim HW bug : TO CHECK IN ACI for SOCS !!! if 400 for 8090p SOC => tune issue !!! */1974adc_target = 200;1975} else1976adc_target = 400;19771978if (adc >= adc_target) {1979adc -= adc_target;1980step_sign = -1;1981} else {1982adc = adc_target - adc;1983step_sign = 1;1984}19851986if (adc < state->adc_diff) {1987dprintk("CAPTRIM=%d is closer to target (%d/%d)", (u32) state->captrim, (u32) adc, (u32) state->adc_diff);1988state->adc_diff = adc;1989state->fcaptrim = state->captrim;1990}19911992state->captrim += step_sign * state->step;1993if (state->step >= 1)1994*tune_state = CT_TUNER_STEP_0;1995else1996*tune_state = CT_TUNER_STEP_2;19971998ret = 25;1999}2000} else if (*tune_state == CT_TUNER_STEP_2) { /* this step is only used by krosus < P1G */2001/*write the final cptrim config */2002dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim);20032004*tune_state = CT_TUNER_STEP_3;20052006} else if (*tune_state == CT_TUNER_STEP_3) {2007state->calibrate &= ~CAPTRIM_CAL;2008*tune_state = CT_TUNER_STEP_0;2009}20102011return ret;2012}20132014static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tune_state *tune_state)2015{2016int ret = 15;2017s16 val;20182019switch (*tune_state) {2020case CT_TUNER_START:2021state->wbdmux = dib0090_read_reg(state, 0x10);2022dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3));20232024state->bias = dib0090_read_reg(state, 0x13);2025dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8));20262027*tune_state = CT_TUNER_STEP_0;2028/* wait for the WBDMUX to switch and for the ADC to sample */2029break;20302031case CT_TUNER_STEP_0:2032state->adc_diff = dib0090_get_slow_adc_val(state);2033dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8));2034*tune_state = CT_TUNER_STEP_1;2035break;20362037case CT_TUNER_STEP_1:2038val = dib0090_get_slow_adc_val(state);2039state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55;20402041dprintk("temperature: %d C", state->temperature - 30);20422043*tune_state = CT_TUNER_STEP_2;2044break;20452046case CT_TUNER_STEP_2:2047dib0090_write_reg(state, 0x13, state->bias);2048dib0090_write_reg(state, 0x10, state->wbdmux); /* write back original WBDMUX */20492050*tune_state = CT_TUNER_START;2051state->calibrate &= ~TEMP_CAL;2052if (state->config->analog_output == 0)2053dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));20542055break;20562057default:2058ret = 0;2059break;2060}2061return ret;2062}20632064#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */2065static int dib0090_tune(struct dvb_frontend *fe)2066{2067struct dib0090_state *state = fe->tuner_priv;2068const struct dib0090_tuning *tune = state->current_tune_table_index;2069const struct dib0090_pll *pll = state->current_pll_table_index;2070enum frontend_tune_state *tune_state = &state->tune_state;20712072u16 lo5, lo6, Den, tmp;2073u32 FBDiv, Rest, FREF, VCOF_kHz = 0;2074int ret = 10; /* 1ms is the default delay most of the time */2075u8 c, i;20762077/************************* VCO ***************************/2078/* Default values for FG */2079/* from these are needed : */2080/* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv */20812082/* in any case we first need to do a calibration if needed */2083if (*tune_state == CT_TUNER_START) {2084/* deactivate DataTX before some calibrations */2085if (state->calibrate & (DC_CAL | TEMP_CAL | WBD_CAL))2086dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));2087else2088/* Activate DataTX in case a calibration has been done before */2089if (state->config->analog_output == 0)2090dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));2091}20922093if (state->calibrate & DC_CAL)2094return dib0090_dc_offset_calibration(state, tune_state);2095else if (state->calibrate & WBD_CAL) {2096if (state->current_rf == 0)2097state->current_rf = state->fe->dtv_property_cache.frequency / 1000;2098return dib0090_wbd_calibration(state, tune_state);2099} else if (state->calibrate & TEMP_CAL)2100return dib0090_get_temperature(state, tune_state);2101else if (state->calibrate & CAPTRIM_CAL)2102return dib0090_captrim_search(state, tune_state);21032104if (*tune_state == CT_TUNER_START) {2105/* if soc and AGC pwm control, disengage mux to be able to R/W access to 0x01 register to set the right filter (cutoff_freq_select) during the tune sequence, otherwise, SOC SERPAR error when accessing to 0x01 */2106if (state->config->use_pwm_agc && state->identity.in_soc) {2107tmp = dib0090_read_reg(state, 0x39);2108if ((tmp >> 10) & 0x1)2109dib0090_write_reg(state, 0x39, tmp & ~(1 << 10));2110}21112112state->current_band = (u8) BAND_OF_FREQUENCY(state->fe->dtv_property_cache.frequency / 1000);2113state->rf_request =2114state->fe->dtv_property_cache.frequency / 1000 + (state->current_band ==2115BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->2116freq_offset_khz_vhf);21172118/* in ISDB-T 1seg we shift tuning frequency */2119if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 12120&& state->fe->dtv_property_cache.isdbt_partial_reception == 0)) {2121const struct dib0090_low_if_offset_table *LUT_offset = state->config->low_if;2122u8 found_offset = 0;2123u32 margin_khz = 100;21242125if (LUT_offset != NULL) {2126while (LUT_offset->RF_freq != 0xffff) {2127if (((state->rf_request > (LUT_offset->RF_freq - margin_khz))2128&& (state->rf_request < (LUT_offset->RF_freq + margin_khz)))2129&& LUT_offset->std == state->fe->dtv_property_cache.delivery_system) {2130state->rf_request += LUT_offset->offset_khz;2131found_offset = 1;2132break;2133}2134LUT_offset++;2135}2136}21372138if (found_offset == 0)2139state->rf_request += 400;2140}2141if (state->current_rf != state->rf_request || (state->current_standard != state->fe->dtv_property_cache.delivery_system)) {2142state->tuner_is_tuned = 0;2143state->current_rf = 0;2144state->current_standard = 0;21452146tune = dib0090_tuning_table;2147if (state->identity.p1g)2148tune = dib0090_p1g_tuning_table;21492150tmp = (state->identity.version >> 5) & 0x7;21512152if (state->identity.in_soc) {2153if (state->config->force_cband_input) { /* Use the CBAND input for all band */2154if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF2155|| state->current_band & BAND_UHF) {2156state->current_band = BAND_CBAND;2157tune = dib0090_tuning_table_cband_7090;2158}2159} else { /* Use the CBAND input for all band under UHF */2160if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) {2161state->current_band = BAND_CBAND;2162tune = dib0090_tuning_table_cband_7090;2163}2164}2165} else2166if (tmp == 0x4 || tmp == 0x7) {2167/* CBAND tuner version for VHF */2168if (state->current_band == BAND_FM || state->current_band == BAND_CBAND || state->current_band == BAND_VHF) {2169state->current_band = BAND_CBAND; /* Force CBAND */21702171tune = dib0090_tuning_table_fm_vhf_on_cband;2172if (state->identity.p1g)2173tune = dib0090_p1g_tuning_table_fm_vhf_on_cband;2174}2175}21762177pll = dib0090_pll_table;2178if (state->identity.p1g)2179pll = dib0090_p1g_pll_table;21802181/* Look for the interval */2182while (state->rf_request > tune->max_freq)2183tune++;2184while (state->rf_request > pll->max_freq)2185pll++;21862187state->current_tune_table_index = tune;2188state->current_pll_table_index = pll;21892190dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim));21912192VCOF_kHz = (pll->hfdiv * state->rf_request) * 2;21932194FREF = state->config->io.clock_khz;2195if (state->config->fref_clock_ratio != 0)2196FREF /= state->config->fref_clock_ratio;21972198FBDiv = (VCOF_kHz / pll->topresc / FREF);2199Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF;22002201if (Rest < LPF)2202Rest = 0;2203else if (Rest < 2 * LPF)2204Rest = 2 * LPF;2205else if (Rest > (FREF - LPF)) {2206Rest = 0;2207FBDiv += 1;2208} else if (Rest > (FREF - 2 * LPF))2209Rest = FREF - 2 * LPF;2210Rest = (Rest * 6528) / (FREF / 10);2211state->rest = Rest;22122213/* external loop filter, otherwise:2214* lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4;2215* lo6 = 0x0e34 */22162217if (Rest == 0) {2218if (pll->vco_band)2219lo5 = 0x049f;2220else2221lo5 = 0x041f;2222} else {2223if (pll->vco_band)2224lo5 = 0x049e;2225else if (state->config->analog_output)2226lo5 = 0x041d;2227else2228lo5 = 0x041c;2229}22302231if (state->identity.p1g) { /* Bias is done automatically in P1G */2232if (state->identity.in_soc) {2233if (state->identity.version == SOC_8090_P1G_11R1)2234lo5 = 0x46f;2235else2236lo5 = 0x42f;2237} else2238lo5 = 0x42c;2239}22402241lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */22422243if (!state->config->io.pll_int_loop_filt) {2244if (state->identity.in_soc)2245lo6 = 0xff98;2246else if (state->identity.p1g || (Rest == 0))2247lo6 = 0xfff8;2248else2249lo6 = 0xff28;2250} else2251lo6 = (state->config->io.pll_int_loop_filt << 3);22522253Den = 1;22542255if (Rest > 0) {2256if (state->config->analog_output)2257lo6 |= (1 << 2) | 2;2258else {2259if (state->identity.in_soc)2260lo6 |= (1 << 2) | 2;2261else2262lo6 |= (1 << 2) | 2;2263}2264Den = 255;2265}2266dib0090_write_reg(state, 0x15, (u16) FBDiv);2267if (state->config->fref_clock_ratio != 0)2268dib0090_write_reg(state, 0x16, (Den << 8) | state->config->fref_clock_ratio);2269else2270dib0090_write_reg(state, 0x16, (Den << 8) | 1);2271dib0090_write_reg(state, 0x17, (u16) Rest);2272dib0090_write_reg(state, 0x19, lo5);2273dib0090_write_reg(state, 0x1c, lo6);22742275lo6 = tune->tuner_enable;2276if (state->config->analog_output)2277lo6 = (lo6 & 0xff9f) | 0x2;22782279dib0090_write_reg(state, 0x24, lo6 | EN_LO | state->config->use_pwm_agc * EN_CRYSTAL);22802281}22822283state->current_rf = state->rf_request;2284state->current_standard = state->fe->dtv_property_cache.delivery_system;22852286ret = 20;2287state->calibrate = CAPTRIM_CAL; /* captrim serach now */2288}22892290else if (*tune_state == CT_TUNER_STEP_0) { /* Warning : because of captrim cal, if you change this step, change it also in _cal.c file because it is the step following captrim cal state machine */2291const struct dib0090_wbd_slope *wbd = state->current_wbd_table;22922293while (state->current_rf / 1000 > wbd->max_freq)2294wbd++;22952296dib0090_write_reg(state, 0x1e, 0x07ff);2297dprintk("Final Captrim: %d", (u32) state->fcaptrim);2298dprintk("HFDIV code: %d", (u32) pll->hfdiv_code);2299dprintk("VCO = %d", (u32) pll->vco_band);2300dprintk("VCOF in kHz: %d ((%d*%d) << 1))", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request);2301dprintk("REFDIV: %d, FREF: %d", (u32) 1, (u32) state->config->io.clock_khz);2302dprintk("FBDIV: %d, Rest: %d", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17));2303dprintk("Num: %d, Den: %d, SD: %d", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8),2304(u32) dib0090_read_reg(state, 0x1c) & 0x3);23052306#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */2307c = 4;2308i = 3;23092310if (wbd->wbd_gain != 0)2311c = wbd->wbd_gain;23122313state->wbdmux = (c << 13) | (i << 11) | (WBD | (state->config->use_pwm_agc << 1));2314dib0090_write_reg(state, 0x10, state->wbdmux);23152316if ((tune->tuner_enable == EN_CAB) && state->identity.p1g) {2317dprintk("P1G : The cable band is selected and lna_tune = %d", tune->lna_tune);2318dib0090_write_reg(state, 0x09, tune->lna_bias);2319dib0090_write_reg(state, 0x0b, 0xb800 | (tune->lna_tune << 6) | (tune->switch_trim));2320} else2321dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | tune->lna_bias);23222323dib0090_write_reg(state, 0x0c, tune->v2i);2324dib0090_write_reg(state, 0x0d, tune->mix);2325dib0090_write_reg(state, 0x0e, tune->load);2326*tune_state = CT_TUNER_STEP_1;23272328} else if (*tune_state == CT_TUNER_STEP_1) {2329/* initialize the lt gain register */2330state->rf_lt_def = 0x7c00;23312332dib0090_set_bandwidth(state);2333state->tuner_is_tuned = 1;23342335state->calibrate |= WBD_CAL;2336state->calibrate |= TEMP_CAL;2337*tune_state = CT_TUNER_STOP;2338} else2339ret = FE_CALLBACK_TIME_NEVER;2340return ret;2341}23422343static int dib0090_release(struct dvb_frontend *fe)2344{2345kfree(fe->tuner_priv);2346fe->tuner_priv = NULL;2347return 0;2348}23492350enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)2351{2352struct dib0090_state *state = fe->tuner_priv;23532354return state->tune_state;2355}23562357EXPORT_SYMBOL(dib0090_get_tune_state);23582359int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)2360{2361struct dib0090_state *state = fe->tuner_priv;23622363state->tune_state = tune_state;2364return 0;2365}23662367EXPORT_SYMBOL(dib0090_set_tune_state);23682369static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)2370{2371struct dib0090_state *state = fe->tuner_priv;23722373*frequency = 1000 * state->current_rf;2374return 0;2375}23762377static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)2378{2379struct dib0090_state *state = fe->tuner_priv;2380u32 ret;23812382state->tune_state = CT_TUNER_START;23832384do {2385ret = dib0090_tune(fe);2386if (ret != FE_CALLBACK_TIME_NEVER)2387msleep(ret / 10);2388else2389break;2390} while (state->tune_state != CT_TUNER_STOP);23912392return 0;2393}23942395static const struct dvb_tuner_ops dib0090_ops = {2396.info = {2397.name = "DiBcom DiB0090",2398.frequency_min = 45000000,2399.frequency_max = 860000000,2400.frequency_step = 1000,2401},2402.release = dib0090_release,24032404.init = dib0090_wakeup,2405.sleep = dib0090_sleep,2406.set_params = dib0090_set_params,2407.get_frequency = dib0090_get_frequency,2408};24092410static const struct dvb_tuner_ops dib0090_fw_ops = {2411.info = {2412.name = "DiBcom DiB0090",2413.frequency_min = 45000000,2414.frequency_max = 860000000,2415.frequency_step = 1000,2416},2417.release = dib0090_release,24182419.init = NULL,2420.sleep = NULL,2421.set_params = NULL,2422.get_frequency = NULL,2423};24242425static const struct dib0090_wbd_slope dib0090_wbd_table_default[] = {2426{470, 0, 250, 0, 100, 4},2427{860, 51, 866, 21, 375, 4},2428{1700, 0, 800, 0, 850, 4},2429{2900, 0, 250, 0, 100, 6},2430{0xFFFF, 0, 0, 0, 0, 0},2431};24322433struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)2434{2435struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL);2436if (st == NULL)2437return NULL;24382439st->config = config;2440st->i2c = i2c;2441st->fe = fe;2442fe->tuner_priv = st;24432444if (config->wbd == NULL)2445st->current_wbd_table = dib0090_wbd_table_default;2446else2447st->current_wbd_table = config->wbd;24482449if (dib0090_reset(fe) != 0)2450goto free_mem;24512452printk(KERN_INFO "DiB0090: successfully identified\n");2453memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops));24542455return fe;2456free_mem:2457kfree(st);2458fe->tuner_priv = NULL;2459return NULL;2460}24612462EXPORT_SYMBOL(dib0090_register);24632464struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)2465{2466struct dib0090_fw_state *st = kzalloc(sizeof(struct dib0090_fw_state), GFP_KERNEL);2467if (st == NULL)2468return NULL;24692470st->config = config;2471st->i2c = i2c;2472st->fe = fe;2473fe->tuner_priv = st;24742475if (dib0090_fw_reset_digital(fe, st->config) != 0)2476goto free_mem;24772478dprintk("DiB0090 FW: successfully identified");2479memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops));24802481return fe;2482free_mem:2483kfree(st);2484fe->tuner_priv = NULL;2485return NULL;2486}2487EXPORT_SYMBOL(dib0090_fw_register);24882489MODULE_AUTHOR("Patrick Boettcher <[email protected]>");2490MODULE_AUTHOR("Olivier Grenie <[email protected]>");2491MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner");2492MODULE_LICENSE("GPL");249324942495