Path: blob/master/drivers/media/dvb/frontends/dib8000.c
15112 views
/*1* Linux-DVB Driver for DiBcom's DiB8000 chip (ISDB-T).2*3* Copyright (C) 2009 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>12#include "dvb_math.h"1314#include "dvb_frontend.h"1516#include "dib8000.h"1718#define LAYER_ALL -119#define LAYER_A 120#define LAYER_B 221#define LAYER_C 32223#define FE_CALLBACK_TIME_NEVER 0xffffffff24#define MAX_NUMBER_OF_FRONTENDS 62526static int debug;27module_param(debug, int, 0644);28MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");2930#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0)3132#define FE_STATUS_TUNE_FAILED 03334struct i2c_device {35struct i2c_adapter *adap;36u8 addr;37u8 *i2c_write_buffer;38u8 *i2c_read_buffer;39};4041struct dib8000_state {42struct dib8000_config cfg;4344struct i2c_device i2c;4546struct dibx000_i2c_master i2c_master;4748u16 wbd_ref;4950u8 current_band;51u32 current_bandwidth;52struct dibx000_agc_config *current_agc;53u32 timf;54u32 timf_default;5556u8 div_force_off:1;57u8 div_state:1;58u16 div_sync_wait;5960u8 agc_state;61u8 differential_constellation;62u8 diversity_onoff;6364s16 ber_monitored_layer;65u16 gpio_dir;66u16 gpio_val;6768u16 revision;69u8 isdbt_cfg_loaded;70enum frontend_tune_state tune_state;71u32 status;7273struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];7475/* for the I2C transfer */76struct i2c_msg msg[2];77u8 i2c_write_buffer[4];78u8 i2c_read_buffer[2];79};8081enum dib8000_power_mode {82DIB8000M_POWER_ALL = 0,83DIB8000M_POWER_INTERFACE_ONLY,84};8586static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)87{88struct i2c_msg msg[2] = {89{.addr = i2c->addr >> 1, .flags = 0,90.buf = i2c->i2c_write_buffer, .len = 2},91{.addr = i2c->addr >> 1, .flags = I2C_M_RD,92.buf = i2c->i2c_read_buffer, .len = 2},93};9495msg[0].buf[0] = reg >> 8;96msg[0].buf[1] = reg & 0xff;9798if (i2c_transfer(i2c->adap, msg, 2) != 2)99dprintk("i2c read error on %d", reg);100101return (msg[1].buf[0] << 8) | msg[1].buf[1];102}103104static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)105{106state->i2c_write_buffer[0] = reg >> 8;107state->i2c_write_buffer[1] = reg & 0xff;108109memset(state->msg, 0, 2 * 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 = 2;114state->msg[1].addr = state->i2c.addr >> 1;115state->msg[1].flags = I2C_M_RD;116state->msg[1].buf = state->i2c_read_buffer;117state->msg[1].len = 2;118119if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)120dprintk("i2c read error on %d", reg);121122return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];123}124125static u32 dib8000_read32(struct dib8000_state *state, u16 reg)126{127u16 rw[2];128129rw[0] = dib8000_read_word(state, reg + 0);130rw[1] = dib8000_read_word(state, reg + 1);131132return ((rw[0] << 16) | (rw[1]));133}134135static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)136{137struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0,138.buf = i2c->i2c_write_buffer, .len = 4};139int ret = 0;140141msg.buf[0] = (reg >> 8) & 0xff;142msg.buf[1] = reg & 0xff;143msg.buf[2] = (val >> 8) & 0xff;144msg.buf[3] = val & 0xff;145146ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;147148return ret;149}150151static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)152{153state->i2c_write_buffer[0] = (reg >> 8) & 0xff;154state->i2c_write_buffer[1] = reg & 0xff;155state->i2c_write_buffer[2] = (val >> 8) & 0xff;156state->i2c_write_buffer[3] = val & 0xff;157158memset(&state->msg[0], 0, sizeof(struct i2c_msg));159state->msg[0].addr = state->i2c.addr >> 1;160state->msg[0].flags = 0;161state->msg[0].buf = state->i2c_write_buffer;162state->msg[0].len = 4;163164return i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;165}166167static const s16 coeff_2k_sb_1seg_dqpsk[8] = {168(769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c,169(920 << 5) | 0x09170};171172static const s16 coeff_2k_sb_1seg[8] = {173(692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f174};175176static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {177(832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11,178(-931 << 5) | 0x0f179};180181static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {182(622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e,183(982 << 5) | 0x0c184};185186static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {187(699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12,188(-720 << 5) | 0x0d189};190191static const s16 coeff_2k_sb_3seg[8] = {192(664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e,193(-610 << 5) | 0x0a194};195196static const s16 coeff_4k_sb_1seg_dqpsk[8] = {197(-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f,198(-922 << 5) | 0x0d199};200201static const s16 coeff_4k_sb_1seg[8] = {202(638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d,203(-655 << 5) | 0x0a204};205206static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {207(-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14,208(-958 << 5) | 0x13209};210211static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {212(-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12,213(-568 << 5) | 0x0f214};215216static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {217(-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14,218(-848 << 5) | 0x13219};220221static const s16 coeff_4k_sb_3seg[8] = {222(612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12,223(-869 << 5) | 0x13224};225226static const s16 coeff_8k_sb_1seg_dqpsk[8] = {227(-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13,228(-598 << 5) | 0x10229};230231static const s16 coeff_8k_sb_1seg[8] = {232(673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f,233(585 << 5) | 0x0f234};235236static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {237(863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18,238(0 << 5) | 0x14239};240241static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {242(-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15,243(-877 << 5) | 0x15244};245246static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {247(-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18,248(-921 << 5) | 0x14249};250251static const s16 coeff_8k_sb_3seg[8] = {252(514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15,253(690 << 5) | 0x14254};255256static const s16 ana_fe_coeff_3seg[24] = {25781, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017258};259260static const s16 ana_fe_coeff_1seg[24] = {261249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003262};263264static const s16 ana_fe_coeff_13seg[24] = {265396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1266};267268static u16 fft_to_mode(struct dib8000_state *state)269{270u16 mode;271switch (state->fe[0]->dtv_property_cache.transmission_mode) {272case TRANSMISSION_MODE_2K:273mode = 1;274break;275case TRANSMISSION_MODE_4K:276mode = 2;277break;278default:279case TRANSMISSION_MODE_AUTO:280case TRANSMISSION_MODE_8K:281mode = 3;282break;283}284return mode;285}286287static void dib8000_set_acquisition_mode(struct dib8000_state *state)288{289u16 nud = dib8000_read_word(state, 298);290nud |= (1 << 3) | (1 << 0);291dprintk("acquisition mode activated");292dib8000_write_word(state, 298, nud);293}294static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)295{296struct dib8000_state *state = fe->demodulator_priv;297298u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */299300outreg = 0;301fifo_threshold = 1792;302smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);303304dprintk("-I- Setting output mode for demod %p to %d",305&state->fe[0], mode);306307switch (mode) {308case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock309outreg = (1 << 10); /* 0x0400 */310break;311case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock312outreg = (1 << 10) | (1 << 6); /* 0x0440 */313break;314case OUTMODE_MPEG2_SERIAL: // STBs with serial input315outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */316break;317case OUTMODE_DIVERSITY:318if (state->cfg.hostbus_diversity) {319outreg = (1 << 10) | (4 << 6); /* 0x0500 */320sram &= 0xfdff;321} else322sram |= 0x0c00;323break;324case OUTMODE_MPEG2_FIFO: // e.g. USB feeding325smo_mode |= (3 << 1);326fifo_threshold = 512;327outreg = (1 << 10) | (5 << 6);328break;329case OUTMODE_HIGH_Z: // disable330outreg = 0;331break;332333case OUTMODE_ANALOG_ADC:334outreg = (1 << 10) | (3 << 6);335dib8000_set_acquisition_mode(state);336break;337338default:339dprintk("Unhandled output_mode passed to be set for demod %p",340&state->fe[0]);341return -EINVAL;342}343344if (state->cfg.output_mpeg2_in_188_bytes)345smo_mode |= (1 << 5);346347dib8000_write_word(state, 299, smo_mode);348dib8000_write_word(state, 300, fifo_threshold); /* synchronous fread */349dib8000_write_word(state, 1286, outreg);350dib8000_write_word(state, 1291, sram);351352return 0;353}354355static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)356{357struct dib8000_state *state = fe->demodulator_priv;358u16 sync_wait = dib8000_read_word(state, 273) & 0xfff0;359360if (!state->differential_constellation) {361dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1362dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2363} else {364dib8000_write_word(state, 272, 0); //dvsy_off_lmod4 = 0365dib8000_write_word(state, 273, sync_wait); // sync_enable = 0; comb_mode = 0366}367state->diversity_onoff = onoff;368369switch (onoff) {370case 0: /* only use the internal way - not the diversity input */371dib8000_write_word(state, 270, 1);372dib8000_write_word(state, 271, 0);373break;374case 1: /* both ways */375dib8000_write_word(state, 270, 6);376dib8000_write_word(state, 271, 6);377break;378case 2: /* only the diversity input */379dib8000_write_word(state, 270, 0);380dib8000_write_word(state, 271, 1);381break;382}383return 0;384}385386static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)387{388/* by default everything is going to be powered off */389u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,390reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,391reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;392393/* now, depending on the requested mode, we power on */394switch (mode) {395/* power up everything in the demod */396case DIB8000M_POWER_ALL:397reg_774 = 0x0000;398reg_775 = 0x0000;399reg_776 = 0x0000;400reg_900 &= 0xfffc;401reg_1280 &= 0x00ff;402break;403case DIB8000M_POWER_INTERFACE_ONLY:404reg_1280 &= 0x00ff;405break;406}407408dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280);409dib8000_write_word(state, 774, reg_774);410dib8000_write_word(state, 775, reg_775);411dib8000_write_word(state, 776, reg_776);412dib8000_write_word(state, 900, reg_900);413dib8000_write_word(state, 1280, reg_1280);414}415416static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)417{418int ret = 0;419u16 reg_907 = dib8000_read_word(state, 907), reg_908 = dib8000_read_word(state, 908);420421switch (no) {422case DIBX000_SLOW_ADC_ON:423reg_908 |= (1 << 1) | (1 << 0);424ret |= dib8000_write_word(state, 908, reg_908);425reg_908 &= ~(1 << 1);426break;427428case DIBX000_SLOW_ADC_OFF:429reg_908 |= (1 << 1) | (1 << 0);430break;431432case DIBX000_ADC_ON:433reg_907 &= 0x0fff;434reg_908 &= 0x0003;435break;436437case DIBX000_ADC_OFF: // leave the VBG voltage on438reg_907 |= (1 << 14) | (1 << 13) | (1 << 12);439reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);440break;441442case DIBX000_VBG_ENABLE:443reg_907 &= ~(1 << 15);444break;445446case DIBX000_VBG_DISABLE:447reg_907 |= (1 << 15);448break;449450default:451break;452}453454ret |= dib8000_write_word(state, 907, reg_907);455ret |= dib8000_write_word(state, 908, reg_908);456457return ret;458}459460static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)461{462struct dib8000_state *state = fe->demodulator_priv;463u32 timf;464465if (bw == 0)466bw = 6000;467468if (state->timf == 0) {469dprintk("using default timf");470timf = state->timf_default;471} else {472dprintk("using updated timf");473timf = state->timf;474}475476dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));477dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));478479return 0;480}481482static int dib8000_sad_calib(struct dib8000_state *state)483{484/* internal */485dib8000_write_word(state, 923, (0 << 1) | (0 << 0));486dib8000_write_word(state, 924, 776); // 0.625*3.3 / 4096487488/* do the calibration */489dib8000_write_word(state, 923, (1 << 0));490dib8000_write_word(state, 923, (0 << 0));491492msleep(1);493return 0;494}495496int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)497{498struct dib8000_state *state = fe->demodulator_priv;499if (value > 4095)500value = 4095;501state->wbd_ref = value;502return dib8000_write_word(state, 106, value);503}504505EXPORT_SYMBOL(dib8000_set_wbd_ref);506static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)507{508dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);509dib8000_write_word(state, 23, (u16) (((bw->internal * 1000) >> 16) & 0xffff)); /* P_sec_len */510dib8000_write_word(state, 24, (u16) ((bw->internal * 1000) & 0xffff));511dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));512dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));513dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));514515dib8000_write_word(state, 922, bw->sad_cfg);516}517518static void dib8000_reset_pll(struct dib8000_state *state)519{520const struct dibx000_bandwidth_config *pll = state->cfg.pll;521u16 clk_cfg1;522523// clk_cfg0524dib8000_write_word(state, 901, (pll->pll_prediv << 8) | (pll->pll_ratio << 0));525526// clk_cfg1527clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |528(pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) |529(pll->pll_range << 1) | (pll->pll_reset << 0);530531dib8000_write_word(state, 902, clk_cfg1);532clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);533dib8000_write_word(state, 902, clk_cfg1);534535dprintk("clk_cfg1: 0x%04x", clk_cfg1); /* 0x507 1 0 1 000 0 0 11 1 */536537/* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */538if (state->cfg.pll->ADClkSrc == 0)539dib8000_write_word(state, 904, (0 << 15) | (0 << 12) | (0 << 10) |540(pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1));541else if (state->cfg.refclksel != 0)542dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |543((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) |544(pll->ADClkSrc << 7) | (0 << 1));545else546dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | (3 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1));547548dib8000_reset_pll_common(state, pll);549}550551static int dib8000_reset_gpio(struct dib8000_state *st)552{553/* reset the GPIOs */554dib8000_write_word(st, 1029, st->cfg.gpio_dir);555dib8000_write_word(st, 1030, st->cfg.gpio_val);556557/* TODO 782 is P_gpio_od */558559dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);560561dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);562return 0;563}564565static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)566{567st->cfg.gpio_dir = dib8000_read_word(st, 1029);568st->cfg.gpio_dir &= ~(1 << num); /* reset the direction bit */569st->cfg.gpio_dir |= (dir & 0x1) << num; /* set the new direction */570dib8000_write_word(st, 1029, st->cfg.gpio_dir);571572st->cfg.gpio_val = dib8000_read_word(st, 1030);573st->cfg.gpio_val &= ~(1 << num); /* reset the direction bit */574st->cfg.gpio_val |= (val & 0x01) << num; /* set the new value */575dib8000_write_word(st, 1030, st->cfg.gpio_val);576577dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val);578579return 0;580}581582int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)583{584struct dib8000_state *state = fe->demodulator_priv;585return dib8000_cfg_gpio(state, num, dir, val);586}587588EXPORT_SYMBOL(dib8000_set_gpio);589static const u16 dib8000_defaults[] = {590/* auto search configuration - lock0 by default waiting591* for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */5923, 7,5930x0004,5940x0400,5950x0814,59659712, 11,5980x001b,5990x7740,6000x005b,6010x8d80,6020x01c9,6030xc380,6040x0000,6050x0080,6060x0000,6070x0090,6080x0001,6090xd4c0,610611/*1, 32,6120x6680 // P_corm_thres Lock algorithms configuration */61361411, 80, /* set ADC level to -16 */615(1 << 13) - 825 - 117,616(1 << 13) - 837 - 117,617(1 << 13) - 811 - 117,618(1 << 13) - 766 - 117,619(1 << 13) - 737 - 117,620(1 << 13) - 693 - 117,621(1 << 13) - 648 - 117,622(1 << 13) - 619 - 117,623(1 << 13) - 575 - 117,624(1 << 13) - 531 - 117,625(1 << 13) - 501 - 117,6266274, 108,6280,6290,6300,6310,6326331, 175,6340x0410,6351, 179,6368192, // P_fft_nb_to_cut6376386, 181,6390x2800, // P_coff_corthres_ ( 2k 4k 8k ) 0x28006400x2800,6410x2800,6420x2800, // P_coff_cpilthres_ ( 2k 4k 8k ) 0x28006430x2800,6440x2800,6456462, 193,6470x0666, // P_pha3_thres6480x0000, // P_cti_use_cpe, P_cti_use_prog6496502, 205,6510x200f, // P_cspu_regul, P_cspu_win_cut6520x000f, // P_des_shift_work6536545, 215,6550x023d, // P_adp_regul_cnt6560x00a4, // P_adp_noise_cnt6570x00a4, // P_adp_regul_ext6580x7ff0, // P_adp_noise_ext6590x3ccc, // P_adp_fil6606611, 230,6620x0000, // P_2d_byp_ti_num6636641, 263,6650x800, //P_equal_thres_wgn6666671, 268,668(2 << 9) | 39, // P_equal_ctrl_synchro, P_equal_speedmode6696701, 270,6710x0001, // P_div_lock0_wait6721, 285,6730x0020, //p_fec_6741, 299,6750x0062, /* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */6766771, 338,678(1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1679(1 << 10) |680(0 << 9) | /* P_ctrl_pre_freq_inh=0 */681(3 << 5) | /* P_ctrl_pre_freq_step=3 */682(1 << 0), /* P_pre_freq_win_len=1 */6836841, 903,685(0 << 4) | 2, // P_divclksel=0 P_divbitsel=2 (was clk=3,bit=1 for MPW)6866870,688};689690static u16 dib8000_identify(struct i2c_device *client)691{692u16 value;693694//because of glitches sometimes695value = dib8000_i2c_read16(client, 896);696697if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {698dprintk("wrong Vendor ID (read=0x%x)", value);699return 0;700}701702value = dib8000_i2c_read16(client, 897);703if (value != 0x8000 && value != 0x8001 && value != 0x8002) {704dprintk("wrong Device ID (%x)", value);705return 0;706}707708switch (value) {709case 0x8000:710dprintk("found DiB8000A");711break;712case 0x8001:713dprintk("found DiB8000B");714break;715case 0x8002:716dprintk("found DiB8000C");717break;718}719return value;720}721722static int dib8000_reset(struct dvb_frontend *fe)723{724struct dib8000_state *state = fe->demodulator_priv;725726dib8000_write_word(state, 1287, 0x0003); /* sram lead in, rdy */727728if ((state->revision = dib8000_identify(&state->i2c)) == 0)729return -EINVAL;730731if (state->revision == 0x8000)732dprintk("error : dib8000 MA not supported");733734dibx000_reset_i2c_master(&state->i2c_master);735736dib8000_set_power_mode(state, DIB8000M_POWER_ALL);737738/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */739dib8000_set_adc_state(state, DIBX000_VBG_ENABLE);740741/* restart all parts */742dib8000_write_word(state, 770, 0xffff);743dib8000_write_word(state, 771, 0xffff);744dib8000_write_word(state, 772, 0xfffc);745dib8000_write_word(state, 898, 0x000c); // sad746dib8000_write_word(state, 1280, 0x004d);747dib8000_write_word(state, 1281, 0x000c);748749dib8000_write_word(state, 770, 0x0000);750dib8000_write_word(state, 771, 0x0000);751dib8000_write_word(state, 772, 0x0000);752dib8000_write_word(state, 898, 0x0004); // sad753dib8000_write_word(state, 1280, 0x0000);754dib8000_write_word(state, 1281, 0x0000);755756/* drives */757if (state->cfg.drives)758dib8000_write_word(state, 906, state->cfg.drives);759else {760dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");761dib8000_write_word(state, 906, 0x2d98); // min drive SDRAM - not optimal - adjust762}763764dib8000_reset_pll(state);765766if (dib8000_reset_gpio(state) != 0)767dprintk("GPIO reset was not successful.");768769if (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0)770dprintk("OUTPUT_MODE could not be resetted.");771772state->current_agc = NULL;773774// P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...775/* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */776if (state->cfg.pll->ifreq == 0)777dib8000_write_word(state, 40, 0x0755); /* P_iqc_corr_inh = 0 enable IQcorr block */778else779dib8000_write_word(state, 40, 0x1f55); /* P_iqc_corr_inh = 1 disable IQcorr block */780781{782u16 l = 0, r;783const u16 *n;784n = dib8000_defaults;785l = *n++;786while (l) {787r = *n++;788do {789dib8000_write_word(state, r, *n++);790r++;791} while (--l);792l = *n++;793}794}795state->isdbt_cfg_loaded = 0;796797//div_cfg override for special configs798if (state->cfg.div_cfg != 0)799dib8000_write_word(state, 903, state->cfg.div_cfg);800801/* unforce divstr regardless whether i2c enumeration was done or not */802dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));803804dib8000_set_bandwidth(fe, 6000);805806dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);807dib8000_sad_calib(state);808dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);809810dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY);811812return 0;813}814815static void dib8000_restart_agc(struct dib8000_state *state)816{817// P_restart_iqc & P_restart_agc818dib8000_write_word(state, 770, 0x0a00);819dib8000_write_word(state, 770, 0x0000);820}821822static int dib8000_update_lna(struct dib8000_state *state)823{824u16 dyn_gain;825826if (state->cfg.update_lna) {827// read dyn_gain here (because it is demod-dependent and not tuner)828dyn_gain = dib8000_read_word(state, 390);829830if (state->cfg.update_lna(state->fe[0], dyn_gain)) {831dib8000_restart_agc(state);832return 1;833}834}835return 0;836}837838static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)839{840struct dibx000_agc_config *agc = NULL;841int i;842if (state->current_band == band && state->current_agc != NULL)843return 0;844state->current_band = band;845846for (i = 0; i < state->cfg.agc_config_count; i++)847if (state->cfg.agc[i].band_caps & band) {848agc = &state->cfg.agc[i];849break;850}851852if (agc == NULL) {853dprintk("no valid AGC configuration found for band 0x%02x", band);854return -EINVAL;855}856857state->current_agc = agc;858859/* AGC */860dib8000_write_word(state, 76, agc->setup);861dib8000_write_word(state, 77, agc->inv_gain);862dib8000_write_word(state, 78, agc->time_stabiliz);863dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);864865// Demod AGC loop configuration866dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);867dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);868869dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",870state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);871872/* AGC continued */873if (state->wbd_ref != 0)874dib8000_write_word(state, 106, state->wbd_ref);875else // use default876dib8000_write_word(state, 106, agc->wbd_ref);877dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));878dib8000_write_word(state, 108, agc->agc1_max);879dib8000_write_word(state, 109, agc->agc1_min);880dib8000_write_word(state, 110, agc->agc2_max);881dib8000_write_word(state, 111, agc->agc2_min);882dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);883dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);884dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);885dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);886887dib8000_write_word(state, 75, agc->agc1_pt3);888dib8000_write_word(state, 923, (dib8000_read_word(state, 923) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); /*LB : 929 -> 923 */889890return 0;891}892893void dib8000_pwm_agc_reset(struct dvb_frontend *fe)894{895struct dib8000_state *state = fe->demodulator_priv;896dib8000_set_adc_state(state, DIBX000_ADC_ON);897dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));898}899EXPORT_SYMBOL(dib8000_pwm_agc_reset);900901static int dib8000_agc_soft_split(struct dib8000_state *state)902{903u16 agc, split_offset;904905if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)906return FE_CALLBACK_TIME_NEVER;907908// n_agc_global909agc = dib8000_read_word(state, 390);910911if (agc > state->current_agc->split.min_thres)912split_offset = state->current_agc->split.min;913else if (agc < state->current_agc->split.max_thres)914split_offset = state->current_agc->split.max;915else916split_offset = state->current_agc->split.max *917(agc - state->current_agc->split.min_thres) /918(state->current_agc->split.max_thres - state->current_agc->split.min_thres);919920dprintk("AGC split_offset: %d", split_offset);921922// P_agc_force_split and P_agc_split_offset923dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);924return 5000;925}926927static int dib8000_agc_startup(struct dvb_frontend *fe)928{929struct dib8000_state *state = fe->demodulator_priv;930enum frontend_tune_state *tune_state = &state->tune_state;931932int ret = 0;933934switch (*tune_state) {935case CT_AGC_START:936// set power-up level: interf+analog+AGC937938dib8000_set_adc_state(state, DIBX000_ADC_ON);939940if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {941*tune_state = CT_AGC_STOP;942state->status = FE_STATUS_TUNE_FAILED;943break;944}945946ret = 70;947*tune_state = CT_AGC_STEP_0;948break;949950case CT_AGC_STEP_0:951//AGC initialization952if (state->cfg.agc_control)953state->cfg.agc_control(fe, 1);954955dib8000_restart_agc(state);956957// wait AGC rough lock time958ret = 50;959*tune_state = CT_AGC_STEP_1;960break;961962case CT_AGC_STEP_1:963// wait AGC accurate lock time964ret = 70;965966if (dib8000_update_lna(state))967// wait only AGC rough lock time968ret = 50;969else970*tune_state = CT_AGC_STEP_2;971break;972973case CT_AGC_STEP_2:974dib8000_agc_soft_split(state);975976if (state->cfg.agc_control)977state->cfg.agc_control(fe, 0);978979*tune_state = CT_AGC_STOP;980break;981default:982ret = dib8000_agc_soft_split(state);983break;984}985return ret;986987}988989static const s32 lut_1000ln_mant[] =990{991908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600992};993994s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)995{996struct dib8000_state *state = fe->demodulator_priv;997u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;998s32 val;9991000val = dib8000_read32(state, 384);1001if (mode) {1002tmp_val = val;1003while (tmp_val >>= 1)1004exp++;1005mant = (val * 1000 / (1<<exp));1006ix = (u8)((mant-1000)/100); /* index of the LUT */1007val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);1008val = (val*256)/1000;1009}1010return val;1011}1012EXPORT_SYMBOL(dib8000_get_adc_power);10131014static void dib8000_update_timf(struct dib8000_state *state)1015{1016u32 timf = state->timf = dib8000_read32(state, 435);10171018dib8000_write_word(state, 29, (u16) (timf >> 16));1019dib8000_write_word(state, 30, (u16) (timf & 0xffff));1020dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);1021}10221023static const u16 adc_target_16dB[11] = {1024(1 << 13) - 825 - 117,1025(1 << 13) - 837 - 117,1026(1 << 13) - 811 - 117,1027(1 << 13) - 766 - 117,1028(1 << 13) - 737 - 117,1029(1 << 13) - 693 - 117,1030(1 << 13) - 648 - 117,1031(1 << 13) - 619 - 117,1032(1 << 13) - 575 - 117,1033(1 << 13) - 531 - 117,1034(1 << 13) - 501 - 1171035};1036static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };10371038static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching)1039{1040u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0;1041u8 guard, crate, constellation, timeI;1042u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff; // All 13 segments enabled1043const s16 *ncoeff = NULL, *ana_fe;1044u16 tmcc_pow = 0;1045u16 coff_pow = 0x2800;1046u16 init_prbs = 0xfff;1047u16 ana_gain = 0;10481049if (state->ber_monitored_layer != LAYER_ALL)1050dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer);1051else1052dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);10531054i = dib8000_read_word(state, 26) & 1; // P_dds_invspec1055dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion^i);10561057if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {1058//compute new dds_freq for the seg and adjust prbs1059int seg_offset =1060state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx -1061(state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) -1062(state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2);1063int clk = state->cfg.pll->internal;1064u32 segtodds = ((u32) (430 << 23) / clk) << 3; // segtodds = SegBW / Fclk * pow(2,26)1065int dds_offset = seg_offset * segtodds;1066int new_dds, sub_channel;1067if ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)1068dds_offset -= (int)(segtodds / 2);10691070if (state->cfg.pll->ifreq == 0) {1071if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) {1072dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);1073new_dds = dds_offset;1074} else1075new_dds = dds_offset;10761077// We shift tuning frequency if the wanted segment is :1078// - the segment of center frequency with an odd total number of segments1079// - the segment to the left of center frequency with an even total number of segments1080// - the segment to the right of center frequency with an even total number of segments1081if ((state->fe[0]->dtv_property_cache.delivery_system == SYS_ISDBT)1082&& (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)1083&& (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)1084&& (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==1085((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))1086|| (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)1087&& (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2)))1088|| (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)1089&& (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==1090((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))1091)) {1092new_dds -= ((u32) (850 << 22) / clk) << 4; // new_dds = 850 (freq shift in KHz) / Fclk * pow(2,26)1093}1094} else {1095if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0)1096new_dds = state->cfg.pll->ifreq - dds_offset;1097else1098new_dds = state->cfg.pll->ifreq + dds_offset;1099}1100dib8000_write_word(state, 27, (u16) ((new_dds >> 16) & 0x01ff));1101dib8000_write_word(state, 28, (u16) (new_dds & 0xffff));1102if (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)1103sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3;1104else1105sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3;1106sub_channel -= 6;11071108if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K1109|| state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) {1110dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); //adp_pass =11111dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); //pha3_force_pha_shift = 11112} else {1113dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); //adp_pass =01114dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); //pha3_force_pha_shift = 01115}11161117switch (state->fe[0]->dtv_property_cache.transmission_mode) {1118case TRANSMISSION_MODE_2K:1119switch (sub_channel) {1120case -6:1121init_prbs = 0x0;1122break; // 41, 0, 11123case -5:1124init_prbs = 0x423;1125break; // 02~041126case -4:1127init_prbs = 0x9;1128break; // 05~071129case -3:1130init_prbs = 0x5C7;1131break; // 08~101132case -2:1133init_prbs = 0x7A6;1134break; // 11~131135case -1:1136init_prbs = 0x3D8;1137break; // 14~161138case 0:1139init_prbs = 0x527;1140break; // 17~191141case 1:1142init_prbs = 0x7FF;1143break; // 20~221144case 2:1145init_prbs = 0x79B;1146break; // 23~251147case 3:1148init_prbs = 0x3D6;1149break; // 26~281150case 4:1151init_prbs = 0x3A2;1152break; // 29~311153case 5:1154init_prbs = 0x53B;1155break; // 32~341156case 6:1157init_prbs = 0x2F4;1158break; // 35~371159default:1160case 7:1161init_prbs = 0x213;1162break; // 38~401163}1164break;11651166case TRANSMISSION_MODE_4K:1167switch (sub_channel) {1168case -6:1169init_prbs = 0x0;1170break; // 41, 0, 11171case -5:1172init_prbs = 0x208;1173break; // 02~041174case -4:1175init_prbs = 0xC3;1176break; // 05~071177case -3:1178init_prbs = 0x7B9;1179break; // 08~101180case -2:1181init_prbs = 0x423;1182break; // 11~131183case -1:1184init_prbs = 0x5C7;1185break; // 14~161186case 0:1187init_prbs = 0x3D8;1188break; // 17~191189case 1:1190init_prbs = 0x7FF;1191break; // 20~221192case 2:1193init_prbs = 0x3D6;1194break; // 23~251195case 3:1196init_prbs = 0x53B;1197break; // 26~281198case 4:1199init_prbs = 0x213;1200break; // 29~311201case 5:1202init_prbs = 0x29;1203break; // 32~341204case 6:1205init_prbs = 0xD0;1206break; // 35~371207default:1208case 7:1209init_prbs = 0x48E;1210break; // 38~401211}1212break;12131214default:1215case TRANSMISSION_MODE_8K:1216switch (sub_channel) {1217case -6:1218init_prbs = 0x0;1219break; // 41, 0, 11220case -5:1221init_prbs = 0x740;1222break; // 02~041223case -4:1224init_prbs = 0x069;1225break; // 05~071226case -3:1227init_prbs = 0x7DD;1228break; // 08~101229case -2:1230init_prbs = 0x208;1231break; // 11~131232case -1:1233init_prbs = 0x7B9;1234break; // 14~161235case 0:1236init_prbs = 0x5C7;1237break; // 17~191238case 1:1239init_prbs = 0x7FF;1240break; // 20~221241case 2:1242init_prbs = 0x53B;1243break; // 23~251244case 3:1245init_prbs = 0x29;1246break; // 26~281247case 4:1248init_prbs = 0x48E;1249break; // 29~311250case 5:1251init_prbs = 0x4C4;1252break; // 32~341253case 6:1254init_prbs = 0x367;1255break; // 33~371256default:1257case 7:1258init_prbs = 0x684;1259break; // 38~401260}1261break;1262}1263} else {1264dib8000_write_word(state, 27, (u16) ((state->cfg.pll->ifreq >> 16) & 0x01ff));1265dib8000_write_word(state, 28, (u16) (state->cfg.pll->ifreq & 0xffff));1266dib8000_write_word(state, 26, (u16) ((state->cfg.pll->ifreq >> 25) & 0x0003));1267}1268/*P_mode == ?? */1269dib8000_write_word(state, 10, (seq << 4));1270// dib8000_write_word(state, 287, (dib8000_read_word(state, 287) & 0xe000) | 0x1000);12711272switch (state->fe[0]->dtv_property_cache.guard_interval) {1273case GUARD_INTERVAL_1_32:1274guard = 0;1275break;1276case GUARD_INTERVAL_1_16:1277guard = 1;1278break;1279case GUARD_INTERVAL_1_8:1280guard = 2;1281break;1282case GUARD_INTERVAL_1_4:1283default:1284guard = 3;1285break;1286}12871288dib8000_write_word(state, 1, (init_prbs << 2) | (guard & 0x3)); // ADDR 112891290max_constellation = DQPSK;1291for (i = 0; i < 3; i++) {1292switch (state->fe[0]->dtv_property_cache.layer[i].modulation) {1293case DQPSK:1294constellation = 0;1295break;1296case QPSK:1297constellation = 1;1298break;1299case QAM_16:1300constellation = 2;1301break;1302case QAM_64:1303default:1304constellation = 3;1305break;1306}13071308switch (state->fe[0]->dtv_property_cache.layer[i].fec) {1309case FEC_1_2:1310crate = 1;1311break;1312case FEC_2_3:1313crate = 2;1314break;1315case FEC_3_4:1316crate = 3;1317break;1318case FEC_5_6:1319crate = 5;1320break;1321case FEC_7_8:1322default:1323crate = 7;1324break;1325}13261327if ((state->fe[0]->dtv_property_cache.layer[i].interleaving > 0) &&1328((state->fe[0]->dtv_property_cache.layer[i].interleaving <= 3) ||1329(state->fe[0]->dtv_property_cache.layer[i].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1))1330)1331timeI = state->fe[0]->dtv_property_cache.layer[i].interleaving;1332else1333timeI = 0;1334dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[i].segment_count & 0xf) << 6) |1335(crate << 3) | timeI);1336if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) {1337switch (max_constellation) {1338case DQPSK:1339case QPSK:1340if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_16 ||1341state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)1342max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;1343break;1344case QAM_16:1345if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)1346max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;1347break;1348}1349}1350}13511352mode = fft_to_mode(state);13531354//dib8000_write_word(state, 5, 13); /*p_last_seg = 13*/13551356dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) |1357((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache.1358isdbt_sb_mode & 1) << 4));13591360dprintk("mode = %d ; guard = %d", mode, state->fe[0]->dtv_property_cache.guard_interval);13611362/* signal optimization parameter */13631364if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) {1365seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0];1366for (i = 1; i < 3; i++)1367nbseg_diff +=1368(state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;1369for (i = 0; i < nbseg_diff; i++)1370seg_diff_mask |= 1 << permu_seg[i + 1];1371} else {1372for (i = 0; i < 3; i++)1373nbseg_diff +=1374(state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;1375for (i = 0; i < nbseg_diff; i++)1376seg_diff_mask |= 1 << permu_seg[i];1377}1378dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask);13791380state->differential_constellation = (seg_diff_mask != 0);1381dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);13821383if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {1384if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)1385seg_mask13 = 0x00E0;1386else // 1-segment1387seg_mask13 = 0x0040;1388} else1389seg_mask13 = 0x1fff;13901391// WRITE: Mode & Diff mask1392dib8000_write_word(state, 0, (mode << 13) | seg_diff_mask);13931394if ((seg_diff_mask) || (state->fe[0]->dtv_property_cache.isdbt_sb_mode))1395dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);1396else1397dib8000_write_word(state, 268, (2 << 9) | 39); //init value13981399// ---- SMALL ----1400// P_small_seg_diff1401dib8000_write_word(state, 352, seg_diff_mask); // ADDR 35214021403dib8000_write_word(state, 353, seg_mask13); // ADDR 35314041405/* // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */14061407// ---- SMALL ----1408if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {1409switch (state->fe[0]->dtv_property_cache.transmission_mode) {1410case TRANSMISSION_MODE_2K:1411if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {1412if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)1413ncoeff = coeff_2k_sb_1seg_dqpsk;1414else // QPSK or QAM1415ncoeff = coeff_2k_sb_1seg;1416} else { // 3-segments1417if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {1418if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)1419ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;1420else // QPSK or QAM on external segments1421ncoeff = coeff_2k_sb_3seg_0dqpsk;1422} else { // QPSK or QAM on central segment1423if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)1424ncoeff = coeff_2k_sb_3seg_1dqpsk;1425else // QPSK or QAM on external segments1426ncoeff = coeff_2k_sb_3seg;1427}1428}1429break;14301431case TRANSMISSION_MODE_4K:1432if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {1433if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)1434ncoeff = coeff_4k_sb_1seg_dqpsk;1435else // QPSK or QAM1436ncoeff = coeff_4k_sb_1seg;1437} else { // 3-segments1438if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {1439if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {1440ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;1441} else { // QPSK or QAM on external segments1442ncoeff = coeff_4k_sb_3seg_0dqpsk;1443}1444} else { // QPSK or QAM on central segment1445if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {1446ncoeff = coeff_4k_sb_3seg_1dqpsk;1447} else // QPSK or QAM on external segments1448ncoeff = coeff_4k_sb_3seg;1449}1450}1451break;14521453case TRANSMISSION_MODE_AUTO:1454case TRANSMISSION_MODE_8K:1455default:1456if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {1457if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)1458ncoeff = coeff_8k_sb_1seg_dqpsk;1459else // QPSK or QAM1460ncoeff = coeff_8k_sb_1seg;1461} else { // 3-segments1462if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {1463if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {1464ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;1465} else { // QPSK or QAM on external segments1466ncoeff = coeff_8k_sb_3seg_0dqpsk;1467}1468} else { // QPSK or QAM on central segment1469if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {1470ncoeff = coeff_8k_sb_3seg_1dqpsk;1471} else // QPSK or QAM on external segments1472ncoeff = coeff_8k_sb_3seg;1473}1474}1475break;1476}1477for (i = 0; i < 8; i++)1478dib8000_write_word(state, 343 + i, ncoeff[i]);1479}14801481// P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=51482dib8000_write_word(state, 351,1483(state->fe[0]->dtv_property_cache.isdbt_sb_mode << 9) | (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5);14841485// ---- COFF ----1486// Carloff, the most robust1487if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {14881489// P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=641490// P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=11491dib8000_write_word(state, 187,1492(4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2)1493| 0x3);14941495/* // P_small_coef_ext_enable = 1 */1496/* dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */14971498if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {14991500// P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width= (P_mode == 3) , P_coff_one_seg_sym= (P_mode-1)1501if (mode == 3)1502dib8000_write_word(state, 180, 0x1fcf | ((mode - 1) << 14));1503else1504dib8000_write_word(state, 180, 0x0fcf | ((mode - 1) << 14));1505// P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1,1506// P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=41507dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);1508// P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=81509dib8000_write_word(state, 340, (16 << 6) | (8 << 0));1510// P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=11511dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));15121513// P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k1514dib8000_write_word(state, 181, 300);1515dib8000_write_word(state, 182, 150);1516dib8000_write_word(state, 183, 80);1517dib8000_write_word(state, 184, 300);1518dib8000_write_word(state, 185, 150);1519dib8000_write_word(state, 186, 80);1520} else { // Sound Broadcasting mode 3 seg1521// P_coff_one_seg_sym= 1, P_coff_one_seg_width= 1, P_coff_winlen=63, P_coff_thres_lock=151522/* if (mode == 3) */1523/* dib8000_write_word(state, 180, 0x2fca | ((0) << 14)); */1524/* else */1525/* dib8000_write_word(state, 180, 0x2fca | ((1) << 14)); */1526dib8000_write_word(state, 180, 0x1fcf | (1 << 14));15271528// P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1,1529// P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=41530dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);1531// P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=81532dib8000_write_word(state, 340, (16 << 6) | (8 << 0));1533//P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=11534dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));15351536// P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k1537dib8000_write_word(state, 181, 350);1538dib8000_write_word(state, 182, 300);1539dib8000_write_word(state, 183, 250);1540dib8000_write_word(state, 184, 350);1541dib8000_write_word(state, 185, 300);1542dib8000_write_word(state, 186, 250);1543}15441545} else if (state->isdbt_cfg_loaded == 0) { // if not Sound Broadcasting mode : put default values for 13 segments1546dib8000_write_word(state, 180, (16 << 6) | 9);1547dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);1548coff_pow = 0x2800;1549for (i = 0; i < 6; i++)1550dib8000_write_word(state, 181 + i, coff_pow);15511552// P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1,1553// P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=11554dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);15551556// P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=61557dib8000_write_word(state, 340, (8 << 6) | (6 << 0));1558// P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=11559dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));1560}1561// ---- FFT ----1562if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 && state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)1563dib8000_write_word(state, 178, 64); // P_fft_powrange=641564else1565dib8000_write_word(state, 178, 32); // P_fft_powrange=3215661567/* make the cpil_coff_lock more robust but slower p_coff_winlen1568* 6bits; p_coff_thres_lock 6bits (for coff lock if needed)1569*/1570/* if ( ( nbseg_diff>0)&&(nbseg_diff<13))1571dib8000_write_word(state, 187, (dib8000_read_word(state, 187) & 0xfffb) | (1 << 3)); */15721573dib8000_write_word(state, 189, ~seg_mask13 | seg_diff_mask); /* P_lmod4_seg_inh */1574dib8000_write_word(state, 192, ~seg_mask13 | seg_diff_mask); /* P_pha3_seg_inh */1575dib8000_write_word(state, 225, ~seg_mask13 | seg_diff_mask); /* P_tac_seg_inh */1576if ((!state->fe[0]->dtv_property_cache.isdbt_sb_mode) && (state->cfg.pll->ifreq == 0))1577dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */1578else1579dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask); /* P_equal_noise_seg_inh */1580dib8000_write_word(state, 287, ~seg_mask13 | 0x1000); /* P_tmcc_seg_inh */1581//dib8000_write_word(state, 288, ~seg_mask13 | seg_diff_mask); /* P_tmcc_seg_eq_inh */1582if (!autosearching)1583dib8000_write_word(state, 288, (~seg_mask13 | seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */1584else1585dib8000_write_word(state, 288, 0x1fff); //disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels.1586dprintk("287 = %X (%d)", ~seg_mask13 | 0x1000, ~seg_mask13 | 0x1000);15871588dib8000_write_word(state, 211, seg_mask13 & (~seg_diff_mask)); /* P_des_seg_enabled */15891590/* offset loop parameters */1591if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {1592if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)1593/* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */1594dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x40);15951596else // Sound Broadcasting mode 3 seg1597/* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */1598dib8000_write_word(state, 32, ((10 - mode) << 12) | (6 << 8) | 0x60);1599} else1600// TODO in 13 seg, timf_alpha can always be the same or not ?1601/* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */1602dib8000_write_word(state, 32, ((9 - mode) << 12) | (6 << 8) | 0x80);16031604if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {1605if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)1606/* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (11-P_mode) */1607dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (10 - mode));16081609else // Sound Broadcasting mode 3 seg1610/* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */1611dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (9 - mode));1612} else1613/* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = 9 */1614dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (8 - mode));16151616/* P_dvsy_sync_wait - reuse mode */1617switch (state->fe[0]->dtv_property_cache.transmission_mode) {1618case TRANSMISSION_MODE_8K:1619mode = 256;1620break;1621case TRANSMISSION_MODE_4K:1622mode = 128;1623break;1624default:1625case TRANSMISSION_MODE_2K:1626mode = 64;1627break;1628}1629if (state->cfg.diversity_delay == 0)1630mode = (mode * (1 << (guard)) * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo1631else1632mode = (mode * (1 << (guard)) * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for DVSY-fifo1633mode <<= 4;1634dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | mode);16351636/* channel estimation fine configuration */1637switch (max_constellation) {1638case QAM_64:1639ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB1640coeff[0] = 0x0148; /* P_adp_regul_cnt 0.04 */1641coeff[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */1642coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */1643coeff[3] = 0xfff8; /* P_adp_noise_ext -0.001 */1644//if (!state->cfg.hostbus_diversity) //if diversity, we should prehaps use the configuration of the max_constallation -11645break;1646case QAM_16:1647ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB1648coeff[0] = 0x023d; /* P_adp_regul_cnt 0.07 */1649coeff[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */1650coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */1651coeff[3] = 0xfff0; /* P_adp_noise_ext -0.002 */1652//if (!((state->cfg.hostbus_diversity) && (max_constellation == QAM_16)))1653break;1654default:1655ana_gain = 0; // 0 : goes along with ADC target at -22dB to keep good mobile performance and lock at sensitivity level1656coeff[0] = 0x099a; /* P_adp_regul_cnt 0.3 */1657coeff[1] = 0xffae; /* P_adp_noise_cnt -0.01 */1658coeff[2] = 0x0333; /* P_adp_regul_ext 0.1 */1659coeff[3] = 0xfff8; /* P_adp_noise_ext -0.002 */1660break;1661}1662for (mode = 0; mode < 4; mode++)1663dib8000_write_word(state, 215 + mode, coeff[mode]);16641665// update ana_gain depending on max constellation1666dib8000_write_word(state, 116, ana_gain);1667// update ADC target depending on ana_gain1668if (ana_gain) { // set -16dB ADC target for ana_gain=-11669for (i = 0; i < 10; i++)1670dib8000_write_word(state, 80 + i, adc_target_16dB[i]);1671} else { // set -22dB ADC target for ana_gain=01672for (i = 0; i < 10; i++)1673dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);1674}16751676// ---- ANA_FE ----1677if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {1678if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)1679ana_fe = ana_fe_coeff_3seg;1680else // 1-segment1681ana_fe = ana_fe_coeff_1seg;1682} else1683ana_fe = ana_fe_coeff_13seg;16841685if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 || state->isdbt_cfg_loaded == 0)1686for (mode = 0; mode < 24; mode++)1687dib8000_write_word(state, 117 + mode, ana_fe[mode]);16881689// ---- CHAN_BLK ----1690for (i = 0; i < 13; i++) {1691if ((((~seg_diff_mask) >> i) & 1) == 1) {1692P_cfr_left_edge += (1 << i) * ((i == 0) || ((((seg_mask13 & (~seg_diff_mask)) >> (i - 1)) & 1) == 0));1693P_cfr_right_edge += (1 << i) * ((i == 12) || ((((seg_mask13 & (~seg_diff_mask)) >> (i + 1)) & 1) == 0));1694}1695}1696dib8000_write_word(state, 222, P_cfr_left_edge); // P_cfr_left_edge1697dib8000_write_word(state, 223, P_cfr_right_edge); // P_cfr_right_edge1698// "P_cspu_left_edge" not used => do not care1699// "P_cspu_right_edge" not used => do not care17001701if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {1702dib8000_write_word(state, 228, 1); // P_2d_mode_byp=11703dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); // P_cspu_win_cut = 01704if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 01705&& state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) {1706//dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); // P_adp_pass = 01707dib8000_write_word(state, 265, 15); // P_equal_noise_sel = 151708}1709} else if (state->isdbt_cfg_loaded == 0) {1710dib8000_write_word(state, 228, 0); // default value1711dib8000_write_word(state, 265, 31); // default value1712dib8000_write_word(state, 205, 0x200f); // init value1713}1714// ---- TMCC ----1715for (i = 0; i < 3; i++)1716tmcc_pow +=1717(((state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe[0]->dtv_property_cache.layer[i].segment_count);1718// Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9);1719// Threshold is set at 1/4 of max power.1720tmcc_pow *= (1 << (9 - 2));17211722dib8000_write_word(state, 290, tmcc_pow); // P_tmcc_dec_thres_2k1723dib8000_write_word(state, 291, tmcc_pow); // P_tmcc_dec_thres_4k1724dib8000_write_word(state, 292, tmcc_pow); // P_tmcc_dec_thres_8k1725//dib8000_write_word(state, 287, (1 << 13) | 0x1000 );1726// ---- PHA3 ----17271728if (state->isdbt_cfg_loaded == 0)1729dib8000_write_word(state, 250, 3285); /*p_2d_hspeed_thr0 */17301731if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)1732state->isdbt_cfg_loaded = 0;1733else1734state->isdbt_cfg_loaded = 1;17351736}17371738static int dib8000_autosearch_start(struct dvb_frontend *fe)1739{1740u8 factor;1741u32 value;1742struct dib8000_state *state = fe->demodulator_priv;17431744int slist = 0;17451746state->fe[0]->dtv_property_cache.inversion = 0;1747if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode)1748state->fe[0]->dtv_property_cache.layer[0].segment_count = 13;1749state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64;1750state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3;1751state->fe[0]->dtv_property_cache.layer[0].interleaving = 0;17521753//choose the right list, in sb, always do everything1754if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {1755state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;1756state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;1757slist = 7;1758dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));1759} else {1760if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) {1761if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {1762slist = 7;1763dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 to have autosearch start ok with mode21764} else1765slist = 3;1766} else {1767if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {1768slist = 2;1769dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 11770} else1771slist = 0;1772}17731774if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO)1775state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;1776if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO)1777state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;17781779dprintk("using list for autosearch : %d", slist);1780dib8000_set_channel(state, (unsigned char)slist, 1);1781//dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 117821783factor = 1;17841785//set lock_mask values1786dib8000_write_word(state, 6, 0x4);1787dib8000_write_word(state, 7, 0x8);1788dib8000_write_word(state, 8, 0x1000);17891790//set lock_mask wait time values1791value = 50 * state->cfg.pll->internal * factor;1792dib8000_write_word(state, 11, (u16) ((value >> 16) & 0xffff)); // lock0 wait time1793dib8000_write_word(state, 12, (u16) (value & 0xffff)); // lock0 wait time1794value = 100 * state->cfg.pll->internal * factor;1795dib8000_write_word(state, 13, (u16) ((value >> 16) & 0xffff)); // lock1 wait time1796dib8000_write_word(state, 14, (u16) (value & 0xffff)); // lock1 wait time1797value = 1000 * state->cfg.pll->internal * factor;1798dib8000_write_word(state, 15, (u16) ((value >> 16) & 0xffff)); // lock2 wait time1799dib8000_write_word(state, 16, (u16) (value & 0xffff)); // lock2 wait time18001801value = dib8000_read_word(state, 0);1802dib8000_write_word(state, 0, (u16) ((1 << 15) | value));1803dib8000_read_word(state, 1284); // reset the INT. n_irq_pending1804dib8000_write_word(state, 0, (u16) value);18051806}18071808return 0;1809}18101811static int dib8000_autosearch_irq(struct dvb_frontend *fe)1812{1813struct dib8000_state *state = fe->demodulator_priv;1814u16 irq_pending = dib8000_read_word(state, 1284);18151816if (irq_pending & 0x1) { // failed1817dprintk("dib8000_autosearch_irq failed");1818return 1;1819}18201821if (irq_pending & 0x2) { // succeeded1822dprintk("dib8000_autosearch_irq succeeded");1823return 2;1824}18251826return 0; // still pending1827}18281829static int dib8000_tune(struct dvb_frontend *fe)1830{1831struct dib8000_state *state = fe->demodulator_priv;1832int ret = 0;1833u16 value, mode = fft_to_mode(state);18341835// we are already tuned - just resuming from suspend1836if (state == NULL)1837return -EINVAL;18381839dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000);1840dib8000_set_channel(state, 0, 0);18411842// restart demod1843ret |= dib8000_write_word(state, 770, 0x4000);1844ret |= dib8000_write_word(state, 770, 0x0000);1845msleep(45);18461847/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3 */1848/* ret |= dib8000_write_word(state, 29, (0 << 9) | (4 << 5) | (0 << 4) | (3 << 0) ); workaround inh_isi stays at 1 */18491850// never achieved a lock before - wait for timfreq to update1851if (state->timf == 0) {1852if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {1853if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)1854msleep(300);1855else // Sound Broadcasting mode 3 seg1856msleep(500);1857} else // 13 seg1858msleep(200);1859}1860if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {1861if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {18621863/* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40 alpha to check on board */1864dib8000_write_word(state, 32, ((13 - mode) << 12) | (6 << 8) | 0x40);1865//dib8000_write_word(state, 32, (8 << 12) | (6 << 8) | 0x80);18661867/* P_ctrl_sfreq_step= (12-P_mode) P_ctrl_sfreq_inh =0 P_ctrl_pha_off_max */1868ret |= dib8000_write_word(state, 37, (12 - mode) | ((5 + mode) << 5));18691870} else { // Sound Broadcasting mode 3 seg18711872/* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 alpha to check on board */1873dib8000_write_word(state, 32, ((12 - mode) << 12) | (6 << 8) | 0x60);18741875ret |= dib8000_write_word(state, 37, (11 - mode) | ((5 + mode) << 5));1876}18771878} else { // 13 seg1879/* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 alpha to check on board */1880dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x80);18811882ret |= dib8000_write_word(state, 37, (10 - mode) | ((5 + mode) << 5));18831884}18851886// we achieved a coff_cpil_lock - it's time to update the timf1887if ((dib8000_read_word(state, 568) >> 11) & 0x1)1888dib8000_update_timf(state);18891890//now that tune is finished, lock0 should lock on fec_mpeg to output this lock on MP_LOCK. It's changed in autosearch start1891dib8000_write_word(state, 6, 0x200);18921893if (state->revision == 0x8002) {1894value = dib8000_read_word(state, 903);1895dib8000_write_word(state, 903, value & ~(1 << 3));1896msleep(1);1897dib8000_write_word(state, 903, value | (1 << 3));1898}18991900return ret;1901}19021903static int dib8000_wakeup(struct dvb_frontend *fe)1904{1905struct dib8000_state *state = fe->demodulator_priv;1906u8 index_frontend;1907int ret;19081909dib8000_set_power_mode(state, DIB8000M_POWER_ALL);1910dib8000_set_adc_state(state, DIBX000_ADC_ON);1911if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)1912dprintk("could not start Slow ADC");19131914for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {1915ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);1916if (ret < 0)1917return ret;1918}19191920return 0;1921}19221923static int dib8000_sleep(struct dvb_frontend *fe)1924{1925struct dib8000_state *state = fe->demodulator_priv;1926u8 index_frontend;1927int ret;19281929for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {1930ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);1931if (ret < 0)1932return ret;1933}19341935dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);1936dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY);1937return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);1938}19391940enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)1941{1942struct dib8000_state *state = fe->demodulator_priv;1943return state->tune_state;1944}1945EXPORT_SYMBOL(dib8000_get_tune_state);19461947int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)1948{1949struct dib8000_state *state = fe->demodulator_priv;1950state->tune_state = tune_state;1951return 0;1952}1953EXPORT_SYMBOL(dib8000_set_tune_state);19541955static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)1956{1957struct dib8000_state *state = fe->demodulator_priv;1958u16 i, val = 0;1959fe_status_t stat;1960u8 index_frontend, sub_index_frontend;19611962fe->dtv_property_cache.bandwidth_hz = 6000000;19631964for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {1965state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);1966if (stat&FE_HAS_SYNC) {1967dprintk("TMCC lock on the slave%i", index_frontend);1968/* synchronize the cache with the other frontends */1969state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep);1970for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) {1971if (sub_index_frontend != index_frontend) {1972state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;1973state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;1974state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;1975state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;1976state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;1977for (i = 0; i < 3; i++) {1978state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;1979state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;1980state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;1981state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;1982}1983}1984}1985return 0;1986}1987}19881989fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;19901991val = dib8000_read_word(state, 570);1992fe->dtv_property_cache.inversion = (val & 0x40) >> 6;1993switch ((val & 0x30) >> 4) {1994case 1:1995fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;1996break;1997case 3:1998default:1999fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;2000break;2001}20022003switch (val & 0x3) {2004case 0:2005fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;2006dprintk("dib8000_get_frontend GI = 1/32 ");2007break;2008case 1:2009fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;2010dprintk("dib8000_get_frontend GI = 1/16 ");2011break;2012case 2:2013dprintk("dib8000_get_frontend GI = 1/8 ");2014fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;2015break;2016case 3:2017dprintk("dib8000_get_frontend GI = 1/4 ");2018fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;2019break;2020}20212022val = dib8000_read_word(state, 505);2023fe->dtv_property_cache.isdbt_partial_reception = val & 1;2024dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);20252026for (i = 0; i < 3; i++) {2027val = dib8000_read_word(state, 493 + i);2028fe->dtv_property_cache.layer[i].segment_count = val & 0x0F;2029dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count);20302031val = dib8000_read_word(state, 499 + i);2032fe->dtv_property_cache.layer[i].interleaving = val & 0x3;2033dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving);20342035val = dib8000_read_word(state, 481 + i);2036switch (val & 0x7) {2037case 1:2038fe->dtv_property_cache.layer[i].fec = FEC_1_2;2039dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i);2040break;2041case 2:2042fe->dtv_property_cache.layer[i].fec = FEC_2_3;2043dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i);2044break;2045case 3:2046fe->dtv_property_cache.layer[i].fec = FEC_3_4;2047dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i);2048break;2049case 5:2050fe->dtv_property_cache.layer[i].fec = FEC_5_6;2051dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i);2052break;2053default:2054fe->dtv_property_cache.layer[i].fec = FEC_7_8;2055dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i);2056break;2057}20582059val = dib8000_read_word(state, 487 + i);2060switch (val & 0x3) {2061case 0:2062dprintk("dib8000_get_frontend : Layer %d DQPSK ", i);2063fe->dtv_property_cache.layer[i].modulation = DQPSK;2064break;2065case 1:2066fe->dtv_property_cache.layer[i].modulation = QPSK;2067dprintk("dib8000_get_frontend : Layer %d QPSK ", i);2068break;2069case 2:2070fe->dtv_property_cache.layer[i].modulation = QAM_16;2071dprintk("dib8000_get_frontend : Layer %d QAM16 ", i);2072break;2073case 3:2074default:2075dprintk("dib8000_get_frontend : Layer %d QAM64 ", i);2076fe->dtv_property_cache.layer[i].modulation = QAM_64;2077break;2078}2079}20802081/* synchronize the cache with the other frontends */2082for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {2083state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode;2084state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;2085state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;2086state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;2087state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception;2088for (i = 0; i < 3; i++) {2089state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count;2090state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving;2091state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec;2092state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation;2093}2094}2095return 0;2096}20972098static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)2099{2100struct dib8000_state *state = fe->demodulator_priv;2101u8 nbr_pending, exit_condition, index_frontend;2102s8 index_frontend_success = -1;2103int time, ret;2104int time_slave = FE_CALLBACK_TIME_NEVER;21052106if (state->fe[0]->dtv_property_cache.frequency == 0) {2107dprintk("dib8000: must at least specify frequency ");2108return 0;2109}21102111if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) {2112dprintk("dib8000: no bandwidth specified, set to default ");2113state->fe[0]->dtv_property_cache.bandwidth_hz = 6000000;2114}21152116for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {2117/* synchronization of the cache */2118state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;2119memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));21202121dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z);2122if (state->fe[index_frontend]->ops.tuner_ops.set_params)2123state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend], fep);21242125dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);2126}21272128/* start up the AGC */2129do {2130time = dib8000_agc_startup(state->fe[0]);2131for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {2132time_slave = dib8000_agc_startup(state->fe[index_frontend]);2133if (time == FE_CALLBACK_TIME_NEVER)2134time = time_slave;2135else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time))2136time = time_slave;2137}2138if (time != FE_CALLBACK_TIME_NEVER)2139msleep(time / 10);2140else2141break;2142exit_condition = 1;2143for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {2144if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {2145exit_condition = 0;2146break;2147}2148}2149} while (exit_condition == 0);21502151for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)2152dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);21532154if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) ||2155(state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) ||2156(state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) ||2157(state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) ||2158(((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) &&2159(state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) &&2160(state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) &&2161((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) ||2162(state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) ||2163(((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) &&2164(state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) &&2165(state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) &&2166((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) ||2167(state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) ||2168(((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) &&2169(state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) &&2170(state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) &&2171((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) ||2172(state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) ||2173(((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) ||2174((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) &&2175((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) ||2176((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) &&2177((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) {2178int i = 80000;2179u8 found = 0;2180u8 tune_failed = 0;21812182for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {2183dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000);2184dib8000_autosearch_start(state->fe[index_frontend]);2185}21862187do {2188msleep(20);2189nbr_pending = 0;2190exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */2191for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {2192if (((tune_failed >> index_frontend) & 0x1) == 0) {2193found = dib8000_autosearch_irq(state->fe[index_frontend]);2194switch (found) {2195case 0: /* tune pending */2196nbr_pending++;2197break;2198case 2:2199dprintk("autosearch succeed on the frontend%i", index_frontend);2200exit_condition = 2;2201index_frontend_success = index_frontend;2202break;2203default:2204dprintk("unhandled autosearch result");2205case 1:2206dprintk("autosearch failed for the frontend%i", index_frontend);2207break;2208}2209}2210}22112212/* if all tune are done and no success, exit: tune failed */2213if ((nbr_pending == 0) && (exit_condition == 0))2214exit_condition = 1;2215} while ((exit_condition == 0) && i--);22162217if (exit_condition == 1) { /* tune failed */2218dprintk("tune failed");2219return 0;2220}22212222dprintk("tune success on frontend%i", index_frontend_success);22232224dib8000_get_frontend(fe, fep);2225}22262227for (index_frontend = 0, ret = 0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)2228ret = dib8000_tune(state->fe[index_frontend]);22292230/* set output mode and diversity input */2231dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);2232for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {2233dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY);2234dib8000_set_diversity_in(state->fe[index_frontend-1], 1);2235}22362237/* turn off the diversity of the last chip */2238dib8000_set_diversity_in(state->fe[index_frontend-1], 0);22392240return ret;2241}22422243static u16 dib8000_read_lock(struct dvb_frontend *fe)2244{2245struct dib8000_state *state = fe->demodulator_priv;22462247return dib8000_read_word(state, 568);2248}22492250static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)2251{2252struct dib8000_state *state = fe->demodulator_priv;2253u16 lock_slave = 0, lock = dib8000_read_word(state, 568);2254u8 index_frontend;22552256for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)2257lock_slave |= dib8000_read_lock(state->fe[index_frontend]);22582259*stat = 0;22602261if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))2262*stat |= FE_HAS_SIGNAL;22632264if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */2265*stat |= FE_HAS_CARRIER;22662267if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */2268*stat |= FE_HAS_SYNC;22692270if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */2271*stat |= FE_HAS_LOCK;22722273if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {2274lock = dib8000_read_word(state, 554); /* Viterbi Layer A */2275if (lock & 0x01)2276*stat |= FE_HAS_VITERBI;22772278lock = dib8000_read_word(state, 555); /* Viterbi Layer B */2279if (lock & 0x01)2280*stat |= FE_HAS_VITERBI;22812282lock = dib8000_read_word(state, 556); /* Viterbi Layer C */2283if (lock & 0x01)2284*stat |= FE_HAS_VITERBI;2285}22862287return 0;2288}22892290static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)2291{2292struct dib8000_state *state = fe->demodulator_priv;2293*ber = (dib8000_read_word(state, 560) << 16) | dib8000_read_word(state, 561); // 13 segments2294return 0;2295}22962297static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)2298{2299struct dib8000_state *state = fe->demodulator_priv;2300*unc = dib8000_read_word(state, 565); // packet error on 13 seg2301return 0;2302}23032304static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)2305{2306struct dib8000_state *state = fe->demodulator_priv;2307u8 index_frontend;2308u16 val;23092310*strength = 0;2311for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {2312state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);2313if (val > 65535 - *strength)2314*strength = 65535;2315else2316*strength += val;2317}23182319val = 65535 - dib8000_read_word(state, 390);2320if (val > 65535 - *strength)2321*strength = 65535;2322else2323*strength += val;2324return 0;2325}23262327static u32 dib8000_get_snr(struct dvb_frontend *fe)2328{2329struct dib8000_state *state = fe->demodulator_priv;2330u32 n, s, exp;2331u16 val;23322333val = dib8000_read_word(state, 542);2334n = (val >> 6) & 0xff;2335exp = (val & 0x3f);2336if ((exp & 0x20) != 0)2337exp -= 0x40;2338n <<= exp+16;23392340val = dib8000_read_word(state, 543);2341s = (val >> 6) & 0xff;2342exp = (val & 0x3f);2343if ((exp & 0x20) != 0)2344exp -= 0x40;2345s <<= exp+16;23462347if (n > 0) {2348u32 t = (s/n) << 16;2349return t + ((s << 16) - n*t) / n;2350}2351return 0xffffffff;2352}23532354static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)2355{2356struct dib8000_state *state = fe->demodulator_priv;2357u8 index_frontend;2358u32 snr_master;23592360snr_master = dib8000_get_snr(fe);2361for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)2362snr_master += dib8000_get_snr(state->fe[index_frontend]);23632364if (snr_master != 0) {2365snr_master = 10*intlog10(snr_master>>16);2366*snr = snr_master / ((1 << 24) / 10);2367}2368else2369*snr = 0;23702371return 0;2372}23732374int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)2375{2376struct dib8000_state *state = fe->demodulator_priv;2377u8 index_frontend = 1;23782379while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))2380index_frontend++;2381if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {2382dprintk("set slave fe %p to index %i", fe_slave, index_frontend);2383state->fe[index_frontend] = fe_slave;2384return 0;2385}23862387dprintk("too many slave frontend");2388return -ENOMEM;2389}2390EXPORT_SYMBOL(dib8000_set_slave_frontend);23912392int dib8000_remove_slave_frontend(struct dvb_frontend *fe)2393{2394struct dib8000_state *state = fe->demodulator_priv;2395u8 index_frontend = 1;23962397while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))2398index_frontend++;2399if (index_frontend != 1) {2400dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1);2401state->fe[index_frontend] = NULL;2402return 0;2403}24042405dprintk("no frontend to be removed");2406return -ENODEV;2407}2408EXPORT_SYMBOL(dib8000_remove_slave_frontend);24092410struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)2411{2412struct dib8000_state *state = fe->demodulator_priv;24132414if (slave_index >= MAX_NUMBER_OF_FRONTENDS)2415return NULL;2416return state->fe[slave_index];2417}2418EXPORT_SYMBOL(dib8000_get_slave_frontend);241924202421int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)2422{2423int k = 0, ret = 0;2424u8 new_addr = 0;2425struct i2c_device client = {.adap = host };24262427client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);2428if (!client.i2c_write_buffer) {2429dprintk("%s: not enough memory", __func__);2430return -ENOMEM;2431}2432client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);2433if (!client.i2c_read_buffer) {2434dprintk("%s: not enough memory", __func__);2435ret = -ENOMEM;2436goto error_memory;2437}24382439for (k = no_of_demods - 1; k >= 0; k--) {2440/* designated i2c address */2441new_addr = first_addr + (k << 1);24422443client.addr = new_addr;2444dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */2445if (dib8000_identify(&client) == 0) {2446dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */2447client.addr = default_addr;2448if (dib8000_identify(&client) == 0) {2449dprintk("#%d: not identified", k);2450ret = -EINVAL;2451goto error;2452}2453}24542455/* start diversity to pull_down div_str - just for i2c-enumeration */2456dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));24572458/* set new i2c address and force divstart */2459dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);2460client.addr = new_addr;2461dib8000_identify(&client);24622463dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);2464}24652466for (k = 0; k < no_of_demods; k++) {2467new_addr = first_addr | (k << 1);2468client.addr = new_addr;24692470// unforce divstr2471dib8000_i2c_write16(&client, 1285, new_addr << 2);24722473/* deactivate div - it was just for i2c-enumeration */2474dib8000_i2c_write16(&client, 1286, 0);2475}24762477error:2478kfree(client.i2c_read_buffer);2479error_memory:2480kfree(client.i2c_write_buffer);24812482return ret;2483}24842485EXPORT_SYMBOL(dib8000_i2c_enumeration);2486static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)2487{2488tune->min_delay_ms = 1000;2489tune->step_size = 0;2490tune->max_drift = 0;2491return 0;2492}24932494static void dib8000_release(struct dvb_frontend *fe)2495{2496struct dib8000_state *st = fe->demodulator_priv;2497u8 index_frontend;24982499for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)2500dvb_frontend_detach(st->fe[index_frontend]);25012502dibx000_exit_i2c_master(&st->i2c_master);2503kfree(st->fe[0]);2504kfree(st);2505}25062507struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)2508{2509struct dib8000_state *st = fe->demodulator_priv;2510return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);2511}25122513EXPORT_SYMBOL(dib8000_get_i2c_master);25142515int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)2516{2517struct dib8000_state *st = fe->demodulator_priv;2518u16 val = dib8000_read_word(st, 299) & 0xffef;2519val |= (onoff & 0x1) << 4;25202521dprintk("pid filter enabled %d", onoff);2522return dib8000_write_word(st, 299, val);2523}2524EXPORT_SYMBOL(dib8000_pid_filter_ctrl);25252526int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)2527{2528struct dib8000_state *st = fe->demodulator_priv;2529dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);2530return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);2531}2532EXPORT_SYMBOL(dib8000_pid_filter);25332534static const struct dvb_frontend_ops dib8000_ops = {2535.info = {2536.name = "DiBcom 8000 ISDB-T",2537.type = FE_OFDM,2538.frequency_min = 44250000,2539.frequency_max = 867250000,2540.frequency_stepsize = 62500,2541.caps = FE_CAN_INVERSION_AUTO |2542FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |2543FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |2544FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |2545FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,2546},25472548.release = dib8000_release,25492550.init = dib8000_wakeup,2551.sleep = dib8000_sleep,25522553.set_frontend = dib8000_set_frontend,2554.get_tune_settings = dib8000_fe_get_tune_settings,2555.get_frontend = dib8000_get_frontend,25562557.read_status = dib8000_read_status,2558.read_ber = dib8000_read_ber,2559.read_signal_strength = dib8000_read_signal_strength,2560.read_snr = dib8000_read_snr,2561.read_ucblocks = dib8000_read_unc_blocks,2562};25632564struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)2565{2566struct dvb_frontend *fe;2567struct dib8000_state *state;25682569dprintk("dib8000_attach");25702571state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);2572if (state == NULL)2573return NULL;2574fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);2575if (fe == NULL)2576goto error;25772578memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));2579state->i2c.adap = i2c_adap;2580state->i2c.addr = i2c_addr;2581state->i2c.i2c_write_buffer = state->i2c_write_buffer;2582state->i2c.i2c_read_buffer = state->i2c_read_buffer;2583state->gpio_val = cfg->gpio_val;2584state->gpio_dir = cfg->gpio_dir;25852586/* Ensure the output mode remains at the previous default if it's2587* not specifically set by the caller.2588*/2589if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))2590state->cfg.output_mode = OUTMODE_MPEG2_FIFO;25912592state->fe[0] = fe;2593fe->demodulator_priv = state;2594memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));25952596state->timf_default = cfg->pll->timf;25972598if (dib8000_identify(&state->i2c) == 0)2599goto error;26002601dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);26022603dib8000_reset(fe);26042605dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */26062607return fe;26082609error:2610kfree(state);2611return NULL;2612}26132614EXPORT_SYMBOL(dib8000_attach);26152616MODULE_AUTHOR("Olivier Grenie <[email protected], " "Patrick Boettcher <[email protected]>");2617MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");2618MODULE_LICENSE("GPL");261926202621