📄 ves1820.c
字号:
/* VES1820 - 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> 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 "dvb_functions.h"#if 0#define dprintk(x...) printk(x)#else#define dprintk(x...)#endif#define MAX_UNITS 4static int pwm[MAX_UNITS] = { -1, -1, -1, -1 };static int verbose;/** * since we need only a few bits to store internal state we don't allocate * extra memory but use frontend->data as bitfield */#define SET_PWM(data,pwm) do { \ long d = (long)data; \ d &= ~0xff; \ d |= pwm; \ data = (void *)d; \} while (0)#define SET_REG0(data,reg0) do { \ long d = (long)data; \ d &= ~(0xff << 8); \ d |= reg0 << 8; \ data = (void *)d; \} while (0)#define SET_TUNER(data,type) do { \ long d = (long)data; \ d &= ~(0xff << 16); \ d |= type << 16; \ data = (void *)d; \} while (0)#define SET_DEMOD_ADDR(data,type) do { \ long d = (long)data; \ d &= ~(0xff << 24); \ d |= type << 24; \ data = (void *)d; \} while (0)#define GET_PWM(data) ((u8) ((long) data & 0xff))#define GET_REG0(data) ((u8) (((long) data >> 8) & 0xff))#define GET_TUNER(data) ((u8) (((long) data >> 16) & 0xff))#define GET_DEMOD_ADDR(data) ((u8) (((long) data >> 24) & 0xff))#if defined(CONFIG_DBOX2)#define XIN 69600000UL#define DISABLE_INVERSION(reg0) do { reg0 &= ~0x20; } while (0)#define ENABLE_INVERSION(reg0) do { reg0 |= 0x20; } while (0)#define HAS_INVERSION(reg0) (reg0 & 0x20)#else /* PCI cards */#define XIN 57840000UL#define DISABLE_INVERSION(reg0) do { reg0 |= 0x20; } while (0)#define ENABLE_INVERSION(reg0) do { reg0 &= ~0x20; } while (0)#define HAS_INVERSION(reg0) (!(reg0 & 0x20))#endif#define FIN (XIN >> 4)static struct dvb_frontend_info ves1820_info = { .name = "VES1820 based DVB-C frontend", .type = FE_QAM, .frequency_stepsize = 62500, .frequency_min = 51000000, .frequency_max = 858000000, .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */ .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */#if 0 .frequency_tolerance = ???, .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */ .notifier_delay = ?,#endif .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO,};static u8 ves1820_inittab [] ={ 0x69, 0x6A, 0x9B, 0x12, 0x12, 0x46, 0x26, 0x1A, 0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x20, 0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40};static int ves1820_writereg (struct dvb_frontend *fe, u8 reg, u8 data){ u8 addr = GET_DEMOD_ADDR(fe->data); u8 buf[] = { 0x00, reg, data }; struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 }; struct dvb_i2c_bus *i2c = fe->i2c; int ret; ret = i2c->xfer (i2c, &msg, 1); if (ret != 1) printk("DVB: VES1820(%d): %s, writereg error " "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", fe->i2c->adapter->num, __FUNCTION__, reg, data, ret); dvb_delay(10); return (ret != 1) ? -EREMOTEIO : 0;}static u8 ves1820_readreg (struct dvb_frontend *fe, u8 reg){ u8 b0 [] = { 0x00, reg }; u8 b1 [] = { 0 }; u8 addr = GET_DEMOD_ADDR(fe->data); struct i2c_msg msg [] = { { .addr = addr, .flags = 0, .buf = b0, .len = 2 }, { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; struct dvb_i2c_bus *i2c = fe->i2c; int ret; ret = i2c->xfer (i2c, msg, 2); if (ret != 2) printk("DVB: VES1820(%d): %s: readreg error (ret == %i)\n", fe->i2c->adapter->num, __FUNCTION__, ret); return b1[0];}static int tuner_write (struct dvb_i2c_bus *i2c, u8 addr, u8 data [4]){ int ret; struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 }; ret = i2c->xfer (i2c, &msg, 1); if (ret != 1) printk("DVB: VES1820(%d): %s: i/o error (ret == %i)\n", i2c->adapter->num, __FUNCTION__, ret); return (ret != 1) ? -EREMOTEIO : 0;}/** * set up the downconverter frequency divisor for a * reference clock comparision frequency of 62.5 kHz. */static int tuner_set_tv_freq (struct dvb_frontend *fe, u32 freq){ u32 div, ifreq; static u8 addr [] = { 0x61, 0x62 }; static u8 byte3 [] = { 0x8e, 0x85 }; int tuner_type = GET_TUNER(fe->data); u8 buf [4]; if (tuner_type == 0xff) /* PLL not reachable over i2c ... */ return 0; if (strstr (fe->i2c->adapter->name, "Technotrend") || strstr (fe->i2c->adapter->name, "TT-Budget")) ifreq = 35937500; else ifreq = 36125000; div = (freq + ifreq + 31250) / 62500; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = byte3[tuner_type]; if (tuner_type == 1) { buf[2] |= (div >> 10) & 0x60; buf[3] = (freq < 174000000 ? 0x88 : freq < 470000000 ? 0x84 : 0x81); } else { buf[3] = (freq < 174000000 ? 0xa1 : freq < 454000000 ? 0x92 : 0x34); } return tuner_write (fe->i2c, addr[tuner_type], buf);}static int ves1820_setup_reg0 (struct dvb_frontend *fe, u8 reg0, fe_spectral_inversion_t inversion){ reg0 |= GET_REG0(fe->data) & 0x62; if (INVERSION_ON == inversion) ENABLE_INVERSION(reg0); else if (INVERSION_OFF == inversion) DISABLE_INVERSION(reg0); ves1820_writereg (fe, 0x00, reg0 & 0xfe); ves1820_writereg (fe, 0x00, reg0 | 0x01); /** * check lock and toggle inversion bit if required... */ if (INVERSION_AUTO == inversion && !(ves1820_readreg (fe, 0x11) & 0x08)) { mdelay(50); if (!(ves1820_readreg (fe, 0x11) & 0x08)) { reg0 ^= 0x20; ves1820_writereg (fe, 0x00, reg0 & 0xfe); ves1820_writereg (fe, 0x00, reg0 | 0x01); } } SET_REG0(fe->data, reg0); return 0;}static int ves1820_init (struct dvb_frontend *fe){ int i; dprintk("DVB: VES1820(%d): init chip\n", fe->i2c->adapter->num); ves1820_writereg (fe, 0, 0);#if defined(CONFIG_DBOX2) ves1820_inittab[2] &= ~0x08;#endif for (i=0; i<53; i++) ves1820_writereg (fe, i, ves1820_inittab[i]); ves1820_writereg (fe, 0x34, GET_PWM(fe->data)); return 0;}static int ves1820_set_symbolrate (struct dvb_frontend *fe, u32 symbolrate){ s32 BDR; s32 BDRI; s16 SFIL=0; u16 NDEC = 0; u32 tmp, ratio; 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -