Path: blob/master/drivers/media/dvb/frontends/dib7000p.c
15112 views
/*1* Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).2*3* Copyright (C) 2005-7 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, version 2.8*/9#include <linux/kernel.h>10#include <linux/slab.h>11#include <linux/i2c.h>1213#include "dvb_math.h"14#include "dvb_frontend.h"1516#include "dib7000p.h"1718static int debug;19module_param(debug, int, 0644);20MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");2122static int buggy_sfn_workaround;23module_param(buggy_sfn_workaround, int, 0644);24MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");2526#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)2728struct i2c_device {29struct i2c_adapter *i2c_adap;30u8 i2c_addr;31};3233struct dib7000p_state {34struct dvb_frontend demod;35struct dib7000p_config cfg;3637u8 i2c_addr;38struct i2c_adapter *i2c_adap;3940struct dibx000_i2c_master i2c_master;4142u16 wbd_ref;4344u8 current_band;45u32 current_bandwidth;46struct dibx000_agc_config *current_agc;47u32 timf;4849u8 div_force_off:1;50u8 div_state:1;51u16 div_sync_wait;5253u8 agc_state;5455u16 gpio_dir;56u16 gpio_val;5758u8 sfn_workaround_active:1;5960#define SOC7090 0x709061u16 version;6263u16 tuner_enable;64struct i2c_adapter dib7090_tuner_adap;6566/* for the I2C transfer */67struct i2c_msg msg[2];68u8 i2c_write_buffer[4];69u8 i2c_read_buffer[2];70};7172enum dib7000p_power_mode {73DIB7000P_POWER_ALL = 0,74DIB7000P_POWER_ANALOG_ADC,75DIB7000P_POWER_INTERFACE_ONLY,76};7778static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);79static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);8081static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)82{83state->i2c_write_buffer[0] = reg >> 8;84state->i2c_write_buffer[1] = reg & 0xff;8586memset(state->msg, 0, 2 * sizeof(struct i2c_msg));87state->msg[0].addr = state->i2c_addr >> 1;88state->msg[0].flags = 0;89state->msg[0].buf = state->i2c_write_buffer;90state->msg[0].len = 2;91state->msg[1].addr = state->i2c_addr >> 1;92state->msg[1].flags = I2C_M_RD;93state->msg[1].buf = state->i2c_read_buffer;94state->msg[1].len = 2;9596if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)97dprintk("i2c read error on %d", reg);9899return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];100}101102static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)103{104state->i2c_write_buffer[0] = (reg >> 8) & 0xff;105state->i2c_write_buffer[1] = reg & 0xff;106state->i2c_write_buffer[2] = (val >> 8) & 0xff;107state->i2c_write_buffer[3] = val & 0xff;108109memset(&state->msg[0], 0, sizeof(struct i2c_msg));110state->msg[0].addr = state->i2c_addr >> 1;111state->msg[0].flags = 0;112state->msg[0].buf = state->i2c_write_buffer;113state->msg[0].len = 4;114115return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;116}117118static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)119{120u16 l = 0, r, *n;121n = buf;122l = *n++;123while (l) {124r = *n++;125126do {127dib7000p_write_word(state, r, *n++);128r++;129} while (--l);130l = *n++;131}132}133134static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)135{136int ret = 0;137u16 outreg, fifo_threshold, smo_mode;138139outreg = 0;140fifo_threshold = 1792;141smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);142143dprintk("setting output mode for demod %p to %d", &state->demod, mode);144145switch (mode) {146case OUTMODE_MPEG2_PAR_GATED_CLK:147outreg = (1 << 10); /* 0x0400 */148break;149case OUTMODE_MPEG2_PAR_CONT_CLK:150outreg = (1 << 10) | (1 << 6); /* 0x0440 */151break;152case OUTMODE_MPEG2_SERIAL:153outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */154break;155case OUTMODE_DIVERSITY:156if (state->cfg.hostbus_diversity)157outreg = (1 << 10) | (4 << 6); /* 0x0500 */158else159outreg = (1 << 11);160break;161case OUTMODE_MPEG2_FIFO:162smo_mode |= (3 << 1);163fifo_threshold = 512;164outreg = (1 << 10) | (5 << 6);165break;166case OUTMODE_ANALOG_ADC:167outreg = (1 << 10) | (3 << 6);168break;169case OUTMODE_HIGH_Z:170outreg = 0;171break;172default:173dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod);174break;175}176177if (state->cfg.output_mpeg2_in_188_bytes)178smo_mode |= (1 << 5);179180ret |= dib7000p_write_word(state, 235, smo_mode);181ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */182if (state->version != SOC7090)183ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */184185return ret;186}187188static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)189{190struct dib7000p_state *state = demod->demodulator_priv;191192if (state->div_force_off) {193dprintk("diversity combination deactivated - forced by COFDM parameters");194onoff = 0;195dib7000p_write_word(state, 207, 0);196} else197dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));198199state->div_state = (u8) onoff;200201if (onoff) {202dib7000p_write_word(state, 204, 6);203dib7000p_write_word(state, 205, 16);204/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */205} else {206dib7000p_write_word(state, 204, 1);207dib7000p_write_word(state, 205, 0);208}209210return 0;211}212213static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)214{215/* by default everything is powered off */216u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);217218/* now, depending on the requested mode, we power on */219switch (mode) {220/* power up everything in the demod */221case DIB7000P_POWER_ALL:222reg_774 = 0x0000;223reg_775 = 0x0000;224reg_776 = 0x0;225reg_899 = 0x0;226if (state->version == SOC7090)227reg_1280 &= 0x001f;228else229reg_1280 &= 0x01ff;230break;231232case DIB7000P_POWER_ANALOG_ADC:233/* dem, cfg, iqc, sad, agc */234reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));235/* nud */236reg_776 &= ~((1 << 0));237/* Dout */238if (state->version != SOC7090)239reg_1280 &= ~((1 << 11));240reg_1280 &= ~(1 << 6);241/* fall through wanted to enable the interfaces */242243/* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */244case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */245if (state->version == SOC7090)246reg_1280 &= ~((1 << 7) | (1 << 5));247else248reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));249break;250251/* TODO following stuff is just converted from the dib7000-driver - check when is used what */252}253254dib7000p_write_word(state, 774, reg_774);255dib7000p_write_word(state, 775, reg_775);256dib7000p_write_word(state, 776, reg_776);257dib7000p_write_word(state, 899, reg_899);258dib7000p_write_word(state, 1280, reg_1280);259260return 0;261}262263static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)264{265u16 reg_908 = dib7000p_read_word(state, 908), reg_909 = dib7000p_read_word(state, 909);266u16 reg;267268switch (no) {269case DIBX000_SLOW_ADC_ON:270if (state->version == SOC7090) {271reg = dib7000p_read_word(state, 1925);272273dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2)); /* en_slowAdc = 1 & reset_sladc = 1 */274275reg = dib7000p_read_word(state, 1925); /* read acces to make it works... strange ... */276msleep(200);277dib7000p_write_word(state, 1925, reg & ~(1 << 4)); /* en_slowAdc = 1 & reset_sladc = 0 */278279reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));280dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524); /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */281} else {282reg_909 |= (1 << 1) | (1 << 0);283dib7000p_write_word(state, 909, reg_909);284reg_909 &= ~(1 << 1);285}286break;287288case DIBX000_SLOW_ADC_OFF:289if (state->version == SOC7090) {290reg = dib7000p_read_word(state, 1925);291dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4)); /* reset_sladc = 1 en_slowAdc = 0 */292} else293reg_909 |= (1 << 1) | (1 << 0);294break;295296case DIBX000_ADC_ON:297reg_908 &= 0x0fff;298reg_909 &= 0x0003;299break;300301case DIBX000_ADC_OFF:302reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);303reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);304break;305306case DIBX000_VBG_ENABLE:307reg_908 &= ~(1 << 15);308break;309310case DIBX000_VBG_DISABLE:311reg_908 |= (1 << 15);312break;313314default:315break;316}317318// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);319320reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;321reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;322323dib7000p_write_word(state, 908, reg_908);324dib7000p_write_word(state, 909, reg_909);325}326327static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)328{329u32 timf;330331// store the current bandwidth for later use332state->current_bandwidth = bw;333334if (state->timf == 0) {335dprintk("using default timf");336timf = state->cfg.bw->timf;337} else {338dprintk("using updated timf");339timf = state->timf;340}341342timf = timf * (bw / 50) / 160;343344dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));345dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));346347return 0;348}349350static int dib7000p_sad_calib(struct dib7000p_state *state)351{352/* internal */353dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));354355if (state->version == SOC7090)356dib7000p_write_word(state, 74, 2048);357else358dib7000p_write_word(state, 74, 776);359360/* do the calibration */361dib7000p_write_word(state, 73, (1 << 0));362dib7000p_write_word(state, 73, (0 << 0));363364msleep(1);365366return 0;367}368369int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)370{371struct dib7000p_state *state = demod->demodulator_priv;372if (value > 4095)373value = 4095;374state->wbd_ref = value;375return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);376}377EXPORT_SYMBOL(dib7000p_set_wbd_ref);378379static void dib7000p_reset_pll(struct dib7000p_state *state)380{381struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];382u16 clk_cfg0;383384if (state->version == SOC7090) {385dib7000p_write_word(state, 1856, (!bw->pll_reset << 13) | (bw->pll_range << 12) | (bw->pll_ratio << 6) | (bw->pll_prediv));386387while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)388;389390dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));391} else {392/* force PLL bypass */393clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |394(bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);395396dib7000p_write_word(state, 900, clk_cfg0);397398/* P_pll_cfg */399dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);400clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);401dib7000p_write_word(state, 900, clk_cfg0);402}403404dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));405dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));406dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));407dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));408409dib7000p_write_word(state, 72, bw->sad_cfg);410}411412static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)413{414u32 internal = (u32) dib7000p_read_word(state, 18) << 16;415internal |= (u32) dib7000p_read_word(state, 19);416internal /= 1000;417418return internal;419}420421int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)422{423struct dib7000p_state *state = fe->demodulator_priv;424u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);425u8 loopdiv, prediv;426u32 internal, xtal;427428/* get back old values */429prediv = reg_1856 & 0x3f;430loopdiv = (reg_1856 >> 6) & 0x3f;431432if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {433dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);434reg_1856 &= 0xf000;435reg_1857 = dib7000p_read_word(state, 1857);436dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));437438dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));439440/* write new system clk into P_sec_len */441internal = dib7000p_get_internal_freq(state);442xtal = (internal / loopdiv) * prediv;443internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio; /* new internal */444dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));445dib7000p_write_word(state, 19, (u16) (internal & 0xffff));446447dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));448449while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)450dprintk("Waiting for PLL to lock");451452return 0;453}454return -EIO;455}456EXPORT_SYMBOL(dib7000p_update_pll);457458static int dib7000p_reset_gpio(struct dib7000p_state *st)459{460/* reset the GPIOs */461dprintk("gpio dir: %x: val: %x, pwm_pos: %x", st->gpio_dir, st->gpio_val, st->cfg.gpio_pwm_pos);462463dib7000p_write_word(st, 1029, st->gpio_dir);464dib7000p_write_word(st, 1030, st->gpio_val);465466/* TODO 1031 is P_gpio_od */467468dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);469470dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);471return 0;472}473474static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)475{476st->gpio_dir = dib7000p_read_word(st, 1029);477st->gpio_dir &= ~(1 << num); /* reset the direction bit */478st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */479dib7000p_write_word(st, 1029, st->gpio_dir);480481st->gpio_val = dib7000p_read_word(st, 1030);482st->gpio_val &= ~(1 << num); /* reset the direction bit */483st->gpio_val |= (val & 0x01) << num; /* set the new value */484dib7000p_write_word(st, 1030, st->gpio_val);485486return 0;487}488489int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)490{491struct dib7000p_state *state = demod->demodulator_priv;492return dib7000p_cfg_gpio(state, num, dir, val);493}494EXPORT_SYMBOL(dib7000p_set_gpio);495496static u16 dib7000p_defaults[] = {497// auto search configuration4983, 2,4990x0004,5000x1000,5010x0814, /* Equal Lock */50250312, 6,5040x001b,5050x7740,5060x005b,5070x8d80,5080x01c9,5090xc380,5100x0000,5110x0080,5120x0000,5130x0090,5140x0001,5150xd4c0,5165171, 26,5180x6680,519520/* set ADC level to -16 */52111, 79,522(1 << 13) - 825 - 117,523(1 << 13) - 837 - 117,524(1 << 13) - 811 - 117,525(1 << 13) - 766 - 117,526(1 << 13) - 737 - 117,527(1 << 13) - 693 - 117,528(1 << 13) - 648 - 117,529(1 << 13) - 619 - 117,530(1 << 13) - 575 - 117,531(1 << 13) - 531 - 117,532(1 << 13) - 501 - 117,5335341, 142,5350x0410,536537/* disable power smoothing */5388, 145,5390,5400,5410,5420,5430,5440,5450,5460,5475481, 154,5491 << 13,5505511, 168,5520x0ccd,5535541, 183,5550x200f,5565571, 212,5580x169,5595605, 187,5610x023d,5620x00a4,5630x00a4,5640x7ff0,5650x3ccc,5665671, 198,5680x800,5695701, 222,5710x0010,5725731, 235,5740x0062,5755762, 901,5770x0006,578(3 << 10) | (1 << 6),5795801, 905,5810x2c8e,5825830,584};585586static int dib7000p_demod_reset(struct dib7000p_state *state)587{588dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);589590if (state->version == SOC7090)591dibx000_reset_i2c_master(&state->i2c_master);592593dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);594595/* restart all parts */596dib7000p_write_word(state, 770, 0xffff);597dib7000p_write_word(state, 771, 0xffff);598dib7000p_write_word(state, 772, 0x001f);599dib7000p_write_word(state, 898, 0x0003);600dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));601602dib7000p_write_word(state, 770, 0);603dib7000p_write_word(state, 771, 0);604dib7000p_write_word(state, 772, 0);605dib7000p_write_word(state, 898, 0);606dib7000p_write_word(state, 1280, 0);607608/* default */609dib7000p_reset_pll(state);610611if (dib7000p_reset_gpio(state) != 0)612dprintk("GPIO reset was not successful.");613614if (state->version == SOC7090) {615dib7000p_write_word(state, 899, 0);616617/* impulse noise */618dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */619dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */620dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */621dib7000p_write_word(state, 273, (1<<6) | 30);622}623if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)624dprintk("OUTPUT_MODE could not be reset.");625626dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);627dib7000p_sad_calib(state);628dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);629630/* unforce divstr regardless whether i2c enumeration was done or not */631dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));632633dib7000p_set_bandwidth(state, 8000);634635if (state->version == SOC7090) {636dib7000p_write_word(state, 36, 0x5755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */637} else {638if (state->cfg.tuner_is_baseband)639dib7000p_write_word(state, 36, 0x0755);640else641dib7000p_write_word(state, 36, 0x1f55);642}643644dib7000p_write_tab(state, dib7000p_defaults);645646dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);647648return 0;649}650651static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)652{653u16 tmp = 0;654tmp = dib7000p_read_word(state, 903);655dib7000p_write_word(state, 903, (tmp | 0x1));656tmp = dib7000p_read_word(state, 900);657dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));658}659660static void dib7000p_restart_agc(struct dib7000p_state *state)661{662// P_restart_iqc & P_restart_agc663dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));664dib7000p_write_word(state, 770, 0x0000);665}666667static int dib7000p_update_lna(struct dib7000p_state *state)668{669u16 dyn_gain;670671if (state->cfg.update_lna) {672dyn_gain = dib7000p_read_word(state, 394);673if (state->cfg.update_lna(&state->demod, dyn_gain)) {674dib7000p_restart_agc(state);675return 1;676}677}678679return 0;680}681682static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)683{684struct dibx000_agc_config *agc = NULL;685int i;686if (state->current_band == band && state->current_agc != NULL)687return 0;688state->current_band = band;689690for (i = 0; i < state->cfg.agc_config_count; i++)691if (state->cfg.agc[i].band_caps & band) {692agc = &state->cfg.agc[i];693break;694}695696if (agc == NULL) {697dprintk("no valid AGC configuration found for band 0x%02x", band);698return -EINVAL;699}700701state->current_agc = agc;702703/* AGC */704dib7000p_write_word(state, 75, agc->setup);705dib7000p_write_word(state, 76, agc->inv_gain);706dib7000p_write_word(state, 77, agc->time_stabiliz);707dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);708709// Demod AGC loop configuration710dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);711dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);712713/* AGC continued */714dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",715state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);716717if (state->wbd_ref != 0)718dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);719else720dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);721722dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));723724dib7000p_write_word(state, 107, agc->agc1_max);725dib7000p_write_word(state, 108, agc->agc1_min);726dib7000p_write_word(state, 109, agc->agc2_max);727dib7000p_write_word(state, 110, agc->agc2_min);728dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);729dib7000p_write_word(state, 112, agc->agc1_pt3);730dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);731dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);732dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);733return 0;734}735736static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)737{738u32 internal = dib7000p_get_internal_freq(state);739s32 unit_khz_dds_val = 67108864 / (internal); /* 2**26 / Fsampling is the unit 1KHz offset */740u32 abs_offset_khz = ABS(offset_khz);741u32 dds = state->cfg.bw->ifreq & 0x1ffffff;742u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));743744dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert);745746if (offset_khz < 0)747unit_khz_dds_val *= -1;748749/* IF tuner */750if (invert)751dds -= (abs_offset_khz * unit_khz_dds_val); /* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */752else753dds += (abs_offset_khz * unit_khz_dds_val);754755if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */756dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));757dib7000p_write_word(state, 22, (u16) (dds & 0xffff));758}759}760761static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)762{763struct dib7000p_state *state = demod->demodulator_priv;764int ret = -1;765u8 *agc_state = &state->agc_state;766u8 agc_split;767u16 reg;768u32 upd_demod_gain_period = 0x1000;769770switch (state->agc_state) {771case 0:772dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);773if (state->version == SOC7090) {774reg = dib7000p_read_word(state, 0x79b) & 0xff00;775dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */776dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));777778/* enable adc i & q */779reg = dib7000p_read_word(state, 0x780);780dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));781} else {782dib7000p_set_adc_state(state, DIBX000_ADC_ON);783dib7000p_pll_clk_cfg(state);784}785786if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)787return -1;788789dib7000p_set_dds(state, 0);790ret = 7;791(*agc_state)++;792break;793794case 1:795if (state->cfg.agc_control)796state->cfg.agc_control(&state->demod, 1);797798dib7000p_write_word(state, 78, 32768);799if (!state->current_agc->perform_agc_softsplit) {800/* we are using the wbd - so slow AGC startup */801/* force 0 split on WBD and restart AGC */802dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));803(*agc_state)++;804ret = 5;805} else {806/* default AGC startup */807(*agc_state) = 4;808/* wait AGC rough lock time */809ret = 7;810}811812dib7000p_restart_agc(state);813break;814815case 2: /* fast split search path after 5sec */816dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */817dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */818(*agc_state)++;819ret = 14;820break;821822case 3: /* split search ended */823agc_split = (u8) dib7000p_read_word(state, 396); /* store the split value for the next time */824dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */825826dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */827dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */828829dib7000p_restart_agc(state);830831dprintk("SPLIT %p: %hd", demod, agc_split);832833(*agc_state)++;834ret = 5;835break;836837case 4: /* LNA startup */838ret = 7;839840if (dib7000p_update_lna(state))841ret = 5;842else843(*agc_state)++;844break;845846case 5:847if (state->cfg.agc_control)848state->cfg.agc_control(&state->demod, 0);849(*agc_state)++;850break;851default:852break;853}854return ret;855}856857static void dib7000p_update_timf(struct dib7000p_state *state)858{859u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);860state->timf = timf * 160 / (state->current_bandwidth / 50);861dib7000p_write_word(state, 23, (u16) (timf >> 16));862dib7000p_write_word(state, 24, (u16) (timf & 0xffff));863dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf);864865}866867u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)868{869struct dib7000p_state *state = fe->demodulator_priv;870switch (op) {871case DEMOD_TIMF_SET:872state->timf = timf;873break;874case DEMOD_TIMF_UPDATE:875dib7000p_update_timf(state);876break;877case DEMOD_TIMF_GET:878break;879}880dib7000p_set_bandwidth(state, state->current_bandwidth);881return state->timf;882}883EXPORT_SYMBOL(dib7000p_ctrl_timf);884885static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)886{887u16 value, est[4];888889dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));890891/* nfft, guard, qam, alpha */892value = 0;893switch (ch->u.ofdm.transmission_mode) {894case TRANSMISSION_MODE_2K:895value |= (0 << 7);896break;897case TRANSMISSION_MODE_4K:898value |= (2 << 7);899break;900default:901case TRANSMISSION_MODE_8K:902value |= (1 << 7);903break;904}905switch (ch->u.ofdm.guard_interval) {906case GUARD_INTERVAL_1_32:907value |= (0 << 5);908break;909case GUARD_INTERVAL_1_16:910value |= (1 << 5);911break;912case GUARD_INTERVAL_1_4:913value |= (3 << 5);914break;915default:916case GUARD_INTERVAL_1_8:917value |= (2 << 5);918break;919}920switch (ch->u.ofdm.constellation) {921case QPSK:922value |= (0 << 3);923break;924case QAM_16:925value |= (1 << 3);926break;927default:928case QAM_64:929value |= (2 << 3);930break;931}932switch (HIERARCHY_1) {933case HIERARCHY_2:934value |= 2;935break;936case HIERARCHY_4:937value |= 4;938break;939default:940case HIERARCHY_1:941value |= 1;942break;943}944dib7000p_write_word(state, 0, value);945dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */946947/* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */948value = 0;949if (1 != 0)950value |= (1 << 6);951if (ch->u.ofdm.hierarchy_information == 1)952value |= (1 << 4);953if (1 == 1)954value |= 1;955switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {956case FEC_2_3:957value |= (2 << 1);958break;959case FEC_3_4:960value |= (3 << 1);961break;962case FEC_5_6:963value |= (5 << 1);964break;965case FEC_7_8:966value |= (7 << 1);967break;968default:969case FEC_1_2:970value |= (1 << 1);971break;972}973dib7000p_write_word(state, 208, value);974975/* offset loop parameters */976dib7000p_write_word(state, 26, 0x6680);977dib7000p_write_word(state, 32, 0x0003);978dib7000p_write_word(state, 29, 0x1273);979dib7000p_write_word(state, 33, 0x0005);980981/* P_dvsy_sync_wait */982switch (ch->u.ofdm.transmission_mode) {983case TRANSMISSION_MODE_8K:984value = 256;985break;986case TRANSMISSION_MODE_4K:987value = 128;988break;989case TRANSMISSION_MODE_2K:990default:991value = 64;992break;993}994switch (ch->u.ofdm.guard_interval) {995case GUARD_INTERVAL_1_16:996value *= 2;997break;998case GUARD_INTERVAL_1_8:999value *= 4;1000break;1001case GUARD_INTERVAL_1_4:1002value *= 8;1003break;1004default:1005case GUARD_INTERVAL_1_32:1006value *= 1;1007break;1008}1009if (state->cfg.diversity_delay == 0)1010state->div_sync_wait = (value * 3) / 2 + 48;1011else1012state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;10131014/* deactive the possibility of diversity reception if extended interleaver */1015state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;1016dib7000p_set_diversity_in(&state->demod, state->div_state);10171018/* channel estimation fine configuration */1019switch (ch->u.ofdm.constellation) {1020case QAM_64:1021est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */1022est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */1023est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */1024est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */1025break;1026case QAM_16:1027est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */1028est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */1029est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */1030est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */1031break;1032default:1033est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */1034est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */1035est[2] = 0x0333; /* P_adp_regul_ext 0.1 */1036est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */1037break;1038}1039for (value = 0; value < 4; value++)1040dib7000p_write_word(state, 187 + value, est[value]);1041}10421043static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)1044{1045struct dib7000p_state *state = demod->demodulator_priv;1046struct dvb_frontend_parameters schan;1047u32 value, factor;1048u32 internal = dib7000p_get_internal_freq(state);10491050schan = *ch;1051schan.u.ofdm.constellation = QAM_64;1052schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;1053schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;1054schan.u.ofdm.code_rate_HP = FEC_2_3;1055schan.u.ofdm.code_rate_LP = FEC_3_4;1056schan.u.ofdm.hierarchy_information = 0;10571058dib7000p_set_channel(state, &schan, 7);10591060factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);1061if (factor >= 5000)1062factor = 1;1063else1064factor = 6;10651066value = 30 * internal * factor;1067dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));1068dib7000p_write_word(state, 7, (u16) (value & 0xffff));1069value = 100 * internal * factor;1070dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));1071dib7000p_write_word(state, 9, (u16) (value & 0xffff));1072value = 500 * internal * factor;1073dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));1074dib7000p_write_word(state, 11, (u16) (value & 0xffff));10751076value = dib7000p_read_word(state, 0);1077dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));1078dib7000p_read_word(state, 1284);1079dib7000p_write_word(state, 0, (u16) value);10801081return 0;1082}10831084static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)1085{1086struct dib7000p_state *state = demod->demodulator_priv;1087u16 irq_pending = dib7000p_read_word(state, 1284);10881089if (irq_pending & 0x1)1090return 1;10911092if (irq_pending & 0x2)1093return 2;10941095return 0;1096}10971098static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)1099{1100static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };1101static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,110224, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,110353, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,110482, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,1105107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,1106128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,1107147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,1108166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,1109183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,1110199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,1111213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,1112225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,1113235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,1114244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,1115250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,1116254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,1117255, 255, 255, 255, 255, 2551118};11191120u32 xtal = state->cfg.bw->xtal_hz / 1000;1121int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;1122int k;1123int coef_re[8], coef_im[8];1124int bw_khz = bw;1125u32 pha;11261127dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);11281129if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)1130return;11311132bw_khz /= 100;11331134dib7000p_write_word(state, 142, 0x0610);11351136for (k = 0; k < 8; k++) {1137pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;11381139if (pha == 0) {1140coef_re[k] = 256;1141coef_im[k] = 0;1142} else if (pha < 256) {1143coef_re[k] = sine[256 - (pha & 0xff)];1144coef_im[k] = sine[pha & 0xff];1145} else if (pha == 256) {1146coef_re[k] = 0;1147coef_im[k] = 256;1148} else if (pha < 512) {1149coef_re[k] = -sine[pha & 0xff];1150coef_im[k] = sine[256 - (pha & 0xff)];1151} else if (pha == 512) {1152coef_re[k] = -256;1153coef_im[k] = 0;1154} else if (pha < 768) {1155coef_re[k] = -sine[256 - (pha & 0xff)];1156coef_im[k] = -sine[pha & 0xff];1157} else if (pha == 768) {1158coef_re[k] = 0;1159coef_im[k] = -256;1160} else {1161coef_re[k] = sine[pha & 0xff];1162coef_im[k] = -sine[256 - (pha & 0xff)];1163}11641165coef_re[k] *= notch[k];1166coef_re[k] += (1 << 14);1167if (coef_re[k] >= (1 << 24))1168coef_re[k] = (1 << 24) - 1;1169coef_re[k] /= (1 << 15);11701171coef_im[k] *= notch[k];1172coef_im[k] += (1 << 14);1173if (coef_im[k] >= (1 << 24))1174coef_im[k] = (1 << 24) - 1;1175coef_im[k] /= (1 << 15);11761177dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);11781179dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));1180dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);1181dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));1182}1183dib7000p_write_word(state, 143, 0);1184}11851186static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)1187{1188struct dib7000p_state *state = demod->demodulator_priv;1189u16 tmp = 0;11901191if (ch != NULL)1192dib7000p_set_channel(state, ch, 0);1193else1194return -EINVAL;11951196// restart demod1197dib7000p_write_word(state, 770, 0x4000);1198dib7000p_write_word(state, 770, 0x0000);1199msleep(45);12001201/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */1202tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);1203if (state->sfn_workaround_active) {1204dprintk("SFN workaround is active");1205tmp |= (1 << 9);1206dib7000p_write_word(state, 166, 0x4000);1207} else {1208dib7000p_write_word(state, 166, 0x0000);1209}1210dib7000p_write_word(state, 29, tmp);12111212// never achieved a lock with that bandwidth so far - wait for osc-freq to update1213if (state->timf == 0)1214msleep(200);12151216/* offset loop parameters */12171218/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */1219tmp = (6 << 8) | 0x80;1220switch (ch->u.ofdm.transmission_mode) {1221case TRANSMISSION_MODE_2K:1222tmp |= (2 << 12);1223break;1224case TRANSMISSION_MODE_4K:1225tmp |= (3 << 12);1226break;1227default:1228case TRANSMISSION_MODE_8K:1229tmp |= (4 << 12);1230break;1231}1232dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */12331234/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */1235tmp = (0 << 4);1236switch (ch->u.ofdm.transmission_mode) {1237case TRANSMISSION_MODE_2K:1238tmp |= 0x6;1239break;1240case TRANSMISSION_MODE_4K:1241tmp |= 0x7;1242break;1243default:1244case TRANSMISSION_MODE_8K:1245tmp |= 0x8;1246break;1247}1248dib7000p_write_word(state, 32, tmp);12491250/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */1251tmp = (0 << 4);1252switch (ch->u.ofdm.transmission_mode) {1253case TRANSMISSION_MODE_2K:1254tmp |= 0x6;1255break;1256case TRANSMISSION_MODE_4K:1257tmp |= 0x7;1258break;1259default:1260case TRANSMISSION_MODE_8K:1261tmp |= 0x8;1262break;1263}1264dib7000p_write_word(state, 33, tmp);12651266tmp = dib7000p_read_word(state, 509);1267if (!((tmp >> 6) & 0x1)) {1268/* restart the fec */1269tmp = dib7000p_read_word(state, 771);1270dib7000p_write_word(state, 771, tmp | (1 << 1));1271dib7000p_write_word(state, 771, tmp);1272msleep(40);1273tmp = dib7000p_read_word(state, 509);1274}1275// we achieved a lock - it's time to update the osc freq1276if ((tmp >> 6) & 0x1) {1277dib7000p_update_timf(state);1278/* P_timf_alpha += 2 */1279tmp = dib7000p_read_word(state, 26);1280dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));1281}12821283if (state->cfg.spur_protect)1284dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));12851286dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));1287return 0;1288}12891290static int dib7000p_wakeup(struct dvb_frontend *demod)1291{1292struct dib7000p_state *state = demod->demodulator_priv;1293dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);1294dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);1295if (state->version == SOC7090)1296dib7000p_sad_calib(state);1297return 0;1298}12991300static int dib7000p_sleep(struct dvb_frontend *demod)1301{1302struct dib7000p_state *state = demod->demodulator_priv;1303if (state->version == SOC7090)1304return dib7090_set_output_mode(demod, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);1305return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);1306}13071308static int dib7000p_identify(struct dib7000p_state *st)1309{1310u16 value;1311dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr);13121313if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {1314dprintk("wrong Vendor ID (read=0x%x)", value);1315return -EREMOTEIO;1316}13171318if ((value = dib7000p_read_word(st, 769)) != 0x4000) {1319dprintk("wrong Device ID (%x)", value);1320return -EREMOTEIO;1321}13221323return 0;1324}13251326static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)1327{1328struct dib7000p_state *state = fe->demodulator_priv;1329u16 tps = dib7000p_read_word(state, 463);13301331fep->inversion = INVERSION_AUTO;13321333fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);13341335switch ((tps >> 8) & 0x3) {1336case 0:1337fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;1338break;1339case 1:1340fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;1341break;1342/* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */1343}13441345switch (tps & 0x3) {1346case 0:1347fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;1348break;1349case 1:1350fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;1351break;1352case 2:1353fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;1354break;1355case 3:1356fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;1357break;1358}13591360switch ((tps >> 14) & 0x3) {1361case 0:1362fep->u.ofdm.constellation = QPSK;1363break;1364case 1:1365fep->u.ofdm.constellation = QAM_16;1366break;1367case 2:1368default:1369fep->u.ofdm.constellation = QAM_64;1370break;1371}13721373/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */1374/* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */13751376fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;1377switch ((tps >> 5) & 0x7) {1378case 1:1379fep->u.ofdm.code_rate_HP = FEC_1_2;1380break;1381case 2:1382fep->u.ofdm.code_rate_HP = FEC_2_3;1383break;1384case 3:1385fep->u.ofdm.code_rate_HP = FEC_3_4;1386break;1387case 5:1388fep->u.ofdm.code_rate_HP = FEC_5_6;1389break;1390case 7:1391default:1392fep->u.ofdm.code_rate_HP = FEC_7_8;1393break;13941395}13961397switch ((tps >> 2) & 0x7) {1398case 1:1399fep->u.ofdm.code_rate_LP = FEC_1_2;1400break;1401case 2:1402fep->u.ofdm.code_rate_LP = FEC_2_3;1403break;1404case 3:1405fep->u.ofdm.code_rate_LP = FEC_3_4;1406break;1407case 5:1408fep->u.ofdm.code_rate_LP = FEC_5_6;1409break;1410case 7:1411default:1412fep->u.ofdm.code_rate_LP = FEC_7_8;1413break;1414}14151416/* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */14171418return 0;1419}14201421static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)1422{1423struct dib7000p_state *state = fe->demodulator_priv;1424int time, ret;14251426if (state->version == SOC7090) {1427dib7090_set_diversity_in(fe, 0);1428dib7090_set_output_mode(fe, OUTMODE_HIGH_Z);1429} else1430dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);14311432/* maybe the parameter has been changed */1433state->sfn_workaround_active = buggy_sfn_workaround;14341435if (fe->ops.tuner_ops.set_params)1436fe->ops.tuner_ops.set_params(fe, fep);14371438/* start up the AGC */1439state->agc_state = 0;1440do {1441time = dib7000p_agc_startup(fe, fep);1442if (time != -1)1443msleep(time);1444} while (time != -1);14451446if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||1447fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) {1448int i = 800, found;14491450dib7000p_autosearch_start(fe, fep);1451do {1452msleep(1);1453found = dib7000p_autosearch_is_irq(fe);1454} while (found == 0 && i--);14551456dprintk("autosearch returns: %d", found);1457if (found == 0 || found == 1)1458return 0;14591460dib7000p_get_frontend(fe, fep);1461}14621463ret = dib7000p_tune(fe, fep);14641465/* make this a config parameter */1466if (state->version == SOC7090)1467dib7090_set_output_mode(fe, state->cfg.output_mode);1468else1469dib7000p_set_output_mode(state, state->cfg.output_mode);14701471return ret;1472}14731474static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)1475{1476struct dib7000p_state *state = fe->demodulator_priv;1477u16 lock = dib7000p_read_word(state, 509);14781479*stat = 0;14801481if (lock & 0x8000)1482*stat |= FE_HAS_SIGNAL;1483if (lock & 0x3000)1484*stat |= FE_HAS_CARRIER;1485if (lock & 0x0100)1486*stat |= FE_HAS_VITERBI;1487if (lock & 0x0010)1488*stat |= FE_HAS_SYNC;1489if ((lock & 0x0038) == 0x38)1490*stat |= FE_HAS_LOCK;14911492return 0;1493}14941495static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)1496{1497struct dib7000p_state *state = fe->demodulator_priv;1498*ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);1499return 0;1500}15011502static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)1503{1504struct dib7000p_state *state = fe->demodulator_priv;1505*unc = dib7000p_read_word(state, 506);1506return 0;1507}15081509static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)1510{1511struct dib7000p_state *state = fe->demodulator_priv;1512u16 val = dib7000p_read_word(state, 394);1513*strength = 65535 - val;1514return 0;1515}15161517static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)1518{1519struct dib7000p_state *state = fe->demodulator_priv;1520u16 val;1521s32 signal_mant, signal_exp, noise_mant, noise_exp;1522u32 result = 0;15231524val = dib7000p_read_word(state, 479);1525noise_mant = (val >> 4) & 0xff;1526noise_exp = ((val & 0xf) << 2);1527val = dib7000p_read_word(state, 480);1528noise_exp += ((val >> 14) & 0x3);1529if ((noise_exp & 0x20) != 0)1530noise_exp -= 0x40;15311532signal_mant = (val >> 6) & 0xFF;1533signal_exp = (val & 0x3F);1534if ((signal_exp & 0x20) != 0)1535signal_exp -= 0x40;15361537if (signal_mant != 0)1538result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);1539else1540result = intlog10(2) * 10 * signal_exp - 100;15411542if (noise_mant != 0)1543result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);1544else1545result -= intlog10(2) * 10 * noise_exp - 100;15461547*snr = result / ((1 << 24) / 10);1548return 0;1549}15501551static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)1552{1553tune->min_delay_ms = 1000;1554return 0;1555}15561557static void dib7000p_release(struct dvb_frontend *demod)1558{1559struct dib7000p_state *st = demod->demodulator_priv;1560dibx000_exit_i2c_master(&st->i2c_master);1561i2c_del_adapter(&st->dib7090_tuner_adap);1562kfree(st);1563}15641565int dib7000pc_detection(struct i2c_adapter *i2c_adap)1566{1567u8 *tx, *rx;1568struct i2c_msg msg[2] = {1569{.addr = 18 >> 1, .flags = 0, .len = 2},1570{.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},1571};1572int ret = 0;15731574tx = kzalloc(2*sizeof(u8), GFP_KERNEL);1575if (!tx)1576return -ENOMEM;1577rx = kzalloc(2*sizeof(u8), GFP_KERNEL);1578if (!rx) {1579goto rx_memory_error;1580ret = -ENOMEM;1581}15821583msg[0].buf = tx;1584msg[1].buf = rx;15851586tx[0] = 0x03;1587tx[1] = 0x00;15881589if (i2c_transfer(i2c_adap, msg, 2) == 2)1590if (rx[0] == 0x01 && rx[1] == 0xb3) {1591dprintk("-D- DiB7000PC detected");1592return 1;1593}15941595msg[0].addr = msg[1].addr = 0x40;15961597if (i2c_transfer(i2c_adap, msg, 2) == 2)1598if (rx[0] == 0x01 && rx[1] == 0xb3) {1599dprintk("-D- DiB7000PC detected");1600return 1;1601}16021603dprintk("-D- DiB7000PC not detected");16041605kfree(rx);1606rx_memory_error:1607kfree(tx);1608return ret;1609}1610EXPORT_SYMBOL(dib7000pc_detection);16111612struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)1613{1614struct dib7000p_state *st = demod->demodulator_priv;1615return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);1616}1617EXPORT_SYMBOL(dib7000p_get_i2c_master);16181619int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)1620{1621struct dib7000p_state *state = fe->demodulator_priv;1622u16 val = dib7000p_read_word(state, 235) & 0xffef;1623val |= (onoff & 0x1) << 4;1624dprintk("PID filter enabled %d", onoff);1625return dib7000p_write_word(state, 235, val);1626}1627EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);16281629int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)1630{1631struct dib7000p_state *state = fe->demodulator_priv;1632dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);1633return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);1634}1635EXPORT_SYMBOL(dib7000p_pid_filter);16361637int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])1638{1639struct dib7000p_state *dpst;1640int k = 0;1641u8 new_addr = 0;16421643dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);1644if (!dpst)1645return -ENOMEM;16461647dpst->i2c_adap = i2c;16481649for (k = no_of_demods - 1; k >= 0; k--) {1650dpst->cfg = cfg[k];16511652/* designated i2c address */1653if (cfg[k].default_i2c_addr != 0)1654new_addr = cfg[k].default_i2c_addr + (k << 1);1655else1656new_addr = (0x40 + k) << 1;1657dpst->i2c_addr = new_addr;1658dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */1659if (dib7000p_identify(dpst) != 0) {1660dpst->i2c_addr = default_addr;1661dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */1662if (dib7000p_identify(dpst) != 0) {1663dprintk("DiB7000P #%d: not identified\n", k);1664kfree(dpst);1665return -EIO;1666}1667}16681669/* start diversity to pull_down div_str - just for i2c-enumeration */1670dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);16711672/* set new i2c address and force divstart */1673dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);16741675dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);1676}16771678for (k = 0; k < no_of_demods; k++) {1679dpst->cfg = cfg[k];1680if (cfg[k].default_i2c_addr != 0)1681dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;1682else1683dpst->i2c_addr = (0x40 + k) << 1;16841685// unforce divstr1686dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);16871688/* deactivate div - it was just for i2c-enumeration */1689dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);1690}16911692kfree(dpst);1693return 0;1694}1695EXPORT_SYMBOL(dib7000p_i2c_enumeration);16961697static const s32 lut_1000ln_mant[] = {16986908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 76001699};17001701static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)1702{1703struct dib7000p_state *state = fe->demodulator_priv;1704u32 tmp_val = 0, exp = 0, mant = 0;1705s32 pow_i;1706u16 buf[2];1707u8 ix = 0;17081709buf[0] = dib7000p_read_word(state, 0x184);1710buf[1] = dib7000p_read_word(state, 0x185);1711pow_i = (buf[0] << 16) | buf[1];1712dprintk("raw pow_i = %d", pow_i);17131714tmp_val = pow_i;1715while (tmp_val >>= 1)1716exp++;17171718mant = (pow_i * 1000 / (1 << exp));1719dprintk(" mant = %d exp = %d", mant / 1000, exp);17201721ix = (u8) ((mant - 1000) / 100); /* index of the LUT */1722dprintk(" ix = %d", ix);17231724pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);1725pow_i = (pow_i << 8) / 1000;1726dprintk(" pow_i = %d", pow_i);17271728return pow_i;1729}17301731static int map_addr_to_serpar_number(struct i2c_msg *msg)1732{1733if ((msg->buf[0] <= 15))1734msg->buf[0] -= 1;1735else if (msg->buf[0] == 17)1736msg->buf[0] = 15;1737else if (msg->buf[0] == 16)1738msg->buf[0] = 17;1739else if (msg->buf[0] == 19)1740msg->buf[0] = 16;1741else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)1742msg->buf[0] -= 3;1743else if (msg->buf[0] == 28)1744msg->buf[0] = 23;1745else1746return -EINVAL;1747return 0;1748}17491750static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)1751{1752struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);1753u8 n_overflow = 1;1754u16 i = 1000;1755u16 serpar_num = msg[0].buf[0];17561757while (n_overflow == 1 && i) {1758n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;1759i--;1760if (i == 0)1761dprintk("Tuner ITF: write busy (overflow)");1762}1763dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));1764dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);17651766return num;1767}17681769static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)1770{1771struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);1772u8 n_overflow = 1, n_empty = 1;1773u16 i = 1000;1774u16 serpar_num = msg[0].buf[0];1775u16 read_word;17761777while (n_overflow == 1 && i) {1778n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;1779i--;1780if (i == 0)1781dprintk("TunerITF: read busy (overflow)");1782}1783dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));17841785i = 1000;1786while (n_empty == 1 && i) {1787n_empty = dib7000p_read_word(state, 1984) & 0x1;1788i--;1789if (i == 0)1790dprintk("TunerITF: read busy (empty)");1791}1792read_word = dib7000p_read_word(state, 1987);1793msg[1].buf[0] = (read_word >> 8) & 0xff;1794msg[1].buf[1] = (read_word) & 0xff;17951796return num;1797}17981799static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)1800{1801if (map_addr_to_serpar_number(&msg[0]) == 0) { /* else = Tuner regs to ignore : DIG_CFG, CTRL_RF_LT, PLL_CFG, PWM1_REG, ADCCLK, DIG_CFG_3; SLEEP_EN... */1802if (num == 1) { /* write */1803return w7090p_tuner_write_serpar(i2c_adap, msg, 1);1804} else { /* read */1805return w7090p_tuner_read_serpar(i2c_adap, msg, 2);1806}1807}1808return num;1809}18101811int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num, u16 apb_address)1812{1813struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);1814u16 word;18151816if (num == 1) { /* write */1817dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));1818} else {1819word = dib7000p_read_word(state, apb_address);1820msg[1].buf[0] = (word >> 8) & 0xff;1821msg[1].buf[1] = (word) & 0xff;1822}18231824return num;1825}18261827static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)1828{1829struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);18301831u16 apb_address = 0, word;1832int i = 0;1833switch (msg[0].buf[0]) {1834case 0x12:1835apb_address = 1920;1836break;1837case 0x14:1838apb_address = 1921;1839break;1840case 0x24:1841apb_address = 1922;1842break;1843case 0x1a:1844apb_address = 1923;1845break;1846case 0x22:1847apb_address = 1924;1848break;1849case 0x33:1850apb_address = 1926;1851break;1852case 0x34:1853apb_address = 1927;1854break;1855case 0x35:1856apb_address = 1928;1857break;1858case 0x36:1859apb_address = 1929;1860break;1861case 0x37:1862apb_address = 1930;1863break;1864case 0x38:1865apb_address = 1931;1866break;1867case 0x39:1868apb_address = 1932;1869break;1870case 0x2a:1871apb_address = 1935;1872break;1873case 0x2b:1874apb_address = 1936;1875break;1876case 0x2c:1877apb_address = 1937;1878break;1879case 0x2d:1880apb_address = 1938;1881break;1882case 0x2e:1883apb_address = 1939;1884break;1885case 0x2f:1886apb_address = 1940;1887break;1888case 0x30:1889apb_address = 1941;1890break;1891case 0x31:1892apb_address = 1942;1893break;1894case 0x32:1895apb_address = 1943;1896break;1897case 0x3e:1898apb_address = 1944;1899break;1900case 0x3f:1901apb_address = 1945;1902break;1903case 0x40:1904apb_address = 1948;1905break;1906case 0x25:1907apb_address = 914;1908break;1909case 0x26:1910apb_address = 915;1911break;1912case 0x27:1913apb_address = 916;1914break;1915case 0x28:1916apb_address = 917;1917break;1918case 0x1d:1919i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);1920word = dib7000p_read_word(state, 384 + i);1921msg[1].buf[0] = (word >> 8) & 0xff;1922msg[1].buf[1] = (word) & 0xff;1923return num;1924case 0x1f:1925if (num == 1) { /* write */1926word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);1927word &= 0x3;1928word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);1929dib7000p_write_word(state, 72, word); /* Set the proper input */1930return num;1931}1932}19331934if (apb_address != 0) /* R/W acces via APB */1935return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);1936else /* R/W access via SERPAR */1937return w7090p_tuner_rw_serpar(i2c_adap, msg, num);19381939return 0;1940}19411942static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)1943{1944return I2C_FUNC_I2C;1945}19461947static struct i2c_algorithm dib7090_tuner_xfer_algo = {1948.master_xfer = dib7090_tuner_xfer,1949.functionality = dib7000p_i2c_func,1950};19511952struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)1953{1954struct dib7000p_state *st = fe->demodulator_priv;1955return &st->dib7090_tuner_adap;1956}1957EXPORT_SYMBOL(dib7090_get_i2c_tuner);19581959static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)1960{1961u16 reg;19621963/* drive host bus 2, 3, 4 */1964reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));1965reg |= (drive << 12) | (drive << 6) | drive;1966dib7000p_write_word(state, 1798, reg);19671968/* drive host bus 5,6 */1969reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));1970reg |= (drive << 8) | (drive << 2);1971dib7000p_write_word(state, 1799, reg);19721973/* drive host bus 7, 8, 9 */1974reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));1975reg |= (drive << 12) | (drive << 6) | drive;1976dib7000p_write_word(state, 1800, reg);19771978/* drive host bus 10, 11 */1979reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));1980reg |= (drive << 8) | (drive << 2);1981dib7000p_write_word(state, 1801, reg);19821983/* drive host bus 12, 13, 14 */1984reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));1985reg |= (drive << 12) | (drive << 6) | drive;1986dib7000p_write_word(state, 1802, reg);19871988return 0;1989}19901991static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)1992{1993u32 quantif = 3;1994u32 nom = (insertExtSynchro * P_Kin + syncSize);1995u32 denom = P_Kout;1996u32 syncFreq = ((nom << quantif) / denom);19971998if ((syncFreq & ((1 << quantif) - 1)) != 0)1999syncFreq = (syncFreq >> quantif) + 1;2000else2001syncFreq = (syncFreq >> quantif);20022003if (syncFreq != 0)2004syncFreq = syncFreq - 1;20052006return syncFreq;2007}20082009static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)2010{2011u8 index_buf;2012u16 rx_copy_buf[22];20132014dprintk("Configure DibStream Tx");2015for (index_buf = 0; index_buf < 22; index_buf++)2016rx_copy_buf[index_buf] = dib7000p_read_word(state, 1536+index_buf);20172018dib7000p_write_word(state, 1615, 1);2019dib7000p_write_word(state, 1603, P_Kin);2020dib7000p_write_word(state, 1605, P_Kout);2021dib7000p_write_word(state, 1606, insertExtSynchro);2022dib7000p_write_word(state, 1608, synchroMode);2023dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);2024dib7000p_write_word(state, 1610, syncWord & 0xffff);2025dib7000p_write_word(state, 1612, syncSize);2026dib7000p_write_word(state, 1615, 0);20272028for (index_buf = 0; index_buf < 22; index_buf++)2029dib7000p_write_word(state, 1536+index_buf, rx_copy_buf[index_buf]);20302031return 0;2032}20332034static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,2035u32 dataOutRate)2036{2037u32 syncFreq;20382039dprintk("Configure DibStream Rx");2040if ((P_Kin != 0) && (P_Kout != 0)) {2041syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);2042dib7000p_write_word(state, 1542, syncFreq);2043}2044dib7000p_write_word(state, 1554, 1);2045dib7000p_write_word(state, 1536, P_Kin);2046dib7000p_write_word(state, 1537, P_Kout);2047dib7000p_write_word(state, 1539, synchroMode);2048dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);2049dib7000p_write_word(state, 1541, syncWord & 0xffff);2050dib7000p_write_word(state, 1543, syncSize);2051dib7000p_write_word(state, 1544, dataOutRate);2052dib7000p_write_word(state, 1554, 0);20532054return 0;2055}20562057static int dib7090_enDivOnHostBus(struct dib7000p_state *state)2058{2059u16 reg;20602061dprintk("Enable Diversity on host bus");2062reg = (1 << 8) | (1 << 5);2063dib7000p_write_word(state, 1288, reg);20642065return dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);2066}20672068static int dib7090_enAdcOnHostBus(struct dib7000p_state *state)2069{2070u16 reg;20712072dprintk("Enable ADC on host bus");2073reg = (1 << 7) | (1 << 5);2074dib7000p_write_word(state, 1288, reg);20752076return dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);2077}20782079static int dib7090_enMpegOnHostBus(struct dib7000p_state *state)2080{2081u16 reg;20822083dprintk("Enable Mpeg on host bus");2084reg = (1 << 9) | (1 << 5);2085dib7000p_write_word(state, 1288, reg);20862087return dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);2088}20892090static int dib7090_enMpegInput(struct dib7000p_state *state)2091{2092dprintk("Enable Mpeg input");2093return dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */2094}20952096static int dib7090_enMpegMux(struct dib7000p_state *state, u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)2097{2098u16 reg = (1 << 7) | ((pulseWidth & 0x1f) << 2) | ((enSerialMode & 0x1) << 1) | (enSerialClkDiv2 & 0x1);20992100dprintk("Enable Mpeg mux");2101dib7000p_write_word(state, 1287, reg);21022103reg &= ~(1 << 7);2104dib7000p_write_word(state, 1287, reg);21052106reg = (1 << 4);2107dib7000p_write_word(state, 1288, reg);21082109return 0;2110}21112112static int dib7090_disableMpegMux(struct dib7000p_state *state)2113{2114u16 reg;21152116dprintk("Disable Mpeg mux");2117dib7000p_write_word(state, 1288, 0);21182119reg = dib7000p_read_word(state, 1287);2120reg &= ~(1 << 7);2121dib7000p_write_word(state, 1287, reg);21222123return 0;2124}21252126static int dib7090_set_input_mode(struct dvb_frontend *fe, int mode)2127{2128struct dib7000p_state *state = fe->demodulator_priv;21292130switch (mode) {2131case INPUT_MODE_DIVERSITY:2132dprintk("Enable diversity INPUT");2133dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);2134break;2135case INPUT_MODE_MPEG:2136dprintk("Enable Mpeg INPUT");2137dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */2138break;2139case INPUT_MODE_OFF:2140default:2141dprintk("Disable INPUT");2142dib7090_cfg_DibRx(state, 0, 0, 0, 0, 0, 0, 0);2143break;2144}2145return 0;2146}21472148static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)2149{2150switch (onoff) {2151case 0: /* only use the internal way - not the diversity input */2152dib7090_set_input_mode(fe, INPUT_MODE_MPEG);2153break;2154case 1: /* both ways */2155case 2: /* only the diversity input */2156dib7090_set_input_mode(fe, INPUT_MODE_DIVERSITY);2157break;2158}21592160return 0;2161}21622163static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)2164{2165struct dib7000p_state *state = fe->demodulator_priv;21662167u16 outreg, smo_mode, fifo_threshold;2168u8 prefer_mpeg_mux_use = 1;2169int ret = 0;21702171dib7090_host_bus_drive(state, 1);21722173fifo_threshold = 1792;2174smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);2175outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));21762177switch (mode) {2178case OUTMODE_HIGH_Z:2179outreg = 0;2180break;21812182case OUTMODE_MPEG2_SERIAL:2183if (prefer_mpeg_mux_use) {2184dprintk("Sip 7090P setting output mode TS_SERIAL using Mpeg Mux");2185dib7090_enMpegOnHostBus(state);2186dib7090_enMpegInput(state);2187if (state->cfg.enMpegOutput == 1)2188dib7090_enMpegMux(state, 3, 1, 1);21892190} else { /* Use Smooth block */2191dprintk("Sip 7090P setting output mode TS_SERIAL using Smooth bloc");2192dib7090_disableMpegMux(state);2193dib7000p_write_word(state, 1288, (1 << 6));2194outreg |= (2 << 6) | (0 << 1);2195}2196break;21972198case OUTMODE_MPEG2_PAR_GATED_CLK:2199if (prefer_mpeg_mux_use) {2200dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Mpeg Mux");2201dib7090_enMpegOnHostBus(state);2202dib7090_enMpegInput(state);2203if (state->cfg.enMpegOutput == 1)2204dib7090_enMpegMux(state, 2, 0, 0);2205} else { /* Use Smooth block */2206dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Smooth block");2207dib7090_disableMpegMux(state);2208dib7000p_write_word(state, 1288, (1 << 6));2209outreg |= (0 << 6);2210}2211break;22122213case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */2214dprintk("Sip 7090P setting output mode TS_PARALLEL_CONT using Smooth block");2215dib7090_disableMpegMux(state);2216dib7000p_write_word(state, 1288, (1 << 6));2217outreg |= (1 << 6);2218break;22192220case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */2221dprintk("Sip 7090P setting output mode TS_FIFO using Smooth block");2222dib7090_disableMpegMux(state);2223dib7000p_write_word(state, 1288, (1 << 6));2224outreg |= (5 << 6);2225smo_mode |= (3 << 1);2226fifo_threshold = 512;2227break;22282229case OUTMODE_DIVERSITY:2230dprintk("Sip 7090P setting output mode MODE_DIVERSITY");2231dib7090_disableMpegMux(state);2232dib7090_enDivOnHostBus(state);2233break;22342235case OUTMODE_ANALOG_ADC:2236dprintk("Sip 7090P setting output mode MODE_ANALOG_ADC");2237dib7090_enAdcOnHostBus(state);2238break;2239}22402241if (state->cfg.output_mpeg2_in_188_bytes)2242smo_mode |= (1 << 5);22432244ret |= dib7000p_write_word(state, 235, smo_mode);2245ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */2246ret |= dib7000p_write_word(state, 1286, outreg | (1 << 10)); /* allways set Dout active = 1 !!! */22472248return ret;2249}22502251int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)2252{2253struct dib7000p_state *state = fe->demodulator_priv;2254u16 en_cur_state;22552256dprintk("sleep dib7090: %d", onoff);22572258en_cur_state = dib7000p_read_word(state, 1922);22592260if (en_cur_state > 0xff)2261state->tuner_enable = en_cur_state;22622263if (onoff)2264en_cur_state &= 0x00ff;2265else {2266if (state->tuner_enable != 0)2267en_cur_state = state->tuner_enable;2268}22692270dib7000p_write_word(state, 1922, en_cur_state);22712272return 0;2273}2274EXPORT_SYMBOL(dib7090_tuner_sleep);22752276int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)2277{2278dprintk("AGC restart callback: %d", restart);2279return 0;2280}2281EXPORT_SYMBOL(dib7090_agc_restart);22822283int dib7090_get_adc_power(struct dvb_frontend *fe)2284{2285return dib7000p_get_adc_power(fe);2286}2287EXPORT_SYMBOL(dib7090_get_adc_power);22882289int dib7090_slave_reset(struct dvb_frontend *fe)2290{2291struct dib7000p_state *state = fe->demodulator_priv;2292u16 reg;22932294reg = dib7000p_read_word(state, 1794);2295dib7000p_write_word(state, 1794, reg | (4 << 12));22962297dib7000p_write_word(state, 1032, 0xffff);2298return 0;2299}2300EXPORT_SYMBOL(dib7090_slave_reset);23012302static struct dvb_frontend_ops dib7000p_ops;2303struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)2304{2305struct dvb_frontend *demod;2306struct dib7000p_state *st;2307st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);2308if (st == NULL)2309return NULL;23102311memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));2312st->i2c_adap = i2c_adap;2313st->i2c_addr = i2c_addr;2314st->gpio_val = cfg->gpio_val;2315st->gpio_dir = cfg->gpio_dir;23162317/* Ensure the output mode remains at the previous default if it's2318* not specifically set by the caller.2319*/2320if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))2321st->cfg.output_mode = OUTMODE_MPEG2_FIFO;23222323demod = &st->demod;2324demod->demodulator_priv = st;2325memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));23262327dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */23282329if (dib7000p_identify(st) != 0)2330goto error;23312332st->version = dib7000p_read_word(st, 897);23332334/* FIXME: make sure the dev.parent field is initialized, or else2335request_firmware() will hit an OOPS (this should be moved somewhere2336more common) */23372338dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);23392340/* init 7090 tuner adapter */2341strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));2342st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;2343st->dib7090_tuner_adap.algo_data = NULL;2344st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;2345i2c_set_adapdata(&st->dib7090_tuner_adap, st);2346i2c_add_adapter(&st->dib7090_tuner_adap);23472348dib7000p_demod_reset(st);23492350if (st->version == SOC7090) {2351dib7090_set_output_mode(demod, st->cfg.output_mode);2352dib7090_set_diversity_in(demod, 0);2353}23542355return demod;23562357error:2358kfree(st);2359return NULL;2360}2361EXPORT_SYMBOL(dib7000p_attach);23622363static struct dvb_frontend_ops dib7000p_ops = {2364.info = {2365.name = "DiBcom 7000PC",2366.type = FE_OFDM,2367.frequency_min = 44250000,2368.frequency_max = 867250000,2369.frequency_stepsize = 62500,2370.caps = FE_CAN_INVERSION_AUTO |2371FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |2372FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |2373FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |2374FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,2375},23762377.release = dib7000p_release,23782379.init = dib7000p_wakeup,2380.sleep = dib7000p_sleep,23812382.set_frontend = dib7000p_set_frontend,2383.get_tune_settings = dib7000p_fe_get_tune_settings,2384.get_frontend = dib7000p_get_frontend,23852386.read_status = dib7000p_read_status,2387.read_ber = dib7000p_read_ber,2388.read_signal_strength = dib7000p_read_signal_strength,2389.read_snr = dib7000p_read_snr,2390.read_ucblocks = dib7000p_read_unc_blocks,2391};23922393MODULE_AUTHOR("Olivier Grenie <[email protected]>");2394MODULE_AUTHOR("Patrick Boettcher <[email protected]>");2395MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");2396MODULE_LICENSE("GPL");239723982399