📄 stv0299.c
字号:
/* Universal driver for STV0299/TDA5059/SL1935 based DVB QPSK frontends Alps BSRU6, LG TDQB-S00x Copyright (C) 2001-2002 Convergence Integrated Media GmbH <ralph@convergence.de>, <holger@convergence.de>, <js@convergence.de> Philips SU1278/SH Copyright (C) 2002 by Peter Schildmann <peter.schildmann@web.de> LG TDQF-S001F Copyright (C) 2002 Felix Domke <tmbinc@elitedvb.net> & Andreas Oberritter <andreas@oberritter.de> 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 <asm/errno.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/string.h>#include "dvb_frontend.h"#include "compat.h"static int debug = 0;#define dprintk if (debug) printkstaticinline void ddelay(int i){ current->state=TASK_INTERRUPTIBLE; schedule_timeout((HZ*i)/1000);}/* frontend types */#define UNKNOWN_FRONTEND -1#define PHILIPS_SU1278SH 0#define ALPS_BSRU6 1#define LG_TDQF_S001F 2/* Master Clock = 88 MHz */#define M_CLK (88000000UL) staticstruct dvb_frontend_info uni0299_info = { name: "STV0299/TSA5059/SL1935 based", type: FE_QPSK, frequency_min: 950000, frequency_max: 2150000, frequency_stepsize: 125, /* kHz for QPSK frontends */ frequency_tolerance: M_CLK/2000, symbol_rate_min: 1000000, symbol_rate_max: 45000000, symbol_rate_tolerance: 500, /* ppm */ notifier_delay: 0, caps: 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_QPSK | FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO | FE_CAN_CLEAN_SETUP};staticu8 init_tab [] = { /* clock registers */ 0x01, 0x15, /* K = 0, DIRCLK = 0, M = 0x15 */ 0x02, 0x30, /* STDBY = 0, VCO = 0 (ON), SERCLK = 0, P = 0 */ /* f_VCO = 4MHz * 4 * (M+1) / (K+1) = 352 MHz */ 0x03, 0x00, /* auxiliary clock not used */ 0x04, 0x7d, /* F22FR = 0x7d */ /* F22 = f_VCO / 128 / 0x7d = 22 kHz */ /* I2C bus repeater */ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ /* general purpose DAC registers */ 0x06, 0x40, /* DAC not used, set to high impendance mode */ 0x07, 0x00, /* DAC LSB */ /* DiSEqC registers */ 0x08, 0x40, /* DiSEqC off */ 0x09, 0x00, /* FIFO */ /* Input/Output configuration register */ 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ /* OP0 ctl = Normal, OP0 val = 1 (18 V) */ /* Nyquist filter = 00, QPSK reverse = 0 */ /* AGC1 control register */ 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ /* Timing loop register */ 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ 0x10, 0x3f, // AGC2 0x3d 0x11, 0x84, 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on 0x13, 0xb6, // alpha_car b:4 a:0 noise est:256ks derot:on 0x14, 0x93, // beat carc:0 d:0 e:0xf phase detect algo: 1 0x15, 0xc9, // lock detector threshold 0x16, 0x1d, /* AGC1 integrator value */ 0x17, 0x00, 0x18, 0x14, 0x19, 0xf2, 0x1a, 0x11, 0x1b, 0x9c, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x0b, 0x1f, 0x50, 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, 0x24, 0xff, 0x25, 0xff, 0x26, 0xff, 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 0x29, 0x1e, // 1/2 threshold 0x2a, 0x14, // 2/3 threshold 0x2b, 0x0f, // 3/4 threshold 0x2c, 0x09, // 5/6 threshold 0x2d, 0x05, // 7/8 threshold 0x2e, 0x01, 0x31, 0x1f, // test all FECs 0x32, 0x19, // viterbi and synchro search 0x33, 0xfc, // rs control 0x34, 0x93, // error control 0x0b, 0x00, 0x27, 0x00, 0x2f, 0x00, 0x30, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00, 0x4c, 0x00, 0x4d, 0x00, 0x4e, 0x00, 0x4f, 0x00};staticint stv0299_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data){ int ret; u8 buf [] = { reg, data }; struct i2c_msg msg = { addr: 0x68, flags: 0, buf: buf, len: 2 }; dprintk ("%s\n", __FUNCTION__); ret = i2c->xfer (i2c, &msg, 1); if (ret != 1) dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " "ret == %i)\n", __FUNCTION__, reg, data, ret); return (ret != 1) ? -1 : 0;}staticu8 stv0299_readreg (struct dvb_i2c_bus *i2c, u8 reg){ int ret; u8 b0 [] = { reg }; u8 b1 [] = { 0 }; struct i2c_msg msg [] = { { addr: 0x68, flags: 0, buf: b0, len: 1 }, { addr: 0x68, flags: I2C_M_RD, buf: b1, len: 1 } }; dprintk ("%s\n", __FUNCTION__); ret = i2c->xfer (i2c, msg, 2); if (ret != 2) dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); return b1[0];}staticint stv0299_readregs (struct dvb_i2c_bus *i2c, u8 reg1, u8 *b, u8 len){ int ret; struct i2c_msg msg [] = { { addr: 0x68, flags: 0, buf: ®1, len: 1 }, { addr: 0x68, flags: I2C_M_RD, buf: b, len: len } }; dprintk ("%s\n", __FUNCTION__); ret = i2c->xfer (i2c, msg, 2); if (ret != 2) dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); return ret == 2 ? 0 : -1;}staticint pll_write (struct dvb_i2c_bus *i2c, u8 data [4], int ftype){ int ret; u8 rpt1 [] = { 0x05, 0xb5 }; /* enable i2c repeater on stv0299 */ /* TSA5059 i2c-bus address */ u8 addr = (ftype == PHILIPS_SU1278SH) ? 0x60 : 0x61; struct i2c_msg msg [] = {{ addr: 0x68, flags: 0, buf: rpt1, len: 2 }, { addr: addr, flags: 0, buf: data, len: 4 }}; dprintk ("%s\n", __FUNCTION__); ret = i2c->xfer (i2c, msg, 2); if (ret != 2) dprintk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret); return (ret != 2) ? -1 : 0;}staticint sl1935_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype){ u8 buf[4]; u32 div; u32 ratios[] = { 2000, 1000, 500, 250, 125 }; u8 ratio; for (ratio = 4; ratio > 0; ratio--) if ((freq / ratios[ratio]) <= 0x3fff) break; div = freq / ratios[ratio]; buf[0] = (freq >> 8) & 0x7f; buf[1] = freq & 0xff; buf[2] = 0x80 | ratio; if (freq < 1531000) buf[3] = 0x10; else buf[3] = 0x00; return pll_write (i2c, buf, ftype);}/** * set up the downconverter frequency divisor for a * reference clock comparision frequency of 125 kHz. */staticint tsa5059_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype){ u32 div = freq / 125; u8 buf[4] = { (div >> 8) & 0x7f, div & 0xff, 0x84 }; if (ftype == PHILIPS_SU1278SH) /* activate f_xtal/f_comp signal output */ /* charge pump current C0/C1 = 00 */ buf[3] = 0x20; else buf[3] = freq > 1530000 ? 0xc0 : 0xc4; dprintk ("%s\n", __FUNCTION__); return pll_write (i2c, buf, ftype);}staticint pll_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype){ if (ftype == LG_TDQF_S001F) return sl1935_set_tv_freq(i2c, freq, ftype); else return tsa5059_set_tv_freq(i2c, freq, ftype);}#if 0staticint tsa5059_read_status (struct dvb_i2c_bus *i2c){ int ret; u8 rpt1 [] = { 0x05, 0xb5 }; u8 stat [] = { 0 }; struct i2c_msg msg [] = {{ addr: 0x68, flags: 0, buf: rpt1, len: 2 }, { addr: 0x60, flags: I2C_M_RD, buf: stat, len: 1 }}; dprintk ("%s\n", __FUNCTION__); ret = i2c->xfer (i2c, msg, 2); if (ret != 2) dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); return stat[0];}#endifstaticint stv0299_init (struct dvb_i2c_bus *i2c, int ftype){ int i; dprintk("stv0299: init chip\n"); for (i=0; i<sizeof(init_tab); i+=2) stv0299_writereg (i2c, init_tab[i], init_tab[i+1]); /* AGC1 reference register setup */ if (ftype == PHILIPS_SU1278SH) stv0299_writereg (i2c, 0x0f, 0xd2); /* Iagc = Inverse, m1 = 18 */ else stv0299_writereg (i2c, 0x0f, 0x52); /* Iagc = Normal, m1 = 18 */ return 0;}staticint stv0299_check_inversion (struct dvb_i2c_bus *i2c){ dprintk ("%s\n", __FUNCTION__); if ((stv0299_readreg (i2c, 0x1b) & 0x98) != 0x98) { ddelay(30); if ((stv0299_readreg (i2c, 0x1b) & 0x98) != 0x98) { u8 val = stv0299_readreg (i2c, 0x0c); dprintk ("toggle inversion\n"); return stv0299_writereg (i2c, 0x0c, val ^ 0x01); } } return 0;}staticint stv0299_set_FEC (struct dvb_i2c_bus *i2c, fe_code_rate_t fec){ dprintk ("%s\n", __FUNCTION__); switch (fec) { case FEC_AUTO: return stv0299_writereg (i2c, 0x31, 0x1f); case FEC_1_2: return stv0299_writereg (i2c, 0x31, 0x01); case FEC_2_3: return stv0299_writereg (i2c, 0x31, 0x02); case FEC_3_4: return stv0299_writereg (i2c, 0x31, 0x04); case FEC_5_6: return stv0299_writereg (i2c, 0x31, 0x08); case FEC_7_8: return stv0299_writereg (i2c, 0x31, 0x10); default: return -EINVAL; }}staticfe_code_rate_t stv0299_get_fec (struct dvb_i2c_bus *i2c){ static fe_code_rate_t fec_tab [] = { FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, FEC_1_2 }; u8 index; dprintk ("%s\n", __FUNCTION__); index = stv0299_readreg (i2c, 0x1b); index &= 0x7; if (index > 4) return FEC_AUTO; return fec_tab [index];}staticint stv0299_wait_diseqc_fifo (struct dvb_i2c_bus *i2c, int timeout){ unsigned long start = jiffies; dprintk ("%s\n", __FUNCTION__); while (stv0299_readreg(i2c, 0x0a) & 1) { if (jiffies - start > timeout) { dprintk ("%s: timeout!!\n", __FUNCTION__); return -ETIMEDOUT; } ddelay(10); }; return 0;}staticint stv0299_wait_diseqc_idle (struct dvb_i2c_bus *i2c, int timeout)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -