📄 stv0299.c
字号:
/* Driver for ST STV0299 demodulator 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/moduleparam.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/jiffies.h>#include <asm/div64.h>#include "dvb_frontend.h"#include "stv0299.h"struct stv0299_state { struct i2c_adapter* i2c; struct dvb_frontend_ops ops; const struct stv0299_config* config; struct dvb_frontend frontend; u8 initialised:1; u32 tuner_frequency; u32 symbol_rate; fe_code_rate_t fec_inner; int errmode;};#define STATUS_BER 0#define STATUS_UCBLOCKS 1static int debug;static int debug_legacy_dish_switch;#define dprintk(args...) \ do { \ if (debug) printk(KERN_DEBUG "stv0299: " args); \ } while (0)static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data){ int ret; u8 buf [] = { reg, data }; struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; ret = i2c_transfer (state->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) ? -EREMOTEIO : 0;}int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data){ struct stv0299_state* state = fe->demodulator_priv; return stv0299_writeregI(state, reg, data);}static u8 stv0299_readreg (struct stv0299_state* state, u8 reg){ int ret; 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 } }; ret = i2c_transfer (state->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 stv0299_state* state, u8 reg1, u8 *b, u8 len){ int ret; struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = ®1, .len = 1 }, { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } }; ret = i2c_transfer (state->i2c, msg, 2); if (ret != 2) dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); return ret == 2 ? 0 : ret;}static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec){ dprintk ("%s\n", __FUNCTION__); switch (fec) { case FEC_AUTO: { return stv0299_writeregI (state, 0x31, 0x1f); } case FEC_1_2: { return stv0299_writeregI (state, 0x31, 0x01); } case FEC_2_3: { return stv0299_writeregI (state, 0x31, 0x02); } case FEC_3_4: { return stv0299_writeregI (state, 0x31, 0x04); } case FEC_5_6: { return stv0299_writeregI (state, 0x31, 0x08); } case FEC_7_8: { return stv0299_writeregI (state, 0x31, 0x10); } default: { return -EINVAL; } }}static fe_code_rate_t stv0299_get_fec (struct stv0299_state* state){ 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 (state, 0x1b); index &= 0x7; if (index > 4) return FEC_AUTO; return fec_tab [index];}static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout){ unsigned long start = jiffies; dprintk ("%s\n", __FUNCTION__); while (stv0299_readreg(state, 0x0a) & 1) { if (jiffies - start > timeout) { dprintk ("%s: timeout!!\n", __FUNCTION__); return -ETIMEDOUT; } msleep(10); }; return 0;}static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout){ unsigned long start = jiffies; dprintk ("%s\n", __FUNCTION__); while ((stv0299_readreg(state, 0x0a) & 3) != 2 ) { if (jiffies - start > timeout) { dprintk ("%s: timeout!!\n", __FUNCTION__); return -ETIMEDOUT; } msleep(10); }; return 0;}static int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate){ struct stv0299_state* state = fe->demodulator_priv; u64 big = srate; u32 ratio; // check rate is within limits if ((srate < 1000000) || (srate > 45000000)) return -EINVAL; // calculate value to program big = big << 20; big += (state->config->mclk-1); // round correctly do_div(big, state->config->mclk); ratio = big << 4; return state->config->set_symbol_rate(fe, srate, ratio);}static int stv0299_get_symbolrate (struct stv0299_state* state){ u32 Mclk = state->config->mclk / 4096L; u32 srate; s32 offset; u8 sfr[3]; s8 rtf; dprintk ("%s\n", __FUNCTION__); stv0299_readregs (state, 0x1f, sfr, 3); stv0299_readregs (state, 0x1a, &rtf, 1); srate = (sfr[0] << 8) | sfr[1]; srate *= Mclk; srate /= 16; srate += (sfr[2] >> 4) * Mclk / 256; offset = (s32) rtf * (srate / 4096L); offset /= 128; dprintk ("%s : srate = %i\n", __FUNCTION__, srate); dprintk ("%s : ofset = %i\n", __FUNCTION__, offset); srate += offset; srate += 1000; srate /= 2000; srate *= 2000; return srate;}static int stv0299_send_diseqc_msg (struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *m){ struct stv0299_state* state = fe->demodulator_priv; u8 val; int i; dprintk ("%s\n", __FUNCTION__); if (stv0299_wait_diseqc_idle (state, 100) < 0) return -ETIMEDOUT; val = stv0299_readreg (state, 0x08); if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x6)) /* DiSEqC mode */ return -EREMOTEIO; for (i=0; i<m->msg_len; i++) { if (stv0299_wait_diseqc_fifo (state, 100) < 0) return -ETIMEDOUT; if (stv0299_writeregI (state, 0x09, m->msg[i])) return -EREMOTEIO; } if (stv0299_wait_diseqc_idle (state, 100) < 0) return -ETIMEDOUT; return 0;}static int stv0299_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst){ struct stv0299_state* state = fe->demodulator_priv; u8 val; dprintk ("%s\n", __FUNCTION__); if (stv0299_wait_diseqc_idle (state, 100) < 0) return -ETIMEDOUT; val = stv0299_readreg (state, 0x08); if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x2)) /* burst mode */ return -EREMOTEIO; if (stv0299_writeregI (state, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff)) return -EREMOTEIO; if (stv0299_wait_diseqc_idle (state, 100) < 0) return -ETIMEDOUT; if (stv0299_writeregI (state, 0x08, val)) return -EREMOTEIO; return 0;}static int stv0299_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone){ struct stv0299_state* state = fe->demodulator_priv; u8 val; if (stv0299_wait_diseqc_idle (state, 100) < 0) return -ETIMEDOUT; val = stv0299_readreg (state, 0x08); switch (tone) { case SEC_TONE_ON: return stv0299_writeregI (state, 0x08, val | 0x3); case SEC_TONE_OFF: return stv0299_writeregI (state, 0x08, (val & ~0x3) | 0x02); default: return -EINVAL; }}static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage){ struct stv0299_state* state = fe->demodulator_priv; u8 reg0x08; u8 reg0x0c; dprintk("%s: %s\n", __FUNCTION__, voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); reg0x08 = stv0299_readreg (state, 0x08);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -