/* * stv0367dd: STV0367 DVB-C/T demodulator driver * * Copyright (C) 2011 Digital Devices GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 only, as published by the Free Software Foundation. * * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #include #include #include #include #include #include #include #include "dvb_math.h" #include "dvb_frontend.h" #include "stv0367dd.h" #include "stv0367dd_regs.h" #define INTLOG10X100(x) ((u32) (((u64) intlog10(x) * 100) >> 24)) enum omode { OM_NONE, OM_DVBT, OM_DVBC, OM_QAM_ITU_C }; enum { QAM_MOD_QAM4 = 0, QAM_MOD_QAM16, QAM_MOD_QAM32, QAM_MOD_QAM64, QAM_MOD_QAM128, QAM_MOD_QAM256, QAM_MOD_QAM512, QAM_MOD_QAM1024 }; enum {QAM_SPECT_NORMAL, QAM_SPECT_INVERTED }; enum { QAM_FEC_A = 1, /* J83 Annex A */ QAM_FEC_B = (1<<1), /* J83 Annex B */ QAM_FEC_C = (1<<2) /* J83 Annex C */ }; enum EDemodState { Off, QAMSet, OFDMSet, QAMStarted, OFDMStarted }; struct stv_state { struct dvb_frontend frontend; fe_modulation_t modulation; u32 symbol_rate; u32 bandwidth; struct device *dev; struct i2c_adapter *i2c; u8 adr; u8 cont_clock; void *priv; struct mutex mutex; struct mutex ctlock; u32 master_clock; u32 adc_clock; u8 ID; u8 I2CRPT; u32 omode; u8 qam_inversion; s32 IF; s32 m_FECTimeOut; s32 m_DemodTimeOut; s32 m_SignalTimeOut; s32 m_DemodLockTime; s32 m_FFTTimeOut; s32 m_TSTimeOut; bool m_bFirstTimeLock; u8 m_Save_QAM_AGC_CTL; enum EDemodState demod_state; u8 m_OFDM_FFTMode; // 0 = 2k, 1 = 8k, 2 = 4k u8 m_OFDM_Modulation; // u8 m_OFDM_FEC; // u8 m_OFDM_Guard; u32 ucblocks; u32 ber; }; struct init_table { u16 adr; u8 data; }; struct init_table base_init[] = { { R367_IOCFG0, 0x80 }, { R367_DAC0R, 0x00 }, { R367_IOCFG1, 0x00 }, { R367_DAC1R, 0x00 }, { R367_IOCFG2, 0x00 }, { R367_SDFR, 0x00 }, { R367_AUX_CLK, 0x00 }, { R367_FREESYS1, 0x00 }, { R367_FREESYS2, 0x00 }, { R367_FREESYS3, 0x00 }, { R367_GPIO_CFG, 0x55 }, { R367_GPIO_CMD, 0x01 }, { R367_TSTRES, 0x00 }, { R367_ANACTRL, 0x00 }, { R367_TSTBUS, 0x00 }, { R367_RF_AGC2, 0x20 }, { R367_ANADIGCTRL, 0x0b }, { R367_PLLMDIV, 0x01 }, { R367_PLLNDIV, 0x08 }, { R367_PLLSETUP, 0x18 }, { R367_DUAL_AD12, 0x04 }, { R367_TSTBIST, 0x00 }, { 0x0000, 0x00 } }; struct init_table qam_init[] = { { R367_QAM_CTRL_1, 0x06 },// Orginal 0x04 { R367_QAM_CTRL_2, 0x03 }, { R367_QAM_IT_STATUS1, 0x2b }, { R367_QAM_IT_STATUS2, 0x08 }, { R367_QAM_IT_EN1, 0x00 }, { R367_QAM_IT_EN2, 0x00 }, { R367_QAM_CTRL_STATUS, 0x04 }, { R367_QAM_TEST_CTL, 0x00 }, { R367_QAM_AGC_CTL, 0x73 }, { R367_QAM_AGC_IF_CFG, 0x50 }, { R367_QAM_AGC_RF_CFG, 0x02 },// RF Freeze { R367_QAM_AGC_PWM_CFG, 0x03 }, { R367_QAM_AGC_PWR_REF_L, 0x5a }, { R367_QAM_AGC_PWR_REF_H, 0x00 }, { R367_QAM_AGC_RF_TH_L, 0xff }, { R367_QAM_AGC_RF_TH_H, 0x07 }, { R367_QAM_AGC_IF_LTH_L, 0x00 }, { R367_QAM_AGC_IF_LTH_H, 0x08 }, { R367_QAM_AGC_IF_HTH_L, 0xff }, { R367_QAM_AGC_IF_HTH_H, 0x07 }, { R367_QAM_AGC_PWR_RD_L, 0xa0 }, { R367_QAM_AGC_PWR_RD_M, 0xe9 }, { R367_QAM_AGC_PWR_RD_H, 0x03 }, { R367_QAM_AGC_PWM_IFCMD_L, 0xe4 }, { R367_QAM_AGC_PWM_IFCMD_H, 0x00 }, { R367_QAM_AGC_PWM_RFCMD_L, 0xff }, { R367_QAM_AGC_PWM_RFCMD_H, 0x07 }, { R367_QAM_IQDEM_CFG, 0x01 }, { R367_QAM_MIX_NCO_LL, 0x22 }, { R367_QAM_MIX_NCO_HL, 0x96 }, { R367_QAM_MIX_NCO_HH, 0x55 }, { R367_QAM_SRC_NCO_LL, 0xff }, { R367_QAM_SRC_NCO_LH, 0x0c }, { R367_QAM_SRC_NCO_HL, 0xf5 }, { R367_QAM_SRC_NCO_HH, 0x20 }, { R367_QAM_IQDEM_GAIN_SRC_L, 0x06 }, { R367_QAM_IQDEM_GAIN_SRC_H, 0x01 }, { R367_QAM_IQDEM_DCRM_CFG_LL, 0xfe }, { R367_QAM_IQDEM_DCRM_CFG_LH, 0xff }, { R367_QAM_IQDEM_DCRM_CFG_HL, 0x0f }, { R367_QAM_IQDEM_DCRM_CFG_HH, 0x00 }, { R367_QAM_IQDEM_ADJ_COEFF0, 0x34 }, { R367_QAM_IQDEM_ADJ_COEFF1, 0xae }, { R367_QAM_IQDEM_ADJ_COEFF2, 0x46 }, { R367_QAM_IQDEM_ADJ_COEFF3, 0x77 }, { R367_QAM_IQDEM_ADJ_COEFF4, 0x96 }, { R367_QAM_IQDEM_ADJ_COEFF5, 0x69 }, { R367_QAM_IQDEM_ADJ_COEFF6, 0xc7 }, { R367_QAM_IQDEM_ADJ_COEFF7, 0x01 }, { R367_QAM_IQDEM_ADJ_EN, 0x04 }, { R367_QAM_IQDEM_ADJ_AGC_REF, 0x94 }, { R367_QAM_ALLPASSFILT1, 0xc9 }, { R367_QAM_ALLPASSFILT2, 0x2d }, { R367_QAM_ALLPASSFILT3, 0xa3 }, { R367_QAM_ALLPASSFILT4, 0xfb }, { R367_QAM_ALLPASSFILT5, 0xf6 }, { R367_QAM_ALLPASSFILT6, 0x45 }, { R367_QAM_ALLPASSFILT7, 0x6f }, { R367_QAM_ALLPASSFILT8, 0x7e }, { R367_QAM_ALLPASSFILT9, 0x05 }, { R367_QAM_ALLPASSFILT10, 0x0a }, { R367_QAM_ALLPASSFILT11, 0x51 }, { R367_QAM_TRL_AGC_CFG, 0x20 }, { R367_QAM_TRL_LPF_CFG, 0x28 }, { R367_QAM_TRL_LPF_ACQ_GAIN, 0x44 }, { R367_QAM_TRL_LPF_TRK_GAIN, 0x22 }, { R367_QAM_TRL_LPF_OUT_GAIN, 0x03 }, { R367_QAM_TRL_LOCKDET_LTH, 0x04 }, { R367_QAM_TRL_LOCKDET_HTH, 0x11 }, { R367_QAM_TRL_LOCKDET_TRGVAL, 0x20 }, { R367_QAM_IQ_QAM, 0x01 }, { R367_QAM_FSM_STATE, 0xa0 }, { R367_QAM_FSM_CTL, 0x08 }, { R367_QAM_FSM_STS, 0x0c }, { R367_QAM_FSM_SNR0_HTH, 0x00 }, { R367_QAM_FSM_SNR1_HTH, 0x00 }, { R367_QAM_FSM_SNR2_HTH, 0x00 }, { R367_QAM_FSM_SNR0_LTH, 0x00 }, { R367_QAM_FSM_SNR1_LTH, 0x00 }, { R367_QAM_FSM_EQA1_HTH, 0x00 }, { R367_QAM_FSM_TEMPO, 0x32 }, { R367_QAM_FSM_CONFIG, 0x03 }, { R367_QAM_EQU_I_TESTTAP_L, 0x11 }, { R367_QAM_EQU_I_TESTTAP_M, 0x00 }, { R367_QAM_EQU_I_TESTTAP_H, 0x00 }, { R367_QAM_EQU_TESTAP_CFG, 0x00 }, { R367_QAM_EQU_Q_TESTTAP_L, 0xff }, { R367_QAM_EQU_Q_TESTTAP_M, 0x00 }, { R367_QAM_EQU_Q_TESTTAP_H, 0x00 }, { R367_QAM_EQU_TAP_CTRL, 0x00 }, { R367_QAM_EQU_CTR_CRL_CONTROL_L, 0x11 }, { R367_QAM_EQU_CTR_CRL_CONTROL_H, 0x05 }, { R367_QAM_EQU_CTR_HIPOW_L, 0x00 }, { R367_QAM_EQU_CTR_HIPOW_H, 0x00 }, { R367_QAM_EQU_I_EQU_LO, 0xef }, { R367_QAM_EQU_I_EQU_HI, 0x00 }, { R367_QAM_EQU_Q_EQU_LO, 0xee }, { R367_QAM_EQU_Q_EQU_HI, 0x00 }, { R367_QAM_EQU_MAPPER, 0xc5 }, { R367_QAM_EQU_SWEEP_RATE, 0x80 }, { R367_QAM_EQU_SNR_LO, 0x64 }, { R367_QAM_EQU_SNR_HI, 0x03 }, { R367_QAM_EQU_GAMMA_LO, 0x00 }, { R367_QAM_EQU_GAMMA_HI, 0x00 }, { R367_QAM_EQU_ERR_GAIN, 0x36 }, { R367_QAM_EQU_RADIUS, 0xaa }, { R367_QAM_EQU_FFE_MAINTAP, 0x00 }, { R367_QAM_EQU_FFE_LEAKAGE, 0x63 }, { R367_QAM_EQU_FFE_MAINTAP_POS, 0xdf }, { R367_QAM_EQU_GAIN_WIDE, 0x88 }, { R367_QAM_EQU_GAIN_NARROW, 0x41 }, { R367_QAM_EQU_CTR_LPF_GAIN, 0xd1 }, { R367_QAM_EQU_CRL_LPF_GAIN, 0xa7 }, { R367_QAM_EQU_GLOBAL_GAIN, 0x06 }, { R367_QAM_EQU_CRL_LD_SEN, 0x85 }, { R367_QAM_EQU_CRL_LD_VAL, 0xe2 }, { R367_QAM_EQU_CRL_TFR, 0x20 }, { R367_QAM_EQU_CRL_BISTH_LO, 0x00 }, { R367_QAM_EQU_CRL_BISTH_HI, 0x00 }, { R367_QAM_EQU_SWEEP_RANGE_LO, 0x00 }, { R367_QAM_EQU_SWEEP_RANGE_HI, 0x00 }, { R367_QAM_EQU_CRL_LIMITER, 0x40 }, { R367_QAM_EQU_MODULUS_MAP, 0x90 }, { R367_QAM_EQU_PNT_GAIN, 0xa7 }, { R367_QAM_FEC_AC_CTR_0, 0x16 }, { R367_QAM_FEC_AC_CTR_1, 0x0b }, { R367_QAM_FEC_AC_CTR_2, 0x88 }, { R367_QAM_FEC_AC_CTR_3, 0x02 }, { R367_QAM_FEC_STATUS, 0x12 }, { R367_QAM_RS_COUNTER_0, 0x7d }, { R367_QAM_RS_COUNTER_1, 0xd0 }, { R367_QAM_RS_COUNTER_2, 0x19 }, { R367_QAM_RS_COUNTER_3, 0x0b }, { R367_QAM_RS_COUNTER_4, 0xa3 }, { R367_QAM_RS_COUNTER_5, 0x00 }, { R367_QAM_BERT_0, 0x01 }, { R367_QAM_BERT_1, 0x25 }, { R367_QAM_BERT_2, 0x41 }, { R367_QAM_BERT_3, 0x39 }, { R367_QAM_OUTFORMAT_0, 0xc2 }, { R367_QAM_OUTFORMAT_1, 0x22 }, { R367_QAM_SMOOTHER_2, 0x28 }, { R367_QAM_TSMF_CTRL_0, 0x01 }, { R367_QAM_TSMF_CTRL_1, 0xc6 }, { R367_QAM_TSMF_CTRL_3, 0x43 }, { R367_QAM_TS_ON_ID_0, 0x00 }, { R367_QAM_TS_ON_ID_1, 0x00 }, { R367_QAM_TS_ON_ID_2, 0x00 }, { R367_QAM_TS_ON_ID_3, 0x00 }, { R367_QAM_RE_STATUS_0, 0x00 }, { R367_QAM_RE_STATUS_1, 0x00 }, { R367_QAM_RE_STATUS_2, 0x00 }, { R367_QAM_RE_STATUS_3, 0x00 }, { R367_QAM_TS_STATUS_0, 0x00 }, { R367_QAM_TS_STATUS_1, 0x00 }, { R367_QAM_TS_STATUS_2, 0xa0 }, { R367_QAM_TS_STATUS_3, 0x00 }, { R367_QAM_T_O_ID_0, 0x00 }, { R367_QAM_T_O_ID_1, 0x00 }, { R367_QAM_T_O_ID_2, 0x00 }, { R367_QAM_T_O_ID_3, 0x00 }, { 0x0000, 0x00 } // EOT }; struct init_table ofdm_init[] = { //{R367_OFDM_ID ,0x60}, //{R367_OFDM_I2CRPT ,0x22}, //{R367_OFDM_TOPCTRL ,0x02}, //{R367_OFDM_IOCFG0 ,0x40}, //{R367_OFDM_DAC0R ,0x00}, //{R367_OFDM_IOCFG1 ,0x00}, //{R367_OFDM_DAC1R ,0x00}, //{R367_OFDM_IOCFG2 ,0x62}, //{R367_OFDM_SDFR ,0x00}, //{R367_OFDM_STATUS ,0xf8}, //{R367_OFDM_AUX_CLK ,0x0a}, //{R367_OFDM_FREESYS1 ,0x00}, //{R367_OFDM_FREESYS2 ,0x00}, //{R367_OFDM_FREESYS3 ,0x00}, //{R367_OFDM_GPIO_CFG ,0x55}, //{R367_OFDM_GPIO_CMD ,0x00}, {R367_OFDM_AGC2MAX ,0xff}, {R367_OFDM_AGC2MIN ,0x00}, {R367_OFDM_AGC1MAX ,0xff}, {R367_OFDM_AGC1MIN ,0x00}, {R367_OFDM_AGCR ,0xbc}, {R367_OFDM_AGC2TH ,0x00}, //{R367_OFDM_AGC12C ,0x01}, //Note: This defines AGC pins, also needed for QAM {R367_OFDM_AGCCTRL1 ,0x85}, {R367_OFDM_AGCCTRL2 ,0x1f}, {R367_OFDM_AGC1VAL1 ,0x00}, {R367_OFDM_AGC1VAL2 ,0x00}, {R367_OFDM_AGC2VAL1 ,0x6f}, {R367_OFDM_AGC2VAL2 ,0x05}, {R367_OFDM_AGC2PGA ,0x00}, {R367_OFDM_OVF_RATE1 ,0x00}, {R367_OFDM_OVF_RATE2 ,0x00}, {R367_OFDM_GAIN_SRC1 ,0x2b}, {R367_OFDM_GAIN_SRC2 ,0x04}, {R367_OFDM_INC_DEROT1 ,0x55}, {R367_OFDM_INC_DEROT2 ,0x55}, {R367_OFDM_PPM_CPAMP_DIR ,0x2c}, {R367_OFDM_PPM_CPAMP_INV ,0x00}, {R367_OFDM_FREESTFE_1 ,0x00}, {R367_OFDM_FREESTFE_2 ,0x1c}, {R367_OFDM_DCOFFSET ,0x00}, {R367_OFDM_EN_PROCESS ,0x05}, {R367_OFDM_SDI_SMOOTHER ,0x80}, {R367_OFDM_FE_LOOP_OPEN ,0x1c}, {R367_OFDM_FREQOFF1 ,0x00}, {R367_OFDM_FREQOFF2 ,0x00}, {R367_OFDM_FREQOFF3 ,0x00}, {R367_OFDM_TIMOFF1 ,0x00}, {R367_OFDM_TIMOFF2 ,0x00}, {R367_OFDM_EPQ ,0x02}, {R367_OFDM_EPQAUTO ,0x01}, {R367_OFDM_SYR_UPDATE ,0xf5}, {R367_OFDM_CHPFREE ,0x00}, {R367_OFDM_PPM_STATE_MAC ,0x23}, {R367_OFDM_INR_THRESHOLD ,0xff}, {R367_OFDM_EPQ_TPS_ID_CELL ,0xf9}, {R367_OFDM_EPQ_CFG ,0x00}, {R367_OFDM_EPQ_STATUS ,0x01}, {R367_OFDM_AUTORELOCK ,0x81}, {R367_OFDM_BER_THR_VMSB ,0x00}, {R367_OFDM_BER_THR_MSB ,0x00}, {R367_OFDM_BER_THR_LSB ,0x00}, {R367_OFDM_CCD ,0x83}, {R367_OFDM_SPECTR_CFG ,0x00}, {R367_OFDM_CHC_DUMMY ,0x18}, {R367_OFDM_INC_CTL ,0x88}, {R367_OFDM_INCTHRES_COR1 ,0xb4}, {R367_OFDM_INCTHRES_COR2 ,0x96}, {R367_OFDM_INCTHRES_DET1 ,0x0e}, {R367_OFDM_INCTHRES_DET2 ,0x11}, {R367_OFDM_IIR_CELLNB ,0x8d}, {R367_OFDM_IIRCX_COEFF1_MSB ,0x00}, {R367_OFDM_IIRCX_COEFF1_LSB ,0x00}, {R367_OFDM_IIRCX_COEFF2_MSB ,0x09}, {R367_OFDM_IIRCX_COEFF2_LSB ,0x18}, {R367_OFDM_IIRCX_COEFF3_MSB ,0x14}, {R367_OFDM_IIRCX_COEFF3_LSB ,0x9c}, {R367_OFDM_IIRCX_COEFF4_MSB ,0x00}, {R367_OFDM_IIRCX_COEFF4_LSB ,0x00}, {R367_OFDM_IIRCX_COEFF5_MSB ,0x36}, {R367_OFDM_IIRCX_COEFF5_LSB ,0x42}, {R367_OFDM_FEPATH_CFG ,0x00}, {R367_OFDM_PMC1_FUNC ,0x65}, {R367_OFDM_PMC1_FOR ,0x00}, {R367_OFDM_PMC2_FUNC ,0x00}, {R367_OFDM_STATUS_ERR_DA ,0xe0}, {R367_OFDM_DIG_AGC_R ,0xfe}, {R367_OFDM_COMAGC_TARMSB ,0x0b}, {R367_OFDM_COM_AGC_TAR_ENMODE ,0x41}, {R367_OFDM_COM_AGC_CFG ,0x3e}, {R367_OFDM_COM_AGC_GAIN1 ,0x39}, {R367_OFDM_AUT_AGC_TARGETMSB ,0x0b}, {R367_OFDM_LOCK_DET_MSB ,0x01}, {R367_OFDM_AGCTAR_LOCK_LSBS ,0x40}, {R367_OFDM_AUT_GAIN_EN ,0xf4}, {R367_OFDM_AUT_CFG ,0xf0}, {R367_OFDM_LOCKN ,0x23}, {R367_OFDM_INT_X_3 ,0x00}, {R367_OFDM_INT_X_2 ,0x03}, {R367_OFDM_INT_X_1 ,0x8d}, {R367_OFDM_INT_X_0 ,0xa0}, {R367_OFDM_MIN_ERRX_MSB ,0x00}, {R367_OFDM_COR_CTL ,0x00}, {R367_OFDM_COR_STAT ,0xf6}, {R367_OFDM_COR_INTEN ,0x00}, {R367_OFDM_COR_INTSTAT ,0x3f}, {R367_OFDM_COR_MODEGUARD ,0x03}, {R367_OFDM_AGC_CTL ,0x08}, {R367_OFDM_AGC_MANUAL1 ,0x00}, {R367_OFDM_AGC_MANUAL2 ,0x00}, {R367_OFDM_AGC_TARG ,0x16}, {R367_OFDM_AGC_GAIN1 ,0x53}, {R367_OFDM_AGC_GAIN2 ,0x1d}, {R367_OFDM_RESERVED_1 ,0x00}, {R367_OFDM_RESERVED_2 ,0x00}, {R367_OFDM_RESERVED_3 ,0x00}, {R367_OFDM_CAS_CTL ,0x44}, {R367_OFDM_CAS_FREQ ,0xb3}, {R367_OFDM_CAS_DAGCGAIN ,0x12}, {R367_OFDM_SYR_CTL ,0x04}, {R367_OFDM_SYR_STAT ,0x10}, {R367_OFDM_SYR_NCO1 ,0x00}, {R367_OFDM_SYR_NCO2 ,0x00}, {R367_OFDM_SYR_OFFSET1 ,0x00}, {R367_OFDM_SYR_OFFSET2 ,0x00}, {R367_OFDM_FFT_CTL ,0x00}, {R367_OFDM_SCR_CTL ,0x70}, {R367_OFDM_PPM_CTL1 ,0xf8}, {R367_OFDM_TRL_CTL ,0xac}, {R367_OFDM_TRL_NOMRATE1 ,0x1e}, {R367_OFDM_TRL_NOMRATE2 ,0x58}, {R367_OFDM_TRL_TIME1 ,0x1d}, {R367_OFDM_TRL_TIME2 ,0xfc}, {R367_OFDM_CRL_CTL ,0x24}, {R367_OFDM_CRL_FREQ1 ,0xad}, {R367_OFDM_CRL_FREQ2 ,0x9d}, {R367_OFDM_CRL_FREQ3 ,0xff}, {R367_OFDM_CHC_CTL ,0x01}, {R367_OFDM_CHC_SNR ,0xf0}, {R367_OFDM_BDI_CTL ,0x00}, {R367_OFDM_DMP_CTL ,0x00}, {R367_OFDM_TPS_RCVD1 ,0x30}, {R367_OFDM_TPS_RCVD2 ,0x02}, {R367_OFDM_TPS_RCVD3 ,0x01}, {R367_OFDM_TPS_RCVD4 ,0x00}, {R367_OFDM_TPS_ID_CELL1 ,0x00}, {R367_OFDM_TPS_ID_CELL2 ,0x00}, {R367_OFDM_TPS_RCVD5_SET1 ,0x02}, {R367_OFDM_TPS_SET2 ,0x02}, {R367_OFDM_TPS_SET3 ,0x01}, {R367_OFDM_TPS_CTL ,0x00}, {R367_OFDM_CTL_FFTOSNUM ,0x34}, {R367_OFDM_TESTSELECT ,0x09}, {R367_OFDM_MSC_REV ,0x0a}, {R367_OFDM_PIR_CTL ,0x00}, {R367_OFDM_SNR_CARRIER1 ,0xa1}, {R367_OFDM_SNR_CARRIER2 ,0x9a}, {R367_OFDM_PPM_CPAMP ,0x2c}, {R367_OFDM_TSM_AP0 ,0x00}, {R367_OFDM_TSM_AP1 ,0x00}, {R367_OFDM_TSM_AP2 ,0x00}, {R367_OFDM_TSM_AP3 ,0x00}, {R367_OFDM_TSM_AP4 ,0x00}, {R367_OFDM_TSM_AP5 ,0x00}, {R367_OFDM_TSM_AP6 ,0x00}, {R367_OFDM_TSM_AP7 ,0x00}, //{R367_OFDM_TSTRES ,0x00}, //{R367_OFDM_ANACTRL ,0x0D},/*caution PLL stopped, to be restarted at init!!!*/ //{R367_OFDM_TSTBUS ,0x00}, //{R367_OFDM_TSTRATE ,0x00}, {R367_OFDM_CONSTMODE ,0x01}, {R367_OFDM_CONSTCARR1 ,0x00}, {R367_OFDM_CONSTCARR2 ,0x00}, {R367_OFDM_ICONSTEL ,0x0a}, {R367_OFDM_QCONSTEL ,0x15}, {R367_OFDM_TSTBISTRES0 ,0x00}, {R367_OFDM_TSTBISTRES1 ,0x00}, {R367_OFDM_TSTBISTRES2 ,0x28}, {R367_OFDM_TSTBISTRES3 ,0x00}, //{R367_OFDM_RF_AGC1 ,0xff}, //{R367_OFDM_RF_AGC2 ,0x83}, //{R367_OFDM_ANADIGCTRL ,0x19}, //{R367_OFDM_PLLMDIV ,0x0c}, //{R367_OFDM_PLLNDIV ,0x55}, //{R367_OFDM_PLLSETUP ,0x18}, //{R367_OFDM_DUAL_AD12 ,0x00}, //{R367_OFDM_TSTBIST ,0x00}, //{R367_OFDM_PAD_COMP_CTRL ,0x00}, //{R367_OFDM_PAD_COMP_WR ,0x00}, //{R367_OFDM_PAD_COMP_RD ,0xe0}, {R367_OFDM_SYR_TARGET_FFTADJT_MSB ,0x00}, {R367_OFDM_SYR_TARGET_FFTADJT_LSB ,0x00}, {R367_OFDM_SYR_TARGET_CHCADJT_MSB ,0x00}, {R367_OFDM_SYR_TARGET_CHCADJT_LSB ,0x00}, {R367_OFDM_SYR_FLAG ,0x00}, {R367_OFDM_CRL_TARGET1 ,0x00}, {R367_OFDM_CRL_TARGET2 ,0x00}, {R367_OFDM_CRL_TARGET3 ,0x00}, {R367_OFDM_CRL_TARGET4 ,0x00}, {R367_OFDM_CRL_FLAG ,0x00}, {R367_OFDM_TRL_TARGET1 ,0x00}, {R367_OFDM_TRL_TARGET2 ,0x00}, {R367_OFDM_TRL_CHC ,0x00}, {R367_OFDM_CHC_SNR_TARG ,0x00}, {R367_OFDM_TOP_TRACK ,0x00}, {R367_OFDM_TRACKER_FREE1 ,0x00}, {R367_OFDM_ERROR_CRL1 ,0x00}, {R367_OFDM_ERROR_CRL2 ,0x00}, {R367_OFDM_ERROR_CRL3 ,0x00}, {R367_OFDM_ERROR_CRL4 ,0x00}, {R367_OFDM_DEC_NCO1 ,0x2c}, {R367_OFDM_DEC_NCO2 ,0x0f}, {R367_OFDM_DEC_NCO3 ,0x20}, {R367_OFDM_SNR ,0xf1}, {R367_OFDM_SYR_FFTADJ1 ,0x00}, {R367_OFDM_SYR_FFTADJ2 ,0x00}, {R367_OFDM_SYR_CHCADJ1 ,0x00}, {R367_OFDM_SYR_CHCADJ2 ,0x00}, {R367_OFDM_SYR_OFF ,0x00}, {R367_OFDM_PPM_OFFSET1 ,0x00}, {R367_OFDM_PPM_OFFSET2 ,0x03}, {R367_OFDM_TRACKER_FREE2 ,0x00}, {R367_OFDM_DEBG_LT10 ,0x00}, {R367_OFDM_DEBG_LT11 ,0x00}, {R367_OFDM_DEBG_LT12 ,0x00}, {R367_OFDM_DEBG_LT13 ,0x00}, {R367_OFDM_DEBG_LT14 ,0x00}, {R367_OFDM_DEBG_LT15 ,0x00}, {R367_OFDM_DEBG_LT16 ,0x00}, {R367_OFDM_DEBG_LT17 ,0x00}, {R367_OFDM_DEBG_LT18 ,0x00}, {R367_OFDM_DEBG_LT19 ,0x00}, {R367_OFDM_DEBG_LT1A ,0x00}, {R367_OFDM_DEBG_LT1B ,0x00}, {R367_OFDM_DEBG_LT1C ,0x00}, {R367_OFDM_DEBG_LT1D ,0x00}, {R367_OFDM_DEBG_LT1E ,0x00}, {R367_OFDM_DEBG_LT1F ,0x00}, {R367_OFDM_RCCFGH ,0x00}, {R367_OFDM_RCCFGM ,0x00}, {R367_OFDM_RCCFGL ,0x00}, {R367_OFDM_RCINSDELH ,0x00}, {R367_OFDM_RCINSDELM ,0x00}, {R367_OFDM_RCINSDELL ,0x00}, {R367_OFDM_RCSTATUS ,0x00}, {R367_OFDM_RCSPEED ,0x6f}, {R367_OFDM_RCDEBUGM ,0xe7}, {R367_OFDM_RCDEBUGL ,0x9b}, {R367_OFDM_RCOBSCFG ,0x00}, {R367_OFDM_RCOBSM ,0x00}, {R367_OFDM_RCOBSL ,0x00}, {R367_OFDM_RCFECSPY ,0x00}, {R367_OFDM_RCFSPYCFG ,0x00}, {R367_OFDM_RCFSPYDATA ,0x00}, {R367_OFDM_RCFSPYOUT ,0x00}, {R367_OFDM_RCFSTATUS ,0x00}, {R367_OFDM_RCFGOODPACK ,0x00}, {R367_OFDM_RCFPACKCNT ,0x00}, {R367_OFDM_RCFSPYMISC ,0x00}, {R367_OFDM_RCFBERCPT4 ,0x00}, {R367_OFDM_RCFBERCPT3 ,0x00}, {R367_OFDM_RCFBERCPT2 ,0x00}, {R367_OFDM_RCFBERCPT1 ,0x00}, {R367_OFDM_RCFBERCPT0 ,0x00}, {R367_OFDM_RCFBERERR2 ,0x00}, {R367_OFDM_RCFBERERR1 ,0x00}, {R367_OFDM_RCFBERERR0 ,0x00}, {R367_OFDM_RCFSTATESM ,0x00}, {R367_OFDM_RCFSTATESL ,0x00}, {R367_OFDM_RCFSPYBER ,0x00}, {R367_OFDM_RCFSPYDISTM ,0x00}, {R367_OFDM_RCFSPYDISTL ,0x00}, {R367_OFDM_RCFSPYOBS7 ,0x00}, {R367_OFDM_RCFSPYOBS6 ,0x00}, {R367_OFDM_RCFSPYOBS5 ,0x00}, {R367_OFDM_RCFSPYOBS4 ,0x00}, {R367_OFDM_RCFSPYOBS3 ,0x00}, {R367_OFDM_RCFSPYOBS2 ,0x00}, {R367_OFDM_RCFSPYOBS1 ,0x00}, {R367_OFDM_RCFSPYOBS0 ,0x00}, //{R367_OFDM_TSGENERAL ,0x00}, //{R367_OFDM_RC1SPEED ,0x6f}, //{R367_OFDM_TSGSTATUS ,0x18}, {R367_OFDM_FECM ,0x01}, {R367_OFDM_VTH12 ,0xff}, {R367_OFDM_VTH23 ,0xa1}, {R367_OFDM_VTH34 ,0x64}, {R367_OFDM_VTH56 ,0x40}, {R367_OFDM_VTH67 ,0x00}, {R367_OFDM_VTH78 ,0x2c}, {R367_OFDM_VITCURPUN ,0x12}, {R367_OFDM_VERROR ,0x01}, {R367_OFDM_PRVIT ,0x3f}, {R367_OFDM_VAVSRVIT ,0x00}, {R367_OFDM_VSTATUSVIT ,0xbd}, {R367_OFDM_VTHINUSE ,0xa1}, {R367_OFDM_KDIV12 ,0x20}, {R367_OFDM_KDIV23 ,0x40}, {R367_OFDM_KDIV34 ,0x20}, {R367_OFDM_KDIV56 ,0x30}, {R367_OFDM_KDIV67 ,0x00}, {R367_OFDM_KDIV78 ,0x30}, {R367_OFDM_SIGPOWER ,0x54}, {R367_OFDM_DEMAPVIT ,0x40}, {R367_OFDM_VITSCALE ,0x00}, {R367_OFDM_FFEC1PRG ,0x00}, {R367_OFDM_FVITCURPUN ,0x12}, {R367_OFDM_FVERROR ,0x01}, {R367_OFDM_FVSTATUSVIT ,0xbd}, {R367_OFDM_DEBUG_LT1 ,0x00}, {R367_OFDM_DEBUG_LT2 ,0x00}, {R367_OFDM_DEBUG_LT3 ,0x00}, {R367_OFDM_TSTSFMET ,0x00}, {R367_OFDM_SELOUT ,0x00}, {R367_OFDM_TSYNC ,0x00}, {R367_OFDM_TSTERR ,0x00}, {R367_OFDM_TSFSYNC ,0x00}, {R367_OFDM_TSTSFERR ,0x00}, {R367_OFDM_TSTTSSF1 ,0x01}, {R367_OFDM_TSTTSSF2 ,0x1f}, {R367_OFDM_TSTTSSF3 ,0x00}, {R367_OFDM_TSTTS1 ,0x00}, {R367_OFDM_TSTTS2 ,0x1f}, {R367_OFDM_TSTTS3 ,0x01}, {R367_OFDM_TSTTS4 ,0x00}, {R367_OFDM_TSTTSRC ,0x00}, {R367_OFDM_TSTTSRS ,0x00}, {R367_OFDM_TSSTATEM ,0xb0}, {R367_OFDM_TSSTATEL ,0x40}, {R367_OFDM_TSCFGH ,0x80}, {R367_OFDM_TSCFGM ,0x00}, {R367_OFDM_TSCFGL ,0x20}, {R367_OFDM_TSSYNC ,0x00}, {R367_OFDM_TSINSDELH ,0x00}, {R367_OFDM_TSINSDELM ,0x00}, {R367_OFDM_TSINSDELL ,0x00}, {R367_OFDM_TSDIVN ,0x03}, {R367_OFDM_TSDIVPM ,0x00}, {R367_OFDM_TSDIVPL ,0x00}, {R367_OFDM_TSDIVQM ,0x00}, {R367_OFDM_TSDIVQL ,0x00}, {R367_OFDM_TSDILSTKM ,0x00}, {R367_OFDM_TSDILSTKL ,0x00}, {R367_OFDM_TSSPEED ,0x6f}, {R367_OFDM_TSSTATUS ,0x81}, {R367_OFDM_TSSTATUS2 ,0x6a}, {R367_OFDM_TSBITRATEM ,0x0f}, {R367_OFDM_TSBITRATEL ,0xc6}, {R367_OFDM_TSPACKLENM ,0x00}, {R367_OFDM_TSPACKLENL ,0xfc}, {R367_OFDM_TSBLOCLENM ,0x0a}, {R367_OFDM_TSBLOCLENL ,0x80}, {R367_OFDM_TSDLYH ,0x90}, {R367_OFDM_TSDLYM ,0x68}, {R367_OFDM_TSDLYL ,0x01}, {R367_OFDM_TSNPDAV ,0x00}, {R367_OFDM_TSBUFSTATH ,0x00}, {R367_OFDM_TSBUFSTATM ,0x00}, {R367_OFDM_TSBUFSTATL ,0x00}, {R367_OFDM_TSDEBUGM ,0xcf}, {R367_OFDM_TSDEBUGL ,0x1e}, {R367_OFDM_TSDLYSETH ,0x00}, {R367_OFDM_TSDLYSETM ,0x68}, {R367_OFDM_TSDLYSETL ,0x00}, {R367_OFDM_TSOBSCFG ,0x00}, {R367_OFDM_TSOBSM ,0x47}, {R367_OFDM_TSOBSL ,0x1f}, {R367_OFDM_ERRCTRL1 ,0x95}, {R367_OFDM_ERRCNT1H ,0x80}, {R367_OFDM_ERRCNT1M ,0x00}, {R367_OFDM_ERRCNT1L ,0x00}, {R367_OFDM_ERRCTRL2 ,0x95}, {R367_OFDM_ERRCNT2H ,0x00}, {R367_OFDM_ERRCNT2M ,0x00}, {R367_OFDM_ERRCNT2L ,0x00}, {R367_OFDM_FECSPY ,0x88}, {R367_OFDM_FSPYCFG ,0x2c}, {R367_OFDM_FSPYDATA ,0x3a}, {R367_OFDM_FSPYOUT ,0x06}, {R367_OFDM_FSTATUS ,0x61}, {R367_OFDM_FGOODPACK ,0xff}, {R367_OFDM_FPACKCNT ,0xff}, {R367_OFDM_FSPYMISC ,0x66}, {R367_OFDM_FBERCPT4 ,0x00}, {R367_OFDM_FBERCPT3 ,0x00}, {R367_OFDM_FBERCPT2 ,0x36}, {R367_OFDM_FBERCPT1 ,0x36}, {R367_OFDM_FBERCPT0 ,0x14}, {R367_OFDM_FBERERR2 ,0x00}, {R367_OFDM_FBERERR1 ,0x03}, {R367_OFDM_FBERERR0 ,0x28}, {R367_OFDM_FSTATESM ,0x00}, {R367_OFDM_FSTATESL ,0x02}, {R367_OFDM_FSPYBER ,0x00}, {R367_OFDM_FSPYDISTM ,0x01}, {R367_OFDM_FSPYDISTL ,0x9f}, {R367_OFDM_FSPYOBS7 ,0xc9}, {R367_OFDM_FSPYOBS6 ,0x99}, {R367_OFDM_FSPYOBS5 ,0x08}, {R367_OFDM_FSPYOBS4 ,0xec}, {R367_OFDM_FSPYOBS3 ,0x01}, {R367_OFDM_FSPYOBS2 ,0x0f}, {R367_OFDM_FSPYOBS1 ,0xf5}, {R367_OFDM_FSPYOBS0 ,0x08}, {R367_OFDM_SFDEMAP ,0x40}, {R367_OFDM_SFERROR ,0x00}, {R367_OFDM_SFAVSR ,0x30}, {R367_OFDM_SFECSTATUS ,0xcc}, {R367_OFDM_SFKDIV12 ,0x20}, {R367_OFDM_SFKDIV23 ,0x40}, {R367_OFDM_SFKDIV34 ,0x20}, {R367_OFDM_SFKDIV56 ,0x20}, {R367_OFDM_SFKDIV67 ,0x00}, {R367_OFDM_SFKDIV78 ,0x20}, {R367_OFDM_SFDILSTKM ,0x00}, {R367_OFDM_SFDILSTKL ,0x00}, {R367_OFDM_SFSTATUS ,0xb5}, {R367_OFDM_SFDLYH ,0x90}, {R367_OFDM_SFDLYM ,0x60}, {R367_OFDM_SFDLYL ,0x01}, {R367_OFDM_SFDLYSETH ,0xc0}, {R367_OFDM_SFDLYSETM ,0x60}, {R367_OFDM_SFDLYSETL ,0x00}, {R367_OFDM_SFOBSCFG ,0x00}, {R367_OFDM_SFOBSM ,0x47}, {R367_OFDM_SFOBSL ,0x05}, {R367_OFDM_SFECINFO ,0x40}, {R367_OFDM_SFERRCTRL ,0x74}, {R367_OFDM_SFERRCNTH ,0x80}, {R367_OFDM_SFERRCNTM ,0x00}, {R367_OFDM_SFERRCNTL ,0x00}, {R367_OFDM_SYMBRATEM ,0x2f}, {R367_OFDM_SYMBRATEL ,0x50}, {R367_OFDM_SYMBSTATUS ,0x7f}, {R367_OFDM_SYMBCFG ,0x00}, {R367_OFDM_SYMBFIFOM ,0xf4}, {R367_OFDM_SYMBFIFOL ,0x0d}, {R367_OFDM_SYMBOFFSM ,0xf0}, {R367_OFDM_SYMBOFFSL ,0x2d}, //{R367_OFDM_DEBUG_LT4 ,0x00}, //{R367_OFDM_DEBUG_LT5 ,0x00}, //{R367_OFDM_DEBUG_LT6 ,0x00}, //{R367_OFDM_DEBUG_LT7 ,0x00}, //{R367_OFDM_DEBUG_LT8 ,0x00}, //{R367_OFDM_DEBUG_LT9 ,0x00}, { 0x0000, 0x00 } // EOT }; static inline u32 MulDiv32(u32 a, u32 b, u32 c) { u64 tmp64; tmp64 = (u64)a * (u64)b; do_div(tmp64, c); return (u32) tmp64; } static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) { struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len}; if (i2c_transfer(adap, &msg, 1) != 1) { printk("stv0367: i2c_write error\n"); return -1; } return 0; } #if 0 static int i2c_read(struct i2c_adapter *adap, u8 adr, u8 *msg, int len, u8 *answ, int alen) { struct i2c_msg msgs[2] = { { .addr = adr, .flags = 0, .buf = msg, .len = len}, { .addr = adr, .flags = I2C_M_RD, .buf = answ, .len = alen } }; if (i2c_transfer(adap, msgs, 2) != 2) { printk("stv0367: i2c_read error\n"); return -1; } return 0; } #endif static int writereg(struct stv_state *state, u16 reg, u8 dat) { u8 mm[3] = { (reg >> 8), reg & 0xff, dat }; return i2c_write(state->i2c, state->adr, mm, 3); } static int readreg(struct stv_state *state, u16 reg, u8 *val) { u8 msg[2] = {reg >> 8, reg & 0xff}; struct i2c_msg msgs[2] = {{.addr = state->adr, .flags = 0, .buf = msg, .len = 2}, {.addr = state->adr, .flags = I2C_M_RD, .buf = val, .len = 1}}; return (i2c_transfer(state->i2c, msgs, 2) == 2) ? 0 : -1; } static int readregs(struct stv_state *state, u16 reg, u8 *val, int count) { u8 msg[2] = {reg >> 8, reg & 0xff}; struct i2c_msg msgs[2] = {{.addr = state->adr, .flags = 0, .buf = msg, .len = 2}, {.addr = state->adr, .flags = I2C_M_RD, .buf = val, .len = count}}; return (i2c_transfer(state->i2c, msgs, 2) == 2) ? 0 : -1; } static int write_init_table(struct stv_state *state, struct init_table *tab) { while (1) { if (!tab->adr) break; if (writereg(state, tab->adr, tab->data) < 0) return -1; tab++; } return 0; } static int qam_set_modulation(struct stv_state *state) { int stat = 0; switch(state->modulation) { case QAM_16: writereg(state, R367_QAM_EQU_MAPPER,state->qam_inversion | QAM_MOD_QAM16 ); writereg(state, R367_QAM_AGC_PWR_REF_L,0x64); /* Set analog AGC reference */ writereg(state, R367_QAM_IQDEM_ADJ_AGC_REF,0x00); /* Set digital AGC reference */ writereg(state, R367_QAM_FSM_STATE,0x90); writereg(state, R367_QAM_EQU_CTR_LPF_GAIN,0xc1); writereg(state, R367_QAM_EQU_CRL_LPF_GAIN,0xa7); writereg(state, R367_QAM_EQU_CRL_LD_SEN,0x95); writereg(state, R367_QAM_EQU_CRL_LIMITER,0x40); writereg(state, R367_QAM_EQU_PNT_GAIN,0x8a); break; case QAM_32: writereg(state, R367_QAM_EQU_MAPPER,state->qam_inversion | QAM_MOD_QAM32 ); writereg(state, R367_QAM_AGC_PWR_REF_L,0x6e); /* Set analog AGC reference */ writereg(state, R367_QAM_IQDEM_ADJ_AGC_REF,0x00); /* Set digital AGC reference */ writereg(state, R367_QAM_FSM_STATE,0xb0); writereg(state, R367_QAM_EQU_CTR_LPF_GAIN,0xc1); writereg(state, R367_QAM_EQU_CRL_LPF_GAIN,0xb7); writereg(state, R367_QAM_EQU_CRL_LD_SEN,0x9d); writereg(state, R367_QAM_EQU_CRL_LIMITER,0x7f); writereg(state, R367_QAM_EQU_PNT_GAIN,0xa7); break; case QAM_64: writereg(state, R367_QAM_EQU_MAPPER,state->qam_inversion | QAM_MOD_QAM64 ); writereg(state, R367_QAM_AGC_PWR_REF_L,0x5a); /* Set analog AGC reference */ writereg(state, R367_QAM_IQDEM_ADJ_AGC_REF,0x82); /* Set digital AGC reference */ if(state->symbol_rate>4500000) { writereg(state, R367_QAM_FSM_STATE,0xb0); writereg(state, R367_QAM_EQU_CTR_LPF_GAIN,0xc1); writereg(state, R367_QAM_EQU_CRL_LPF_GAIN,0xa5); } else if(state->symbol_rate>2500000) // 25000000 { writereg(state, R367_QAM_FSM_STATE,0xa0); writereg(state, R367_QAM_EQU_CTR_LPF_GAIN,0xc1); writereg(state, R367_QAM_EQU_CRL_LPF_GAIN,0xa6); } else { writereg(state, R367_QAM_FSM_STATE,0xa0); writereg(state, R367_QAM_EQU_CTR_LPF_GAIN,0xd1); writereg(state, R367_QAM_EQU_CRL_LPF_GAIN,0xa7); } writereg(state, R367_QAM_EQU_CRL_LD_SEN,0x95); writereg(state, R367_QAM_EQU_CRL_LIMITER,0x40); writereg(state, R367_QAM_EQU_PNT_GAIN,0x99); break; case QAM_128: writereg(state, R367_QAM_EQU_MAPPER,state->qam_inversion | QAM_MOD_QAM128 ); writereg(state, R367_QAM_AGC_PWR_REF_L,0x76); /* Set analog AGC reference */ writereg(state, R367_QAM_IQDEM_ADJ_AGC_REF,0x00); /* Set digital AGC reference */ writereg(state, R367_QAM_FSM_STATE,0x90); writereg(state, R367_QAM_EQU_CTR_LPF_GAIN,0xb1); if(state->symbol_rate>4500000) // 45000000 { writereg(state, R367_QAM_EQU_CRL_LPF_GAIN,0xa7); } else if(state->symbol_rate>2500000) // 25000000 { writereg(state, R367_QAM_EQU_CRL_LPF_GAIN,0xa6); } else { writereg(state, R367_QAM_EQU_CRL_LPF_GAIN,0x97); } writereg(state, R367_QAM_EQU_CRL_LD_SEN,0x8e); writereg(state, R367_QAM_EQU_CRL_LIMITER,0x7f); writereg(state, R367_QAM_EQU_PNT_GAIN,0xa7); break; case QAM_256: writereg(state, R367_QAM_EQU_MAPPER,state->qam_inversion | QAM_MOD_QAM256 ); writereg(state, R367_QAM_AGC_PWR_REF_L,0x5a); /* Set analog AGC reference */ writereg(state, R367_QAM_IQDEM_ADJ_AGC_REF,0x94); /* Set digital AGC reference */ writereg(state, R367_QAM_FSM_STATE,0xa0); if(state->symbol_rate>4500000) // 45000000 { writereg(state, R367_QAM_EQU_CTR_LPF_GAIN,0xc1); } else if(state->symbol_rate>2500000) // 25000000 { writereg(state, R367_QAM_EQU_CTR_LPF_GAIN,0xc1); } else { writereg(state, R367_QAM_EQU_CTR_LPF_GAIN,0xd1); } writereg(state, R367_QAM_EQU_CRL_LPF_GAIN,0xa7); writereg(state, R367_QAM_EQU_CRL_LD_SEN,0x85); writereg(state, R367_QAM_EQU_CRL_LIMITER,0x40); writereg(state, R367_QAM_EQU_PNT_GAIN,0xa7); break; default: stat = -EINVAL; break; } return stat; } static int QAM_SetSymbolRate(struct stv_state *state) { int status = 0; u32 sr = state->symbol_rate; u32 Corr = 0; u32 Temp, Temp1, AdpClk; switch(state->modulation) { default: case QAM_16: Corr = 1032; break; case QAM_32: Corr = 954; break; case QAM_64: Corr = 983; break; case QAM_128: Corr = 957; break; case QAM_256: Corr = 948; break; } // Transfer ration Temp = (256*sr) / state->adc_clock; writereg(state, R367_QAM_EQU_CRL_TFR,(Temp)); /* Symbol rate and SRC gain calculation */ AdpClk = (state->master_clock) / 2000; /* TRL works at half the system clock */ Temp = state->symbol_rate; Temp1 = sr; if(sr < 2097152) /* 2097152 = 2^21 */ { Temp = ((((sr * 2048) / AdpClk) * 16384 ) / 125 ) * 8; Temp1 = (((((sr * 2048) / 439 ) * 256 ) / AdpClk ) * Corr * 9 ) / 10000000; } else if(sr < 4194304) /* 4194304 = 2**22 */ { Temp = ((((sr * 1024) / AdpClk) * 16384 ) / 125 ) * 16; Temp1 = (((((sr * 1024) / 439 ) * 256 ) / AdpClk ) * Corr * 9 ) / 5000000; } else if(sr < 8388608) /* 8388608 = 2**23 */ { Temp = ((((sr * 512) / AdpClk) * 16384 ) / 125 ) * 32; Temp1 = (((((sr * 512) / 439 ) * 256 ) / AdpClk ) * Corr * 9 ) / 2500000; } else { Temp = ((((sr * 256) / AdpClk) * 16384 ) / 125 ) * 64; Temp1 = (((((sr * 256) / 439 ) * 256 ) / AdpClk ) * Corr * 9 ) / 1250000; } ///* Filters' coefficients are calculated and written into registers only if the filters are enabled */ //if (ChipGetField(hChip,F367qam_ADJ_EN)) // Is disabled from init! //{ // FE_367qam_SetIirAdjacentcoefficient(hChip, MasterClk_Hz, SymbolRate); //} ///* AllPass filter is never used on this IC */ //ChipSetField(hChip,F367qam_ALLPASSFILT_EN,0); // should be disabled from init! writereg(state, R367_QAM_SRC_NCO_LL,(Temp)); writereg(state, R367_QAM_SRC_NCO_LH,(Temp>>8)); writereg(state, R367_QAM_SRC_NCO_HL,(Temp>>16)); writereg(state, R367_QAM_SRC_NCO_HH,(Temp>>24)); writereg(state, R367_QAM_IQDEM_GAIN_SRC_L,(Temp1)); writereg(state, R367_QAM_IQDEM_GAIN_SRC_H,(Temp1>>8)); return status; } static int QAM_SetDerotFrequency(struct stv_state *state, u32 DerotFrequency) { int status = 0; u32 Sampled_IF; do { //if (DerotFrequency < 1000000) // DerotFrequency = state->adc_clock/4; /* ZIF operation */ if (DerotFrequency > state->adc_clock) DerotFrequency = DerotFrequency - state->adc_clock; // User Alias Sampled_IF = ((32768 * (DerotFrequency/1000)) / (state->adc_clock/1000)) * 256; if(Sampled_IF > 8388607) Sampled_IF = 8388607; writereg(state, R367_QAM_MIX_NCO_LL, (Sampled_IF)); writereg(state, R367_QAM_MIX_NCO_HL, (Sampled_IF>>8)); writereg(state, R367_QAM_MIX_NCO_HH, (Sampled_IF>>16)); } while(0); return status; } static int QAM_Start(struct stv_state *state, s32 offsetFreq,s32 IntermediateFrequency) { int status = 0; u32 AGCTimeOut = 25; u32 TRLTimeOut = 100000000 / state->symbol_rate; u32 CRLSymbols = 0; u32 EQLTimeOut = 100; u32 SearchRange = state->symbol_rate / 25; u32 CRLTimeOut; u8 Temp; if( state->demod_state != QAMSet ) { writereg(state, R367_DEBUG_LT4,0x00); writereg(state, R367_DEBUG_LT5,0x01); writereg(state, R367_DEBUG_LT6,0x06);// R367_QAM_CTRL_1 writereg(state, R367_DEBUG_LT7,0x03);// R367_QAM_CTRL_2 writereg(state, R367_DEBUG_LT8,0x00); writereg(state, R367_DEBUG_LT9,0x00); // Tuner Setup writereg(state, R367_ANADIGCTRL,0x8B); /* Buffer Q disabled, I Enabled, signed ADC */ writereg(state, R367_DUAL_AD12,0x04); /* ADCQ disabled */ // Clock setup writereg(state, R367_ANACTRL,0x0D); /* PLL bypassed and disabled */ writereg(state, R367_TOPCTRL,0x10); // Set QAM writereg(state, R367_PLLMDIV,27); /* IC runs at 58 MHz with a 27 MHz crystal */ writereg(state, R367_PLLNDIV,232); writereg(state, R367_PLLSETUP,0x18); /* ADC clock is equal to system clock */ msleep(50); writereg(state, R367_ANACTRL,0x00); /* PLL enabled and used */ state->master_clock = 58000000; state->adc_clock = 58000000; state->demod_state = QAMSet; } state->m_bFirstTimeLock = true; state->m_DemodLockTime = -1; qam_set_modulation(state); QAM_SetSymbolRate(state); // Will make problems on low symbol rates ( < 2500000 ) switch(state->modulation) { default: case QAM_16: CRLSymbols = 150000; break; case QAM_32: CRLSymbols = 250000; break; case QAM_64: CRLSymbols = 200000; break; case QAM_128: CRLSymbols = 250000; break; case QAM_256: CRLSymbols = 250000; break; } CRLTimeOut = (25 * CRLSymbols * (SearchRange/1000)) / (state->symbol_rate/1000); CRLTimeOut = (1000 * CRLTimeOut) / state->symbol_rate; if( CRLTimeOut < 50 ) CRLTimeOut = 50; state->m_FECTimeOut = 20; state->m_DemodTimeOut = AGCTimeOut + TRLTimeOut + CRLTimeOut + EQLTimeOut; state->m_SignalTimeOut = AGCTimeOut + TRLTimeOut; // QAM_AGC_ACCUMRSTSEL = 0; readreg(state, R367_QAM_AGC_CTL,&state->m_Save_QAM_AGC_CTL); writereg(state, R367_QAM_AGC_CTL,state->m_Save_QAM_AGC_CTL & ~0x0F); // QAM_MODULUSMAP_EN = 0 readreg(state, R367_QAM_EQU_PNT_GAIN,&Temp); writereg(state, R367_QAM_EQU_PNT_GAIN,Temp & ~0x40); // QAM_SWEEP_EN = 0 readreg(state, R367_QAM_EQU_CTR_LPF_GAIN,&Temp); writereg(state, R367_QAM_EQU_CTR_LPF_GAIN,Temp & ~0x08); QAM_SetDerotFrequency(state, IntermediateFrequency); // Release TRL writereg(state, R367_QAM_CTRL_1,0x00); state->IF = IntermediateFrequency; state->demod_state = QAMStarted; return status; } static int OFDM_Start(struct stv_state *state, s32 offsetFreq,s32 IntermediateFrequency) { int status = 0; u8 GAIN_SRC1; u32 Derot; u8 SYR_CTL; u8 tmp1; u8 tmp2; if ( state->demod_state != OFDMSet ) { // QAM Disable writereg(state, R367_DEBUG_LT4, 0x00); writereg(state, R367_DEBUG_LT5, 0x00); writereg(state, R367_DEBUG_LT6, 0x00);// R367_QAM_CTRL_1 writereg(state, R367_DEBUG_LT7, 0x00);// R367_QAM_CTRL_2 writereg(state, R367_DEBUG_LT8, 0x00); writereg(state, R367_DEBUG_LT9, 0x00); // Tuner Setup writereg(state, R367_ANADIGCTRL, 0x89); /* Buffer Q disabled, I Enabled, unsigned ADC */ writereg(state, R367_DUAL_AD12, 0x04); /* ADCQ disabled */ // Clock setup writereg(state, R367_ANACTRL, 0x0D); /* PLL bypassed and disabled */ writereg(state, R367_TOPCTRL, 0x00); // Set OFDM writereg(state, R367_PLLMDIV, 1); /* IC runs at 54 MHz with a 27 MHz crystal */ writereg(state, R367_PLLNDIV, 8); writereg(state, R367_PLLSETUP, 0x18); /* ADC clock is equal to system clock */ msleep(50); writereg(state, R367_ANACTRL, 0x00); /* PLL enabled and used */ state->master_clock = 54000000; state->adc_clock = 54000000; state->demod_state = OFDMSet; } state->m_bFirstTimeLock = true; state->m_DemodLockTime = -1; // Set inversion in GAIN_SRC1 (fixed from init) // is in GAIN_SRC1, see below GAIN_SRC1 = 0xA0; // Bandwidth // Fixed values for 54 MHz switch(state->bandwidth) { case 0: case 8000000: // Normrate = 44384; writereg(state, R367_OFDM_TRL_CTL,0x14); writereg(state, R367_OFDM_TRL_NOMRATE1,0xB0); writereg(state, R367_OFDM_TRL_NOMRATE2,0x56); // Gain SRC = 2774 writereg(state, R367_OFDM_GAIN_SRC1,0x0A | GAIN_SRC1); writereg(state, R367_OFDM_GAIN_SRC2,0xD6); break; case 7000000: // Normrate = 38836; writereg(state, R367_OFDM_TRL_CTL,0x14); writereg(state, R367_OFDM_TRL_NOMRATE1,0xDA); writereg(state, R367_OFDM_TRL_NOMRATE2,0x4B); // Gain SRC = 2427 writereg(state, R367_OFDM_GAIN_SRC1,0x09 | GAIN_SRC1); writereg(state, R367_OFDM_GAIN_SRC2,0x7B); break; case 6000000: // Normrate = 33288; writereg(state, R367_OFDM_TRL_CTL,0x14); writereg(state, R367_OFDM_TRL_NOMRATE1,0x04); writereg(state, R367_OFDM_TRL_NOMRATE2,0x41); // Gain SRC = 2080 writereg(state, R367_OFDM_GAIN_SRC1,0x08 | GAIN_SRC1); writereg(state, R367_OFDM_GAIN_SRC2,0x20); break; default: return -EINVAL; break; } Derot = ((IntermediateFrequency / 1000) * 65536) / (state->master_clock / 1000); writereg(state, R367_OFDM_INC_DEROT1,(Derot>>8)); writereg(state, R367_OFDM_INC_DEROT2,(Derot)); readreg(state, R367_OFDM_SYR_CTL,&SYR_CTL); SYR_CTL &= ~0x78; writereg(state, R367_OFDM_SYR_CTL,SYR_CTL); // EchoPos = 0 writereg(state, R367_OFDM_COR_MODEGUARD,0x03); // Force = 0, Mode = 0, Guard = 3 SYR_CTL &= 0x01; writereg(state, R367_OFDM_SYR_CTL,SYR_CTL); // SYR_TR_DIS = 0 msleep(5); writereg(state, R367_OFDM_COR_CTL,0x20); // Start core // -- Begin M.V. // Reset FEC and Read Solomon readreg(state, R367_OFDM_SFDLYSETH,&tmp1); readreg(state, R367_TSGENERAL,&tmp2); writereg(state, R367_OFDM_SFDLYSETH,tmp1 | 0x08); writereg(state, R367_TSGENERAL,tmp2 | 0x01); // -- End M.V. state->m_SignalTimeOut = 200; state->IF = IntermediateFrequency; state->demod_state = OFDMStarted; state->m_DemodTimeOut = 0; state->m_FECTimeOut = 0; state->m_TSTimeOut = 0; return status; } #if 0 static int Stop(struct stv_state *state) { int status = 0; switch(state->demod_state) { case QAMStarted: status = writereg(state, R367_QAM_CTRL_1,0x06); state->demod_state = QAMSet; break; case OFDMStarted: status = writereg(state, R367_OFDM_COR_CTL,0x00); state->demod_state = OFDMSet; break; default: break; } return status; } #endif static int QAM_GetSignalToNoise(struct stv_state *state, s32 *pSignalToNoise) { u32 RegValAvg = 0; u8 RegVal[2]; int status = 0, i; *pSignalToNoise = 0; for (i = 0; i < 10; i += 1 ) { readregs(state, R367_QAM_EQU_SNR_LO, RegVal, 2); RegValAvg += RegVal[0] + 256 * RegVal[1]; } if (RegValAvg != 0) { s32 Power = 1; switch(state->modulation) { case QAM_16: Power = 20480; break; case QAM_32: Power = 23040; break; case QAM_64: Power = 21504; break; case QAM_128: Power = 23616; break; case QAM_256: Power = 21760; break; default: break; } *pSignalToNoise = INTLOG10X100((Power * 320) / RegValAvg); } else { *pSignalToNoise = 380; } return status; } static int OFDM_GetSignalToNoise(struct stv_state *state, s32 *pSignalToNoise) { u8 CHC_SNR = 0; int status = readreg(state, R367_OFDM_CHC_SNR, &CHC_SNR); if (status >= 0) { // Note: very unclear documentation on this. // Datasheet states snr = CHC_SNR/4 dB -> way to high values! // Software snr = ( 1000 * CHC_SNR ) / 8 / 32 / 10; -> to low values // Comment in SW states this should be ( 1000 * CHC_SNR ) / 4 / 32 / 10; for the 367 // 361/362 Datasheet: snr = CHC_SNR/8 dB -> this looks best *pSignalToNoise = ( (s32)CHC_SNR * 10) / 8; } //printk("SNR %d\n", *pSignalToNoise); return status; } #if 0 static int DVBC_GetQuality(struct stv_state *state, s32 SignalToNoise, s32 *pQuality) { *pQuality = 100; return 0; }; static int DVBT_GetQuality(struct stv_state *state, s32 SignalToNoise, s32 *pQuality) { static s32 QE_SN[] = { 51, // QPSK 1/2 69, // QPSK 2/3 79, // QPSK 3/4 89, // QPSK 5/6 97, // QPSK 7/8 108, // 16-QAM 1/2 131, // 16-QAM 2/3 146, // 16-QAM 3/4 156, // 16-QAM 5/6 160, // 16-QAM 7/8 165, // 64-QAM 1/2 187, // 64-QAM 2/3 202, // 64-QAM 3/4 216, // 64-QAM 5/6 225, // 64-QAM 7/8 }; u8 TPS_Received[2]; int Constellation; int CodeRate; s32 SignalToNoiseRel, BERQuality; *pQuality = 0; readregs(state, R367_OFDM_TPS_RCVD2, TPS_Received, sizeof(TPS_Received)); Constellation = TPS_Received[0] & 0x03; CodeRate = TPS_Received[1] & 0x07; if( Constellation > 2 || CodeRate > 5 ) return -1; SignalToNoiseRel = SignalToNoise - QE_SN[Constellation * 5 + CodeRate]; BERQuality = 100; if( SignalToNoiseRel < -70 ) *pQuality = 0; else if( SignalToNoiseRel < 30 ) { *pQuality = ((SignalToNoiseRel + 70) * BERQuality)/100; } else *pQuality = BERQuality; return 0; }; static s32 DVBCQuality(struct stv_state *state, s32 SignalToNoise) { s32 SignalToNoiseRel = 0; s32 Quality = 0; s32 BERQuality = 100; switch(state->modulation) { case QAM_16: SignalToNoiseRel = SignalToNoise - 200 ; break; case QAM_32: SignalToNoiseRel = SignalToNoise - 230 ; break; // Not in NorDig case QAM_64: SignalToNoiseRel = SignalToNoise - 260 ; break; case QAM_128: SignalToNoiseRel = SignalToNoise - 290 ; break; case QAM_256: SignalToNoiseRel = SignalToNoise - 320 ; break; } if( SignalToNoiseRel < -70 ) Quality = 0; else if( SignalToNoiseRel < 30 ) { Quality = ((SignalToNoiseRel + 70) * BERQuality)/100; } else Quality = BERQuality; return Quality; } static int GetQuality(struct stv_state *state, s32 SignalToNoise, s32 *pQuality) { *pQuality = 0; switch(state->demod_state) { case QAMStarted: *pQuality = DVBCQuality(state, SignalToNoise); break; case OFDMStarted: return DVBT_GetQuality(state, SignalToNoise, pQuality); } return 0; }; #endif static int attach_init(struct stv_state *state) { int stat = 0; stat = readreg(state, R367_ID, &state->ID); if ( stat < 0 || state->ID != 0x60 ) return -ENODEV; printk("stv0367 found\n"); writereg(state, R367_TOPCTRL, 0x10); write_init_table(state, base_init); write_init_table(state, qam_init); writereg(state, R367_TOPCTRL, 0x00); write_init_table(state, ofdm_init); writereg(state, R367_OFDM_GAIN_SRC1, 0x2A); writereg(state, R367_OFDM_GAIN_SRC2, 0xD6); writereg(state, R367_OFDM_INC_DEROT1, 0x55); writereg(state, R367_OFDM_INC_DEROT2, 0x55); writereg(state, R367_OFDM_TRL_CTL, 0x14); writereg(state, R367_OFDM_TRL_NOMRATE1, 0xAE); writereg(state, R367_OFDM_TRL_NOMRATE2, 0x56); writereg(state, R367_OFDM_FEPATH_CFG, 0x0); // OFDM TS Setup writereg(state, R367_OFDM_TSCFGH, 0x70); writereg(state, R367_OFDM_TSCFGM, 0xC0); writereg(state, R367_OFDM_TSCFGL, 0x20); writereg(state, R367_OFDM_TSSPEED, 0x40); // Fixed at 54 MHz //writereg(state, R367_TSTBUS, 0x80); // Invert CLK writereg(state, R367_OFDM_TSCFGH, 0x71); if (state->cont_clock) writereg(state, R367_OFDM_TSCFGH, 0xf0); else writereg(state, R367_OFDM_TSCFGH, 0x70); writereg(state, R367_TOPCTRL, 0x10); // Also needed for QAM writereg(state, R367_OFDM_AGC12C, 0x01); // AGC Pin setup writereg(state, R367_OFDM_AGCCTRL1, 0x8A); // // QAM TS setup, note exact format also depends on descrambler settings writereg(state, R367_QAM_OUTFORMAT_0, 0x85); // Inverted Clock, Swap, serial // writereg(state, R367_QAM_OUTFORMAT_1, 0x00); // // Clock setup writereg(state, R367_ANACTRL, 0x0D); /* PLL bypassed and disabled */ if( state->master_clock == 58000000 ) { writereg(state, R367_PLLMDIV,27); /* IC runs at 58 MHz with a 27 MHz crystal */ writereg(state, R367_PLLNDIV,232); } else { writereg(state, R367_PLLMDIV,1); /* IC runs at 54 MHz with a 27 MHz crystal */ writereg(state, R367_PLLNDIV,8); } writereg(state, R367_PLLSETUP, 0x18); /* ADC clock is equal to system clock */ // Tuner setup writereg(state, R367_ANADIGCTRL, 0x8b); /* Buffer Q disabled, I Enabled, signed ADC */ writereg(state, R367_DUAL_AD12, 0x04); /* ADCQ disabled */ writereg(state, R367_QAM_FSM_SNR2_HTH, 0x23); /* Improves the C/N lock limit */ writereg(state, R367_QAM_IQ_QAM, 0x01); /* ZIF/IF Automatic mode */ writereg(state, R367_QAM_EQU_FFE_LEAKAGE, 0x83); /* Improving burst noise performances */ writereg(state, R367_QAM_IQDEM_ADJ_EN, 0x05); /* Improving ACI performances */ writereg(state, R367_ANACTRL, 0x00); /* PLL enabled and used */ writereg(state, R367_I2CRPT, state->I2CRPT); state->demod_state = QAMSet; return stat; } static void release(struct dvb_frontend* fe) { struct stv_state *state=fe->demodulator_priv; printk("%s\n", __FUNCTION__); kfree(state); } static int gate_ctrl(struct dvb_frontend *fe, int enable) { struct stv_state *state = fe->demodulator_priv; u8 i2crpt = state->I2CRPT & ~0x80; if (enable) i2crpt |= 0x80; if (writereg(state, R367_I2CRPT, i2crpt) < 0) return -1; state->I2CRPT = i2crpt; return 0; } #if 0 static int c_track(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { return DVBFE_ALGO_SEARCH_AGAIN; } #endif #if 0 int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp); int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp); #endif static int ofdm_lock(struct stv_state *state) { int status = 0; u8 OFDM_Status; s32 DemodTimeOut = 10; s32 FECTimeOut = 0; s32 TSTimeOut = 0; u8 CPAMPMin = 255; u8 CPAMPValue; u8 SYR_STAT; u8 FFTMode; u8 TSStatus; msleep(state->m_SignalTimeOut); readreg(state, R367_OFDM_STATUS,&OFDM_Status); if (!(OFDM_Status & 0x40)) return -1; //printk("lock 1\n"); readreg(state, R367_OFDM_SYR_STAT,&SYR_STAT); FFTMode = (SYR_STAT & 0x0C) >> 2; switch(FFTMode) { case 0: // 2K DemodTimeOut = 10; FECTimeOut = 150; TSTimeOut = 125; CPAMPMin = 20; break; case 1: // 8K DemodTimeOut = 55; FECTimeOut = 600; TSTimeOut = 500; CPAMPMin = 80; break; case 2: // 4K DemodTimeOut = 40; FECTimeOut = 300; TSTimeOut = 250; CPAMPMin = 30; break; } state->m_OFDM_FFTMode = FFTMode; readreg(state, R367_OFDM_PPM_CPAMP_DIR,&CPAMPValue); msleep(DemodTimeOut); { // Release FEC and Read Solomon Reset u8 tmp1; u8 tmp2; readreg(state, R367_OFDM_SFDLYSETH,&tmp1); readreg(state, R367_TSGENERAL,&tmp2); writereg(state, R367_OFDM_SFDLYSETH,tmp1 & ~0x08); writereg(state, R367_TSGENERAL,tmp2 & ~0x01); } msleep(FECTimeOut); if( (OFDM_Status & 0x98) != 0x98 ) ;//return -1; //printk("lock 2\n"); { u8 Guard = (SYR_STAT & 0x03); if(Guard < 2) { u8 tmp; readreg(state, R367_OFDM_SYR_CTL,&tmp); writereg(state, R367_OFDM_SYR_CTL,tmp & ~0x04); // Clear AUTO_LE_EN readreg(state, R367_OFDM_SYR_UPDATE,&tmp); writereg(state, R367_OFDM_SYR_UPDATE,tmp & ~0x10); // Clear SYR_FILTER } else { u8 tmp; readreg(state, R367_OFDM_SYR_CTL,&tmp); writereg(state, R367_OFDM_SYR_CTL,tmp | 0x04); // Set AUTO_LE_EN readreg(state, R367_OFDM_SYR_UPDATE,&tmp); writereg(state, R367_OFDM_SYR_UPDATE,tmp | 0x10); // Set SYR_FILTER } // apply Sfec workaround if 8K 64QAM CR!=1/2 if( FFTMode == 1) { u8 tmp[2]; readregs(state, R367_OFDM_TPS_RCVD2, tmp, 2); if( ((tmp[0] & 0x03) == 0x02) && (( tmp[1] & 0x07 ) != 0) ) { writereg(state, R367_OFDM_SFDLYSETH,0xc0); writereg(state, R367_OFDM_SFDLYSETM,0x60); writereg(state, R367_OFDM_SFDLYSETL,0x00); } else { writereg(state, R367_OFDM_SFDLYSETH,0x00); } } } msleep(TSTimeOut); readreg(state, R367_OFDM_TSSTATUS,&TSStatus); if( (TSStatus & 0x80) != 0x80 ) return -1; //printk("lock 3\n"); return status; } static int set_parameters(struct dvb_frontend *fe) { int stat; struct stv_state *state = fe->demodulator_priv; u32 OF = 0; u32 IF; switch (fe->dtv_property_cache.delivery_system) { case SYS_DVBC_ANNEX_A: state->omode = OM_DVBC; /* symbol rate 0 might cause an oops */ if (fe->dtv_property_cache.symbol_rate == 0) { printk(KERN_ERR "stv0367dd: Invalid symbol rate\n"); return -EINVAL; } break; case SYS_DVBT: state->omode = OM_DVBT; break; default: return -EINVAL; } if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe); state->modulation = fe->dtv_property_cache.modulation; state->symbol_rate = fe->dtv_property_cache.symbol_rate; state->bandwidth = fe->dtv_property_cache.bandwidth_hz; fe->ops.tuner_ops.get_if_frequency(fe, &IF); //fe->ops.tuner_ops.get_frequency(fe, &IF); switch(state->omode) { case OM_DVBT: stat = OFDM_Start(state, OF, IF); ofdm_lock(state); break; case OM_DVBC: case OM_QAM_ITU_C: stat = QAM_Start(state, OF, IF); break; default: stat = -EINVAL; } //printk("%s IF=%d OF=%d done\n", __FUNCTION__, IF, OF); return stat; } #if 0 static int c_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { //struct stv_state *state = fe->demodulator_priv; //printk("%s\n", __FUNCTION__); return 0; } static int OFDM_GetLockStatus(struct stv_state *state, LOCK_STATUS* pLockStatus, s32 Time) { int status = STATUS_SUCCESS; u8 OFDM_Status; s32 DemodTimeOut = 0; s32 FECTimeOut = 0; s32 TSTimeOut = 0; u8 CPAMPMin = 255; u8 CPAMPValue; bool SYRLock; u8 SYR_STAT; u8 FFTMode; u8 TSStatus; readreg(state, R367_OFDM_STATUS,&OFDM_Status); SYRLock = (OFDM_Status & 0x40) != 0; if( Time > m_SignalTimeOut && !SYRLock ) { *pLockStatus = NEVER_LOCK; break; } if( !SYRLock ) break; *pLockStatus = SIGNAL_PRESENT; // Check Mode readreg(state, R367_OFDM_SYR_STAT,&SYR_STAT); FFTMode = (SYR_STAT & 0x0C) >> 2; switch(FFTMode) { case 0: // 2K DemodTimeOut = 10; FECTimeOut = 150; TSTimeOut = 125; CPAMPMin = 20; break; case 1: // 8K DemodTimeOut = 55; FECTimeOut = 600; TSTimeOut = 500; CPAMPMin = 80; break; case 2: // 4K DemodTimeOut = 40; FECTimeOut = 300; TSTimeOut = 250; CPAMPMin = 30; break; } m_OFDM_FFTMode = FFTMode; if( m_DemodTimeOut == 0 && m_bFirstTimeLock ) { m_DemodTimeOut = Time + DemodTimeOut; //break; } readreg(state, R367_OFDM_PPM_CPAMP_DIR,&CPAMPValue); if( Time <= m_DemodTimeOut && CPAMPValue < CPAMPMin ) { break; } if( CPAMPValue < CPAMPMin && m_bFirstTimeLock ) { // initiate retry *pLockStatus = NEVER_LOCK; break; } if( CPAMPValue < CPAMPMin ) break; *pLockStatus = DEMOD_LOCK; if( m_FECTimeOut == 0 && m_bFirstTimeLock ) { // Release FEC and Read Solomon Reset u8 tmp1; u8 tmp2; readreg(state, R367_OFDM_SFDLYSETH,&tmp1); readreg(state, R367_TSGENERAL,&tmp2); writereg(state, R367_OFDM_SFDLYSETH,tmp1 & ~0x08); writereg(state, R367_TSGENERAL,tmp2 & ~0x01); m_FECTimeOut = Time + FECTimeOut; } // Wait for TSP_LOCK, LK, PRF if( (OFDM_Status & 0x98) != 0x98 ) { if( Time > m_FECTimeOut ) *pLockStatus = NEVER_LOCK; break; } if( m_bFirstTimeLock && m_TSTimeOut == 0) { u8 Guard = (SYR_STAT & 0x03); if(Guard < 2) { u8 tmp; readreg(state, R367_OFDM_SYR_CTL,&tmp); writereg(state, R367_OFDM_SYR_CTL,tmp & ~0x04); // Clear AUTO_LE_EN readreg(state, R367_OFDM_SYR_UPDATE,&tmp); writereg(state, R367_OFDM_SYR_UPDATE,tmp & ~0x10); // Clear SYR_FILTER } else { u8 tmp; readreg(state, R367_OFDM_SYR_CTL,&tmp); writereg(state, R367_OFDM_SYR_CTL,tmp | 0x04); // Set AUTO_LE_EN readreg(state, R367_OFDM_SYR_UPDATE,&tmp); writereg(state, R367_OFDM_SYR_UPDATE,tmp | 0x10); // Set SYR_FILTER } // apply Sfec workaround if 8K 64QAM CR!=1/2 if( FFTMode == 1) { u8 tmp[2]; readreg(state, R367_OFDM_TPS_RCVD2,tmp,2); if( ((tmp[0] & 0x03) == 0x02) && (( tmp[1] & 0x07 ) != 0) ) { writereg(state, R367_OFDM_SFDLYSETH,0xc0); writereg(state, R367_OFDM_SFDLYSETM,0x60); writereg(state, R367_OFDM_SFDLYSETL,0x00); } else { writereg(state, R367_OFDM_SFDLYSETH,0x00); } } m_TSTimeOut = Time + TSTimeOut; } readreg(state, R367_OFDM_TSSTATUS,&TSStatus); if( (TSStatus & 0x80) != 0x80 ) { if( Time > m_TSTimeOut ) *pLockStatus = NEVER_LOCK; break; } *pLockStatus = MPEG_LOCK; m_bFirstTimeLock = false; return status; } #endif static int read_status(struct dvb_frontend *fe, fe_status_t *status) { struct stv_state *state = fe->demodulator_priv; *status=0; switch(state->demod_state) { case QAMStarted: { u8 FEC_Lock; u8 QAM_Lock; readreg(state, R367_QAM_FSM_STS, &QAM_Lock); QAM_Lock &= 0x0F; if (QAM_Lock >10) *status|=0x07; readreg(state, R367_QAM_FEC_STATUS,&FEC_Lock); if (FEC_Lock&2) *status|=0x1f; if (state->m_bFirstTimeLock) { state->m_bFirstTimeLock = false; // QAM_AGC_ACCUMRSTSEL to Tracking; writereg(state, R367_QAM_AGC_CTL, state->m_Save_QAM_AGC_CTL); } break; } case OFDMStarted: { u8 OFDM_Status; u8 TSStatus; readreg(state, R367_OFDM_TSSTATUS, &TSStatus); readreg(state, R367_OFDM_STATUS, &OFDM_Status); if (OFDM_Status & 0x40) *status |= FE_HAS_SIGNAL; if ((OFDM_Status & 0x98) == 0x98) *status|=0x0f; if (TSStatus & 0x80) *status |= 0x1f; break; } default: break; } return 0; } static int read_ber_ter(struct dvb_frontend *fe, u32 *ber) { struct stv_state *state = fe->demodulator_priv; u32 err; u8 cnth, cntm, cntl; #if 1 readreg(state, R367_OFDM_SFERRCNTH, &cnth); if (cnth & 0x80) { *ber = state->ber; return 0; } readreg(state, R367_OFDM_SFERRCNTM, &cntm); readreg(state, R367_OFDM_SFERRCNTL, &cntl); err = ((cnth & 0x7f) << 16) | (cntm << 8) | cntl; #if 0 { u64 err64; err64 = (u64) err; err64 *= 1000000000ULL; err64 >>= 21; err = err64; } #endif #else readreg(state, R367_OFDM_ERRCNT1HM, &cnth); #endif *ber = state->ber = err; return 0; } static int read_ber_cab(struct dvb_frontend *fe, u32 *ber) { struct stv_state *state = fe->demodulator_priv; u32 err; u8 cntm, cntl, ctrl; readreg(state, R367_QAM_BERT_1, &ctrl); if (!(ctrl & 0x20)) { readreg(state, R367_QAM_BERT_2, &cntl); readreg(state, R367_QAM_BERT_3, &cntm); err = (cntm << 8) | cntl; //printk("err %04x\n", err); state->ber = err; writereg(state, R367_QAM_BERT_1, 0x27); } *ber = (u32) state->ber; return 0; } static int read_ber(struct dvb_frontend *fe, u32 *ber) { struct stv_state *state = fe->demodulator_priv; if (state->demod_state == QAMStarted) return read_ber_cab(fe, ber); if (state->demod_state == OFDMStarted) return read_ber_ter(fe, ber); *ber = 0; return 0; } static int read_signal_strength(struct dvb_frontend *fe, u16 *strength) { if (fe->ops.tuner_ops.get_rf_strength) fe->ops.tuner_ops.get_rf_strength(fe, strength); else *strength = 0; return 0; } static int read_snr(struct dvb_frontend *fe, u16 *snr) { struct stv_state *state = fe->demodulator_priv; s32 snr2 = 0; switch(state->demod_state) { case QAMStarted: QAM_GetSignalToNoise(state, &snr2); break; case OFDMStarted: OFDM_GetSignalToNoise(state, &snr2); break; default: break; } *snr = snr2&0xffff; return 0; } static int read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { struct stv_state *state = fe->demodulator_priv; u8 errl, errm, errh; u8 val; switch(state->demod_state) { case QAMStarted: readreg(state, R367_QAM_RS_COUNTER_4, &errl); readreg(state, R367_QAM_RS_COUNTER_5, &errm); *ucblocks = (errm << 8) | errl; break; case OFDMStarted: readreg(state, R367_OFDM_SFERRCNTH, &val); if ((val & 0x80) == 0) { readreg(state, R367_OFDM_ERRCNT1H, &errh); readreg(state, R367_OFDM_ERRCNT1M, &errl); readreg(state, R367_OFDM_ERRCNT1L, &errm); state->ucblocks = (errh <<16) | (errm << 8) | errl; } *ucblocks = state->ucblocks; break; default: *ucblocks = 0; break; } return 0; } static int c_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *sets) { sets->min_delay_ms=3000; sets->max_drift=0; sets->step_size=0; return 0; } static int get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *sets) { switch (fe->dtv_property_cache.delivery_system) { case SYS_DVBC_ANNEX_A: case SYS_DVBC_ANNEX_C: return c_get_tune_settings(fe, sets); default: /* DVB-T: Use info.frequency_stepsize. */ return -EINVAL; } } #if 0 static int t_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { //struct stv_state *state = fe->demodulator_priv; //printk("%s\n", __FUNCTION__); return 0; } static enum dvbfe_algo algo(struct dvb_frontend *fe) { return DVBFE_ALGO_CUSTOM; } #endif static struct dvb_frontend_ops common_ops = { .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT }, .info = { .name = "STV0367 DVB-C DVB-T", .frequency_stepsize = 166667, /* DVB-T only */ .frequency_min = 47000000, /* DVB-T: 47125000 */ .frequency_max = 865000000, /* DVB-C: 862000000 */ .symbol_rate_min = 870000, .symbol_rate_max = 11700000, .caps = /* DVB-C */ FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO | /* DVB-T */ FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS }, .release = release, .i2c_gate_ctrl = gate_ctrl, .get_tune_settings = get_tune_settings, .set_frontend = set_parameters, .read_status = read_status, .read_ber = read_ber, .read_signal_strength = read_signal_strength, .read_snr = read_snr, .read_ucblocks = read_ucblocks, }; static void init_state(struct stv_state *state, struct stv0367_cfg *cfg) { u32 ulENARPTLEVEL = 5; u32 ulQAMInversion = 2; state->omode = OM_NONE; state->adr = cfg->adr; state->cont_clock = cfg->cont_clock; mutex_init(&state->mutex); mutex_init(&state->ctlock); memcpy(&state->frontend.ops, &common_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; state->master_clock = 58000000; state->adc_clock = 58000000; state->I2CRPT = 0x08 | ((ulENARPTLEVEL & 0x07) << 4); state->qam_inversion = ((ulQAMInversion & 3) << 6 ); state->demod_state = Off; } struct dvb_frontend *stv0367_attach(struct i2c_adapter *i2c, struct stv0367_cfg *cfg, struct dvb_frontend **fe_t) { struct stv_state *state = NULL; state = kzalloc(sizeof(struct stv_state), GFP_KERNEL); if (!state) return NULL; state->i2c = i2c; init_state(state, cfg); if (attach_init(state)<0) goto error; return &state->frontend; error: printk("stv0367: not found\n"); kfree(state); return NULL; } MODULE_DESCRIPTION("STV0367DD driver"); MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(stv0367_attach);