1
0
mirror of https://github.com/DigitalDevices/dddvb.git synced 2023-10-10 13:37:43 +02:00
dddvb/frontends/stv0367dd.c

2161 lines
62 KiB
C

/*
* 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 <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
#include <linux/version.h>
#include <asm/div64.h>
#include <media/dvb_frontend.h>
#include "stv0367dd.h"
#include "stv0367dd_regs.h"
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;
enum fe_modulation 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 s32 Log10x100(u32 x)
{
static u32 LookupTable[100] = {
101157945, 103514217, 105925373, 108392691, 110917482,
113501082, 116144861, 118850223, 121618600, 124451461, // 800.5 - 809.5
127350308, 130316678, 133352143, 136458314, 139636836,
142889396, 146217717, 149623566, 153108746, 156675107, // 810.5 - 819.5
160324539, 164058977, 167880402, 171790839, 175792361,
179887092, 184077200, 188364909, 192752491, 197242274, // 820.5 - 829.5
201836636, 206538016, 211348904, 216271852, 221309471,
226464431, 231739465, 237137371, 242661010, 248313311, // 830.5 - 839.5
254097271, 260015956, 266072506, 272270131, 278612117,
285101827, 291742701, 298538262, 305492111, 312607937, // 840.5 - 849.5
319889511, 327340695, 334965439, 342767787, 350751874,
358921935, 367282300, 375837404, 384591782, 393550075, // 850.5 - 859.5
402717034, 412097519, 421696503, 431519077, 441570447,
451855944, 462381021, 473151259, 484172368, 495450191, // 860.5 - 869.5
506990708, 518800039, 530884444, 543250331, 555904257,
568852931, 582103218, 595662144, 609536897, 623734835, // 870.5 - 879.5
638263486, 653130553, 668343918, 683911647, 699841996,
716143410, 732824533, 749894209, 767361489, 785235635, // 880.5 - 889.5
803526122, 822242650, 841395142, 860993752, 881048873,
901571138, 922571427, 944060876, 966050879, 988553095, // 890.5 - 899.5
};
s32 y;
int i;
if (x == 0)
return 0;
y = 800;
if (x >= 1000000000) {
x /= 10;
y += 100;
}
while (x < 100000000) {
x *= 10;
y -= 100;
}
i = 0;
while (i < 100 && x > LookupTable[i])
i += 1;
y += i;
return y;
}
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 = Log10x100((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, enum fe_status *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_hz = 166667, /* DVB-T only */
.frequency_min_hz = 47000000, /* DVB-T: 47125000 */
.frequency_max_hz = 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 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 v2");
EXPORT_SYMBOL_GPL(stv0367_attach);