📄 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 <obi@linuxtv.org> Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B Copyright (C) 2003 Vadim Catana <skystar@moldova.cc>: Support for Philips SU1278 on Technotrend hardware Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.net> 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/init.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/string.h>#include <linux/slab.h>#include <asm/div64.h>#include "dvb_frontend.h"#include "dvb_functions.h"#if 0#define dprintk(x...) printk(x)#else#define dprintk(x...)#endifstatic int stv0299_status = 0;#define STATUS_BER 0#define STATUS_UCBLOCKS 1/* frontend types */#define UNKNOWN_FRONTEND -1#define PHILIPS_SU1278_TSA 0 // SU1278 with TSA5059 synth and datasheet recommended settings#define ALPS_BSRU6 1#define LG_TDQF_S001F 2#define PHILIPS_SU1278_TUA 3 // SU1278 with TUA6100 synth#define SAMSUNG_TBMU24112IMB 4#define PHILIPS_SU1278_TSA_TT 5 // SU1278 with TSA5059 synth and TechnoTrend settings/* Master Clock = 88 MHz */#define M_CLK (88000000UL)/* Master Clock for TT cards = 64 MHz */#define M_CLK_SU1278_TSA_TT (64000000UL)static struct 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_CLEAN_SETUP};struct stv0299_state { u8 tuner_type; u8 initialised:1; u32 tuner_frequency; u32 symbol_rate; fe_code_rate_t fec_inner;};static u8 init_tab [] = { 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, LNB power on OP2/LOCK pin on */ 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 0x15, 0xc9, // lock detector threshold 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1f, 0x50, 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, 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};static u8 init_tab_samsung [] = { 0x01, 0x15, 0x02, 0x00, 0x03, 0x00, 0x04, 0x7D, 0x05, 0x35, 0x06, 0x02, 0x07, 0x00, 0x08, 0xC3, 0x0C, 0x00, 0x0D, 0x81, 0x0E, 0x23, 0x0F, 0x12, 0x10, 0x7E, 0x11, 0x84, 0x12, 0xB9, 0x13, 0x88, 0x14, 0x89, 0x15, 0xC9, 0x16, 0x00, 0x17, 0x5C, 0x18, 0x00, 0x19, 0x00, 0x1A, 0x00, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x00, 0x1F, 0x3A, 0x20, 0x2E, 0x21, 0x80, 0x22, 0xFF, 0x23, 0xC1, 0x28, 0x00, 0x29, 0x1E, 0x2A, 0x14, 0x2B, 0x0F, 0x2C, 0x09, 0x2D, 0x05, 0x31, 0x1F, 0x32, 0x19, 0x33, 0xFE, 0x34, 0x93};static u8 init_tab_su1278_tsa_tt [] = { 0x01, 0x0f, 0x02, 0x30, 0x03, 0x00, 0x04, 0x5b, 0x05, 0x85, 0x06, 0x02, 0x07, 0x00, 0x08, 0x02, 0x09, 0x00, 0x0C, 0x01, 0x0D, 0x81, 0x0E, 0x44, 0x0f, 0x14, 0x10, 0x3c, 0x11, 0x84, 0x12, 0xda, 0x13, 0x97, 0x14, 0x95, 0x15, 0xc9, 0x16, 0x19, 0x17, 0x8c, 0x18, 0x59, 0x19, 0xf8, 0x1a, 0xfe, 0x1c, 0x7f, 0x1d, 0x00, 0x1e, 0x00, 0x1f, 0x50, 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, 0x28, 0x00, 0x29, 0x28, 0x2a, 0x14, 0x2b, 0x0f, 0x2c, 0x09, 0x2d, 0x09, 0x31, 0x1f, 0x32, 0x19, 0x33, 0xfc, 0x34, 0x13};static int stv0299_set_FEC (struct dvb_i2c_bus *i2c, fe_code_rate_t fec);static int stv0299_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate, int tuner_type);static int 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 }; 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;}static u8 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 } }; ret = i2c->xfer (i2c, msg, 2); if (ret != 2) dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); return b1[0];}static int 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 } }; ret = i2c->xfer (i2c, msg, 2); if (ret != 2) dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); return ret == 2 ? 0 : ret;}static int pll_write (struct dvb_i2c_bus *i2c, u8 addr, u8 *data, int len){ int ret; struct i2c_msg msg = { addr: addr, .flags = 0, .buf = data, .len = len }; stv0299_writereg(i2c, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ ret = i2c->xfer (i2c, &msg, 1); stv0299_writereg(i2c, 0x05, 0x35); /* disable i2c repeater on stv0299 */ if (ret != 1) dprintk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret); return (ret != 1) ? -1 : 0;}static int sl1935_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype){ u8 buf[4]; u32 div; div = freq / 125; dprintk("%s : freq = %i, div = %i\n", __FUNCTION__, freq, div); buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0x84; // 0xC4 buf[3] = 0x08; if (freq < 1500000) buf[3] |= 0x10; return pll_write (i2c, 0x61, buf, sizeof(buf));}/** * set up the downconverter frequency divisor for a * reference clock comparision frequency of 125 kHz. */static int tsa5059_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype, int srate){ u8 addr; u32 div; u8 buf[4]; int divisor, regcode; dprintk ("%s: freq %i, ftype %i\n", __FUNCTION__, freq, ftype); if ((freq < 950000) || (freq > 2150000)) return -EINVAL; divisor = 500; regcode = 2; // setup frequency divisor div = (freq + (divisor - 1)) / divisor; // round correctly buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0x80 | ((div & 0x18000) >> 10) | regcode; buf[3] = 0; // tuner-specific settings switch(ftype) { case PHILIPS_SU1278_TSA: case PHILIPS_SU1278_TSA_TT: addr = 0x60; buf[3] |= 0x20; if (srate < 4000000) buf[3] |= 1; if (freq < 1250000) buf[3] |= 0; else if (freq < 1550000) buf[3] |= 0x40; else if (freq < 2050000) buf[3] |= 0x80; else if (freq < 2150000) buf[3] |= 0xC0; break; case ALPS_BSRU6: addr = 0x61; buf[3] |= 0xC0; break; default: return -EINVAL; } return pll_write (i2c, addr, buf, sizeof(buf));}#define ABS(x) ((x) < 0 ? -(x) : (x))#define MIN2(a,b) ((a) < (b) ? (a) : (b))#define MIN3(a,b,c) MIN2(MIN2(a,b),c)static int tua6100_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype, int srate){ u8 reg0 [2] = { 0x00, 0x00 }; u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 }; u8 reg2 [3] = { 0x02, 0x00, 0x00 }; int _fband; int first_ZF; int R, A, N, P, M; int err; first_ZF = (freq) / 1000; if (ABS(MIN2(ABS(first_ZF-1190),ABS(first_ZF-1790))) < ABS(MIN3(ABS(first_ZF-1202),ABS(first_ZF-1542),ABS(first_ZF-1890)))) _fband = 2; else _fband = 3; if (_fband == 2) { if (((first_ZF >= 950) && (first_ZF < 1350)) || ((first_ZF >= 1430) && (first_ZF < 1950))) reg0[1] = 0x07; else if (((first_ZF >= 1350) && (first_ZF < 1430)) || ((first_ZF >= 1950) && (first_ZF < 2150))) reg0[1] = 0x0B; } if(_fband == 3) { if (((first_ZF >= 950) && (first_ZF < 1350)) || ((first_ZF >= 1455) && (first_ZF < 1950))) reg0[1] = 0x07;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -