📄 tda10021.c
字号:
/* TDA10021 - Single Chip Cable Channel Receiver driver module used on the the Siemens DVB-C cards Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> Copyright (C) 2004 Markus Schulz <msc@antzsystem.de> Support for TDA10021 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <linux/config.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/string.h>#include <linux/slab.h>#include "dvb_frontend.h"#include "tda10021.h"struct tda10021_state { struct i2c_adapter* i2c; struct dvb_frontend_ops ops; /* configuration settings */ const struct tda10021_config* config; struct dvb_frontend frontend; u8 pwm; u8 reg0;};#if 0#define dprintk(x...) printk(x)#else#define dprintk(x...)#endifstatic int verbose;//ZHU#define m_iIfagcMax 140#define m_iIfagcMin 90#define m_iRfagcMax 255#define m_iRfagcMin 0#define m_iMpegoutput 1 // 0 Parllel 1 Serial Msb 2 Serial LSB#define m_Mpegmode 0 // 0 Mode A 1 Mode B #define m_MpegmodeBclk 13<<4#define m_Mpegclk 0 //0 Falling 1 rising //#define XIN 57840000UL#define XIN 58000000UL#define uSysClk XIN#define DISABLE_INVERSION(reg0) do { reg0 |= 0x20; } while (0)#define ENABLE_INVERSION(reg0) do { reg0 &= ~0x20; } while (0)#define HAS_INVERSION(reg0) (!(reg0 & 0x20))#define FIN (XIN >> 4)static int tda10021_inittab_size = 0x40;static u8 tda10021_inittab[0x40]={// 0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a,// 0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40,// 0xb8, 0x3f, 0xa0, 0x00, 0xcd, 0x01, 0x00, 0xff,// 0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00,// 0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00,// 0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58,// 0x00, 0x00, 0x80, 0x00, 0x80, 0xff, 0x00, 0x00,// 0x04, 0x2d, 0x2f, 0xff, 0x00, 0x00, 0x00, 0x00,// 0-8 1-9 2-a 3-b 4-c 5-d 6-e 7-f 0x47, 0x8c, 0x23, 0x4a, 0x0a, 0x64, 0x77, 0x1a,//0 0x74, 0x96, 0x96, 0x7b, 0x1a, 0x9b, 0x03, 0x40,//8 0x78, 0x2f, 0xa1, 0x00, 0xc1, 0x02, 0x00, 0x46,//10 0x0a, 0x06, 0x7c, 0x31, 0x30, 0x0b, 0x00, 0x00,//18 0x92, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,//20 0x1c, 0x00, 0x21, 0x11, 0x0d, 0x94, 0x08, 0x5a,//28 0x00, 0x00, 0x80, 0x00, 0x80, 0xff, 0x00, 0xfc,//30 0x07, 0x2f, 0x0f, 0x8c, 0x5a, 0x00, 0x00, 0x00,//38};static int tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data){ u8 buf[] = { reg, data }; struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; int ret; ret = i2c_transfer (state->i2c, &msg, 1); if (ret != 1) printk("DVB: TDA10021(%d): %s, writereg error " "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", state->frontend.dvb->num, __FUNCTION__, reg, data, ret); msleep(10); return (ret != 1) ? -EREMOTEIO : 0;}static u8 tda10021_readreg (struct tda10021_state* state, u8 reg){ u8 b0 [] = { reg }; u8 b1 [] = { 0 }; struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; int ret; ret = i2c_transfer (state->i2c, msg, 2); if (ret != 2) printk("DVB: TDA10021(%d): %s: readreg error (ret == %i)\n", state->frontend.dvb->num, __FUNCTION__, ret); return b1[0];}//Zhustatic int ChipWriteMasked(struct tda10021_state * state,u8 addr,u8 mask,u8 data ){ u8 i; i=tda10021_readreg(state,addr); i=i&~mask; i=i|(data & mask); return tda10021_writereg(state,addr,i); }//get access to tunerstatic int lock_tuner(struct tda10021_state* state){ u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] | 0x80 }; struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; if(i2c_transfer(state->i2c, &msg, 1) != 1) { printk("tda10021: lock tuner fails\n"); return -EREMOTEIO; } return 0;}//release access from tunerstatic int unlock_tuner(struct tda10021_state* state){ u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] & 0x7f }; struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; if(i2c_transfer(state->i2c, &msg_post, 1) != 1) { printk("tda10021: unlock tuner fails\n"); return -EREMOTEIO; } return 0;}static void Q10021AlgoDelay(u32 uNbSymbol,u32 uSR){ uNbSymbol *= 1000; uNbSymbol += uSR/2; uNbSymbol /= uSR; //printk("udelay %d\n",uNbSymbol); udelay((unsigned short)uNbSymbol);}static u8 Q10021AlgoGain(struct tda10021_state* state,u32 uSR,u8 bGain){ long lRCentralCoef, lICentralCoef; u8 pReadCoef[2]; do { // read the real part of the central coef of the equalizer pReadCoef[0]=(u8)tda10021_readreg(state,0x50); pReadCoef[1]=(u8)tda10021_readreg(state,0x51); lRCentralCoef = (u32)(pReadCoef[0] << 3 | pReadCoef[1] >> 5); if (lRCentralCoef & 0x400) lRCentralCoef |= 0xFFFFF800; // lRCentralCoef^2 lRCentralCoef *= lRCentralCoef; // read the imaginary part of the central coef of the equalizer pReadCoef[0]=(u8)tda10021_readreg(state,0x90); pReadCoef[1]=(u8)tda10021_readreg(state,0x91); lICentralCoef = (u32)(pReadCoef[0] << 3 | pReadCoef[1] >> 5); if (lICentralCoef & 0x400) lICentralCoef |= 0xFFFFF800; // lICentralCoef^2 lICentralCoef *= lICentralCoef; // test the module if ((lRCentralCoef + lICentralCoef) >490000) { //printk("bGain=%x\n",bGain); // no scanning so use all agin - test if gain max is reached if (bGain < 5) { // try next gain bGain++; ChipWriteMasked(state,0x0e,0xe0, (u8)(bGain << 5)); // wait for synchro Q10021AlgoDelay(10000, uSR); } else return 6;//err } else return bGain; // if ok }while(1);}static int tda10021_RunAlgo (struct tda10021_state* state,u32 uSR, u8 *pGain, u8 bAutoGain, u8 bAutoSpecInv){ u8 bAGC1, bAGC2, bSI,bGainFound; if(bAutoGain)*pGain=0; bGainFound=*pGain; // set the gain ChipWriteMasked(state,0x0e,0xe0, (u8)(bGainFound << 5)); // set the AGC time constant ChipWriteMasked(state,0x02, 0x03, 1); // program the CARCONF ChipWriteMasked(state,0x04, 0x3f, 0x0a); // only use the central coef and disable other adaptation when gain auto if (bAutoGain) ChipWriteMasked(state,0x1c, 0x08, 0x08); // reset the demod reset CLB bit ChipWriteMasked(state,0x00, 0x01, 0); Q10021AlgoDelay(80000, uSR); // read the AGC values // test if there is a signal bAGC1=(u8)tda10021_readreg(state,0x17); bAGC2=(u8)tda10021_readreg(state,0x2f); //printk("-----------bAGC1=%x,bAGC2=%x\n",bAGC1,bAGC2); if (bAGC1 == 255 && bAGC2 == 255) return 1; /*UpdateData(FALSE);*/ // test the algo in used if (bAutoGain) { if ((bGainFound=Q10021AlgoGain(state, uSR, bGainFound)) == 6) return 2;// if err else { // set the AGC time constant ChipWriteMasked(state,0x02, 0x03, 1); // use all coef ChipWriteMasked(state,0x1c, 0x08, 0); // reset the demod ChipWriteMasked(state,0x00, 0x01, 0); Q10021AlgoDelay(80000, uSR); *pGain=bGainFound; } } // set the AGC time constant ChipWriteMasked(state,0x02, 0x03, 3); Q10021AlgoDelay(200000, uSR); // read the synchro registers // test if carlock u8 bSyncReg; bSyncReg=(u8)tda10021_readreg(state,0x11); if (!(bSyncReg & 0x02))return 3; // test if frame synchro if ((bSyncReg & 0x04) && !(bSyncReg & 0x40)) { //printk("-----------------------------fram synchro test ok\n"); // oK case if (uSR > 3000000) ChipWriteMasked(state,0x04, 0x3f, 0x02); else ChipWriteMasked(state,0x04, 0x3f, 0x0a); return 0; } // test if auto spectral inv else if(bAutoSpecInv) { // test the other spectral inversion bSI=(u8)tda10021_readreg(state,0x00); if (bSI & 0x20) bSI &= ~0x20; else bSI |= 0x20; //printk("-------------------------bSI=%x\n",bSI); tda10021_writereg(state,0x00,bSI); Q10021AlgoDelay(30000, uSR); // read the synchro registers bSyncReg=(u8)tda10021_readreg(state,0x11); // test if frame sync and DVB if ((bSyncReg & 0x04) && !(bSyncReg & 0x40)) { // oK case if (uSR > 3000000) ChipWriteMasked(state,0x04, 0x3f, 0x02); else ChipWriteMasked(state,0x04, 0x3f, 0x0a); return 0; } } return 4;}/*static int tda10021_setup_reg0 (struct tda10021_state* state, u8 reg0, fe_spectral_inversion_t inversion){ reg0 |= state->reg0 & 0x63; if (INVERSION_ON == inversion) { ENABLE_INVERSION(reg0); printk("Enable inversion\n"); } else if (INVERSION_OFF == inversion) { DISABLE_INVERSION(reg0); printk("Disable inversion\n"); } tda10021_writereg (state, 0x00, reg0 & 0xfe); tda10021_writereg (state, 0x00, reg0 | 0x01); state->reg0 = reg0; return 0;}*/static int tda10021_set_symbolrate (struct tda10021_state* state, u32 uFreqSymb){ u8 pWrite[4], bNdec, bSFil; u32 uBDR, uFreqSymbInv, uFreqSymb240;/* float fFreqSymb, fSysClk ,fResult, fBDR ;*/ u32 fFreqSymb, fSysClk ,fResult, fBDR ; // add 240 ppm to the SR uFreqSymb240 = uFreqSymb*240; uFreqSymb240 /= 1000000; uFreqSymb240 = uFreqSymb + uFreqSymb240; // calculate the number of decimation and the antialias filter bNdec = 0; bSFil = 0; if ((uFreqSymb240/10) < (uSysClk/123)){ bNdec = 0; bSFil = 1;} if ((uFreqSymb240/10) < (uSysClk/160)){ bNdec = 1; bSFil = 0;} if ((uFreqSymb240/10) < (uSysClk/246)){ bNdec = 1; bSFil = 1;} if ((uFreqSymb240/10) < (uSysClk/320)){ bNdec = 2; bSFil = 0;} if ((uFreqSymb240/10) < (uSysClk/492)){ bNdec = 2; bSFil = 1;} if ((uFreqSymb240/10) < (uSysClk/640)){ bNdec = 3; bSFil = 0;} if ((uFreqSymb240/10) < (uSysClk/984)){ bNdec = 3; bSFil = 1;} // program SFIL ChipWriteMasked(state,0x0e, 0x10, (u8)(bSFil<<4)); // program NDEC ChipWriteMasked(state,0x03, 0xc0, (u8)(bNdec<<6)); // calculate the inversion of the symbol frequency uFreqSymbInv = uSysClk*16; uFreqSymbInv >>= bNdec; // divide by 2^decim uFreqSymbInv += uFreqSymb/2; // rounding for division uFreqSymbInv /= uFreqSymb; if (uFreqSymbInv > 255) uFreqSymbInv = 255; // calculate the symbol rate// fFreqSymb = (u32)uFreqSymb;// fSysClk = (u32)uSysClk;// fResult = (u32)(1<<(24+bNdec));// fResult /= fSysClk;// fResult *= fFreqSymb;// uBDR = (u32)fResult; uBDR=(289262*(uFreqSymb/1000))/1000; uBDR=uBDR*(1<<bNdec); //printk("------------------------uBDR=%x\n",uBDR); //uBDR=1735574; // program the value in register of the symbol rate pWrite[0] = (u8)(uBDR); pWrite[1] = (u8)(uBDR >> 8); pWrite[2] = (u8)(uBDR >> 16); pWrite[3] = (u8)uFreqSymbInv; tda10021_writereg(state,0x0a, pWrite[0]); tda10021_writereg(state,0x0b, pWrite[1]); tda10021_writereg(state,0x0c, pWrite[2]); tda10021_writereg(state,0x0d, pWrite[3]); // return the value programmed// fBDR = (u32)uBDR;// fSysClk = (u32)uSysClk;// fResult = fBDR*fSysClk;// fResult /= (u32)(1<<(24+bNdec)); return (u32)fResult;}/*static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate){ s32 BDR; s32 BDRI; s16 SFIL=0; u16 NDEC = 0; u32 tmp, ratio; printk("symbolrate=%x(%d)\n",symbolrate,symbolrate); if (symbolrate > XIN/2) symbolrate = XIN/2; if (symbolrate < 500000) symbolrate = 500000; if (symbolrate < XIN/16) NDEC = 1; if (symbolrate < XIN/32) NDEC = 2; if (symbolrate < XIN/64) NDEC = 3; if (symbolrate < (u32)(XIN/12.3)) SFIL = 1; if (symbolrate < (u32)(XIN/16)) SFIL = 0; if (symbolrate < (u32)(XIN/24.6)) SFIL = 1; if (symbolrate < (u32)(XIN/32)) SFIL = 0; if (symbolrate < (u32)(XIN/49.2)) SFIL = 1; if (symbolrate < (u32)(XIN/64)) SFIL = 0; if (symbolrate < (u32)(XIN/98.4)) SFIL = 1; symbolrate <<= NDEC; ratio = (symbolrate << 4) / FIN;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -