⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stv0297.c

📁 STV0297的QAM解码芯片的 Linux 驱动程序
💻 C
字号:
/*    Driver for STV0297/TSA5512 based DVB QAM frontends    Copyright (C) 2003 Dennis N鰎mann <dennis.noermann@noernet.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/init.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/string.h>#include <linux/delay.h>#include "dvb_frontend.h"#include "dvb_functions.h"#if 1#define dprintk(x...) printk(x)#else#define dprintk(x...)#endifstatic struct dvb_frontend_info stv0297_info = {	.name			= "STV0297/TSA5512 based DVB-C frontend",	.type			= FE_QAM,	.frequency_min		= 64000000,	.frequency_max		= 1300000000,	.frequency_stepsize	= 62500,	.symbol_rate_min	= 870000,	.symbol_rate_max	= 11700000,#if 0	.frequency_tolerance	= ???,	.symbol_rate_tolerance	= ???,	.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 |		FE_CAN_CLEAN_SETUP | FE_CAN_RECOVER };static u8 init_tab [] = {	0x80, 0x01, /* soft_reset */	0x80, 0x00, /* cleared soft_reset */	0x81, 0x01, /* deinterleaver descrambler reset */	0x81, 0x00, /* cleared deinterleaver descrambler reset */	0x83, 0x10, /* the Reed-Solomon block reset*/ 	0x83, 0x00, /* cleared the Reed-Solomon block reset */	0x84, 0x2b, /* clears the equalizer and also reinitializes the Reg. 00through 04. */	0x84, 0x2a, /* cleares it .. */	0x03, 0x00,	0x25, 0x88,	0x30, 0x97, 	0x31, 0x4C,	0x32, 0xFF,	0x33, 0x55,	0x34, 0x00,	0x35, 0x65,	0x36, 0x80,	0x40, 0x1C, 	0x42, 0x3C, 	0x43, 0x00,	0x52, 0x28,	0x5A, 0x1E,	0x5B, 0x05,	0x62, 0x06, 	0x6A, 0x02, 	0x70, 0xFF,	0x71, 0x84,	0x83, 0x10, 	0x84, 0x25,	0x85, 0x00,	0x86, 0x78,	0x87, 0x73,	0x88, 0x08,	0x89, 0x00,	0x90, 0x05,	0xA0, 0x00,	0xB0, 0x91,	0xB1, 0x0B, 	0xC0, 0x4B,	0xC1, 0x01,	0xC2, 0x00,	0xDE, 0x00,	0xDF, 0x03,	0x87, 0x73};static int stv0297_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data){	int ret;	u8 buf [] = { reg, data };	struct i2c_msg msg = { .addr = 0x1C, .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 int stv0297_writeregs (struct dvb_i2c_bus *i2c, u8 *data, int len){        int ret;        struct i2c_msg msg = { .addr = 0x1C , .flags = 0, .buf = data, .len = len };                ret = i2c->xfer (i2c, &msg, 1);                        if (ret != 1)                dprintk("%s: writeregs error\n ", __FUNCTION__);        return (ret != 1) ? -1 : 0;}static u8 stv0297_readreg (struct dvb_i2c_bus *i2c, u8 reg){        int ret;        u8 b0[] = { reg };        u8 b1[] = { 0 };        struct i2c_msg msg1[] = { {.addr =  0x38 >> 1, .flags =  0, .buf =  b0, .len = 1} };        struct i2c_msg msg2[] = { {.addr =  0x38 >> 1, .flags = I2C_M_RD, .buf =  b1, .len = 1} };        ret = i2c->xfer(i2c, msg1, 1);        if (ret != 1)                dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);	ret = i2c->xfer(i2c, msg2, 1);        if (ret != 1)                dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);        return b1[0];}static int stv0297_readregs (struct dvb_i2c_bus *i2c, u8 reg1, u8 *b, u8 len){        int ret;        struct i2c_msg msg1[] = { { .addr = 0x38 >> 1, .flags = 0, .buf = &reg1, .len = 1 } };        struct i2c_msg msg2[] = { { .addr = 0x38 >> 1, .flags = I2C_M_RD, .buf = b, .len = len } };        ret = i2c->xfer (i2c, msg1, 1);        if (ret != 1)                dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);        ret = i2c->xfer(i2c, msg2, 1);                if (ret != 1)                dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);        return ret == 1 ? 0 : ret;}static int pll_write (struct dvb_i2c_bus *i2c, u8 *data, int len){	int ret;	stv0297_writereg (i2c, 0x86, 0xF8);		struct i2c_msg msg = { .addr = 0xC0 >> 1, .flags = 0, .buf = data, .len = len };        ret = i2c->xfer (i2c, &msg, 1);        if (ret != 1)                  printk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret);	return (ret != 1) ? -1 : 0;}static int tsa5512_set_tv_freq	(struct dvb_i2c_bus *i2c, u32 freq){	u8 buf[4];	u32 div, ifreq;        ifreq = 36125000;         div = (freq + ifreq + 31250) / 62500;	buf[0] = (div >> 8) & 0x7f;	buf[1] = div & 0xff;	buf[2] = 0xCE; 	if (freq < 166000000)		buf[3] = 0xA2; // 41 Mhz bis 166 Mhz 	else		buf[3] = 0x92; // 166 Mhz bis 451 Mhz 	dprintk("%s:  div = %d 0 == 0x%02x, 1 == 0x%02x 3 == 0x%02x \n",__FUNCTION__,div,buf[0],buf[1],buf[3]);	pll_write (i2c, buf, sizeof(buf));	return 0;}static int tsa5512_read_status	(struct dvb_i2c_bus *i2c){	int ret;	u8 stat [] = { 0 };	stv0297_writereg (i2c, 0x86, 0xF8);	struct i2c_msg msg [] = {{ .addr = 0xC0 >> 1, .flags = I2C_M_RD, .buf = stat, .len = 1 }};	ret = i2c->xfer (i2c, msg, 1);	if (ret != 1)		dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);	return stat[0];}static int stv0297_init (struct dvb_i2c_bus *i2c){	int i;	dprintk("stv0297: init chip\n");	for (i=0; i<sizeof(init_tab); i+=2) {		stv0297_writereg (i2c, init_tab[i], init_tab[i+1]);		}	return 0;}/*static int stv0297_check_inversion (struct dvb_i2c_bus *i2c){	return 0;}*/static int stv0297_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate)  // DONE {/*	u32 clock;	u32 rate;	u32 drate;	u8 buf[4];	drate = srate * 2 * 2 * 2 * 2 *2 * 2 *2 *2;	clock = 28800000 ;			rate = drate / clock ;	rate = rate << 24;	dprintk("symbolrate %d clock %d drate %d srate %d\n",rate,clock,drate,srate);		        buf[0] = (rate >> 24) ;        buf[1] = (rate >> 16) ;        buf[2] = (rate >> 8) ;        buf[3] = rate ;	dprintk(" 0x%02x 0x%02x 0x%02x 0x%02x \n", buf[0], buf[1], buf[2], buf[3]);				fix me , hardcoded to 6900000 ...*/	stv0297_writereg (i2c, 0x55, 0x4E);	stv0297_writereg (i2c, 0x56, 0x00);	stv0297_writereg (i2c, 0x57, 0x1F);	stv0297_writereg (i2c, 0x58, 0x3D);	return 0;}static int stv0297_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg){	struct dvb_i2c_bus *i2c = fe->i2c;	switch (cmd) {	case FE_GET_INFO: 		memcpy (arg, &stv0297_info, sizeof(struct dvb_frontend_info));		break;	case FE_READ_STATUS: 	{		fe_status_t *status = (fe_status_t *) arg;		u8 tuner = tsa5512_read_status(i2c);				u8 sync = stv0297_readreg (i2c, 0xDF);				*status = 0;		if (sync & 0x80)			*status |= FE_HAS_SYNC;		if (tuner & 50) 			*status |= FE_HAS_SIGNAL;		if (sync & 0x80)			*status |= FE_HAS_CARRIER; 		if (sync & 0x80)			*status |= FE_HAS_VITERBI;		if (sync & 0x80)			*status |= FE_HAS_LOCK;		break;	}        case FE_READ_BER:  	{		u32 ber;		u8 BER[3];		stv0297_writereg (i2c, 0xA0, 0x80);	// Start Counting bit errors for 4096 Bytes 				udelay(25000);				// Hopefully got 4096 Bytes 		stv0297_readregs (i2c, 0xA0, BER, 3);		udelay(25000);		ber = (BER[2] << 8 | BER[1]) / ( 8 * 4096);		*((u32*) arg) = ber;		break;	}	case FE_READ_SIGNAL_STRENGTH:	{		u16 strength;		u8 STRENGTH[2];		udelay(25000);		stv0297_readregs (i2c, 0x41, STRENGTH, 2);		strength = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0];		*((u16*) arg) = strength;		break;	}        case FE_READ_SNR:	{		u16 snr;		u8 SNR[2];		udelay(25000);		stv0297_readregs (i2c, 0x07, SNR, 2);		snr = SNR[1] << 8 | SNR[0];		*((u16*) arg) = snr;		break;	}	case FE_READ_UNCORRECTED_BLOCKS:         {                *((u16*) arg) = (stv0297_readreg (i2c, 0xD5) << 8)                               | stv0297_readreg (i2c, 0xD4);                break;        }        case FE_SET_FRONTEND:         {		struct dvb_frontend_parameters *p = arg;		u8 buf[] = { 0x30, 0x97, 0x4C, 0xFF, 0x55, 0x00, 0x65, 0x80 };		u8 buf2[] = { 0x83, 0x10, 0x25, 0x00, 0x78, 0x73 };		u8 buf3[] = { 0xC0, 0x4B, 0x01, 0x00 };		u8 buf4[] = { 0x66, 0xB9, 0x1E, 0x85, 0x0F };		u8 pll[] = { 0x8E };				stv0297_writereg (i2c, 0x80, 0x01);		stv0297_writereg (i2c, 0x80, 0x00);                stv0297_writereg (i2c, 0x87, 0x73);		tsa5512_set_tv_freq (i2c, p->frequency);		/*  wait till tuner has tuned ?? */		stv0297_writereg (i2c, 0x87, 0x73);		pll_write (i2c, pll, sizeof(pll));                stv0297_writereg (i2c, 0x80, 0x01); //udelay(1000);                stv0297_writereg (i2c, 0x80, 0x00); //udelay(1000);                stv0297_writereg (i2c, 0x25, 0x88); //udelay(1000);		stv0297_writeregs (i2c, buf, sizeof(buf)); //udelay(1000);                stv0297_writereg (i2c, 0x43, 0x00); //udelay(1000);                stv0297_writereg (i2c, 0x70, 0xFF); //udelay(1000);                stv0297_writereg (i2c, 0x71, 0x84); //udelay(1000);		stv0297_writereg (i2c, 0x81, 0x01); //udelay(3000);		stv0297_writereg (i2c, 0x85, 0x04); //udelay(3000);		stv0297_writereg (i2c, 0x81, 0x00); //udelay(1000);		stv0297_writeregs (i2c, buf2, sizeof(buf2)); //udelay(1000);		stv0297_writereg (i2c, 0x84, 0x24); //udelay(1000);		stv0297_writeregs (i2c, buf3, sizeof(buf3)); //udelay(1000);		stv0297_writereg (i2c, 0x88, 0x08); //udelay(1000);		stv0297_writereg (i2c, 0x90, 0x01); //udelay(1000);		stv0297_writereg (i2c, 0x37, 0x20); //udelay(1000);				stv0297_writereg (i2c, 0x40, 0x19); //udelay(1000);				stv0297_writereg (i2c, 0x43, 0x40); //udelay(1000);		stv0297_writereg (i2c, 0x41, 0xE4); //udelay(1000);		stv0297_writereg (i2c, 0x42, 0x3C); //udelay(1000);		stv0297_writereg (i2c, 0x44, 0xFF); //udelay(1000);		stv0297_writereg (i2c, 0x49, 0x04); //udelay(1000);		stv0297_writereg (i2c, 0x4A, 0xFF); //udelay(1000);		stv0297_writereg (i2c, 0x4B, 0xFF); //udelay(1000);		stv0297_writereg (i2c, 0x71, 0x04); //udelay(1000);		stv0297_writereg (i2c, 0x53, 0x08); //udelay(1000);		stv0297_writereg (i2c, 0x5A, 0x3E); //udelay(1000); //3E forces the direct path to be immediately 		stv0297_writereg (i2c, 0x5B, 0x07); //udelay(1000);		stv0297_writereg (i2c, 0x5B, 0x05); //udelay(1000);                stv0297_set_symbolrate (i2c, p->u.qam.symbol_rate); //udelay(10000);		stv0297_writereg (i2c, 0x59, 0x08); //udelay(1000);		stv0297_writereg (i2c, 0x61, 0x49); //udelay(1000);		stv0297_writereg (i2c, 0x62, 0x0E); //udelay(1000);		stv0297_writereg (i2c, 0x6A, 0x02); //udelay(1000);		stv0297_writereg (i2c, 0x00, 0x48); //udelay(1000); // set qam-64		//stv0297_writereg (i2c, 0x89, 0xFE); udelay(100000); // qam auto 		stv0297_writereg (i2c, 0x01, 0x58); //udelay(1000);		stv0297_writereg (i2c, 0x82, 0x00); //udelay(1000);		stv0297_writereg (i2c, 0x83, 0x08); //udelay(1000);		stv0297_writereg (i2c, 0x60, 0x2D); //udelay(1000);		stv0297_writereg (i2c, 0x20, 0x00); //udelay(1000);		stv0297_writereg (i2c, 0x21, 0x40); //udelay(1000);		stv0297_writeregs (i2c, buf4, sizeof(buf4)); //udelay(1000);		stv0297_writereg (i2c, 0x82, 0x00); //udelay(5000);		stv0297_writereg (i2c, 0x85, 0x04); //udelay(5000);		stv0297_writereg (i2c, 0x43, 0x10); //udelay(5000);		stv0297_writereg (i2c, 0x5A, 0x5E); //udelay(80000);		stv0297_writereg (i2c, 0x6A, 0x03); //udelay(80000);				stv0297_writereg (i2c, 0x85, 0x04); 		stv0297_writereg (i2c, 0x6B, 0x00); 		stv0297_writereg (i2c, 0x4A, 0xFF); 		stv0297_writereg (i2c, 0x61, 0x49); 		stv0297_writereg (i2c, 0x62, 0x0E);                 stv0297_writereg (i2c, 0xDF, 0x02);		stv0297_writereg (i2c, 0xDF, 0x01);                stv0297_writereg (i2c, 0xDF, 0x02);		stv0297_writereg (i2c, 0xDF, 0x01);						stv0297_writereg (i2c, 0xDF, 0x02); 		stv0297_writereg (i2c, 0xDF, 0x01);                 break;        }        case FE_GET_FRONTEND:        {                break;        }        case FE_SLEEP:		break;        case FE_INIT:		return stv0297_init (i2c);	default:		return -EOPNOTSUPP;	};	return 0;}static int stv0297_attach (struct dvb_i2c_bus *i2c, void **data){	return dvb_register_frontend (stv0297_ioctl, i2c, NULL, &stv0297_info);}static void stv0297_detach (struct dvb_i2c_bus *i2c, void *data){	dprintk ("%s\n", __FUNCTION__);	dvb_unregister_frontend (stv0297_ioctl, i2c);}static int __init init_stv0297 (void){	dprintk ("%s\n", __FUNCTION__);	return dvb_register_i2c_device (NULL, stv0297_attach, stv0297_detach);}static void __exit exit_stv0297 (void){	dprintk ("%s\n", __FUNCTION__);	dvb_unregister_i2c_device (stv0297_attach);}module_init (init_stv0297);module_exit (exit_stv0297);MODULE_DESCRIPTION("STV0299/TSA5512 DVB-C Frontend driver");MODULE_AUTHOR("Dennis N?rmann");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -