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

📄 tda10048.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    NXP TDA10048HN DVB OFDM demodulator driver    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>    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/kernel.h>#include <linux/init.h>#include <linux/module.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/delay.h>#include "dvb_frontend.h"#include "dvb_math.h"#include "tda10048.h"#define TDA10048_DEFAULT_FIRMWARE "dvb-fe-tda10048-1.0.fw"#define TDA10048_DEFAULT_FIRMWARE_SIZE 24878/* Register name definitions */#define TDA10048_IDENTITY          0x00#define TDA10048_VERSION           0x01#define TDA10048_DSP_CODE_CPT      0x0C#define TDA10048_DSP_CODE_IN       0x0E#define TDA10048_IN_CONF1          0x10#define TDA10048_IN_CONF2          0x11#define TDA10048_IN_CONF3          0x12#define TDA10048_OUT_CONF1         0x14#define TDA10048_OUT_CONF2         0x15#define TDA10048_OUT_CONF3         0x16#define TDA10048_AUTO              0x18#define TDA10048_SYNC_STATUS       0x1A#define TDA10048_CONF_C4_1         0x1E#define TDA10048_CONF_C4_2         0x1F#define TDA10048_CODE_IN_RAM       0x20#define TDA10048_CHANNEL_INFO_1_R  0x22#define TDA10048_CHANNEL_INFO_2_R  0x23#define TDA10048_CHANNEL_INFO1     0x24#define TDA10048_CHANNEL_INFO2     0x25#define TDA10048_TIME_ERROR_R      0x26#define TDA10048_TIME_ERROR        0x27#define TDA10048_FREQ_ERROR_LSB_R  0x28#define TDA10048_FREQ_ERROR_MSB_R  0x29#define TDA10048_FREQ_ERROR_LSB    0x2A#define TDA10048_FREQ_ERROR_MSB    0x2B#define TDA10048_IT_SEL            0x30#define TDA10048_IT_STAT           0x32#define TDA10048_DSP_AD_LSB        0x3C#define TDA10048_DSP_AD_MSB        0x3D#define TDA10048_DSP_REF_LSB       0x3E#define TDA10048_DSP_REF_MSB       0x3F#define TDA10048_CONF_TRISTATE1    0x44#define TDA10048_CONF_TRISTATE2    0x45#define TDA10048_CONF_POLARITY     0x46#define TDA10048_GPIO_SP_DS0       0x48#define TDA10048_GPIO_SP_DS1       0x49#define TDA10048_GPIO_SP_DS2       0x4A#define TDA10048_GPIO_SP_DS3       0x4B#define TDA10048_GPIO_OUT_SEL      0x4C#define TDA10048_GPIO_SELECT       0x4D#define TDA10048_IC_MODE           0x4E#define TDA10048_CONF_XO           0x50#define TDA10048_CONF_PLL1         0x51#define TDA10048_CONF_PLL2         0x52#define TDA10048_CONF_PLL3         0x53#define TDA10048_CONF_ADC          0x54#define TDA10048_CONF_ADC_2        0x55#define TDA10048_CONF_C1_1         0x60#define TDA10048_CONF_C1_3         0x62#define TDA10048_AGC_CONF          0x70#define TDA10048_AGC_THRESHOLD_LSB 0x72#define TDA10048_AGC_THRESHOLD_MSB 0x73#define TDA10048_AGC_RENORM        0x74#define TDA10048_AGC_GAINS         0x76#define TDA10048_AGC_TUN_MIN       0x78#define TDA10048_AGC_TUN_MAX       0x79#define TDA10048_AGC_IF_MIN        0x7A#define TDA10048_AGC_IF_MAX        0x7B#define TDA10048_AGC_TUN_LEVEL     0x7E#define TDA10048_AGC_IF_LEVEL      0x7F#define TDA10048_DIG_AGC_LEVEL     0x81#define TDA10048_FREQ_PHY2_LSB     0x86#define TDA10048_FREQ_PHY2_MSB     0x87#define TDA10048_TIME_INVWREF_LSB  0x88#define TDA10048_TIME_INVWREF_MSB  0x89#define TDA10048_TIME_WREF_LSB     0x8A#define TDA10048_TIME_WREF_MID1    0x8B#define TDA10048_TIME_WREF_MID2    0x8C#define TDA10048_TIME_WREF_MSB     0x8D#define TDA10048_NP_OUT            0xA2#define TDA10048_CELL_ID_LSB       0xA4#define TDA10048_CELL_ID_MSB       0xA5#define TDA10048_EXTTPS_ODD        0xAA#define TDA10048_EXTTPS_EVEN       0xAB#define TDA10048_TPS_LENGTH        0xAC#define TDA10048_FREE_REG_1        0xB2#define TDA10048_FREE_REG_2        0xB3#define TDA10048_CONF_C3_1         0xC0#define TDA10048_CYBER_CTRL        0xC2#define TDA10048_CBER_NMAX_LSB     0xC4#define TDA10048_CBER_NMAX_MSB     0xC5#define TDA10048_CBER_LSB          0xC6#define TDA10048_CBER_MSB          0xC7#define TDA10048_VBER_LSB          0xC8#define TDA10048_VBER_MID          0xC9#define TDA10048_VBER_MSB          0xCA#define TDA10048_CYBER_LUT         0xCC#define TDA10048_UNCOR_CTRL        0xCD#define TDA10048_UNCOR_CPT_LSB     0xCE#define TDA10048_UNCOR_CPT_MSB     0xCF#define TDA10048_SOFT_IT_C3        0xD6#define TDA10048_CONF_TS2          0xE0#define TDA10048_CONF_TS1          0xE1static unsigned int debug;#define dprintk(level, fmt, arg...)\	do { if (debug >= level)\		printk(KERN_DEBUG "tda10048: " fmt, ## arg);\	} while (0)struct tda10048_state {	struct i2c_adapter *i2c;	/* configuration settings */	const struct tda10048_config *config;	struct dvb_frontend frontend;	int fwloaded;};static struct init_tab {	u8	reg;	u16	data;} init_tab[] = {	{ TDA10048_CONF_PLL1, 0x08 },	{ TDA10048_CONF_ADC_2, 0x00 },	{ TDA10048_CONF_C4_1, 0x00 },	{ TDA10048_CONF_PLL1, 0x0f },	{ TDA10048_CONF_PLL2, 0x0a },	{ TDA10048_CONF_PLL3, 0x43 },	{ TDA10048_FREQ_PHY2_LSB, 0x02 },	{ TDA10048_FREQ_PHY2_MSB, 0x0a },	{ TDA10048_TIME_WREF_LSB, 0xbd },	{ TDA10048_TIME_WREF_MID1, 0xe4 },	{ TDA10048_TIME_WREF_MID2, 0xa8 },	{ TDA10048_TIME_WREF_MSB, 0x02 },	{ TDA10048_TIME_INVWREF_LSB, 0x04 },	{ TDA10048_TIME_INVWREF_MSB, 0x06 },	{ TDA10048_CONF_C4_1, 0x00 },	{ TDA10048_CONF_C1_1, 0xa8 },	{ TDA10048_AGC_CONF, 0x16 },	{ TDA10048_CONF_C1_3, 0x0b },	{ TDA10048_AGC_TUN_MIN, 0x00 },	{ TDA10048_AGC_TUN_MAX, 0xff },	{ TDA10048_AGC_IF_MIN, 0x00 },	{ TDA10048_AGC_IF_MAX, 0xff },	{ TDA10048_AGC_THRESHOLD_MSB, 0x00 },	{ TDA10048_AGC_THRESHOLD_LSB, 0x70 },	{ TDA10048_CYBER_CTRL, 0x38 },	{ TDA10048_AGC_GAINS, 0x12 },	{ TDA10048_CONF_XO, 0x00 },	{ TDA10048_CONF_TS1, 0x07 },	{ TDA10048_IC_MODE, 0x00 },	{ TDA10048_CONF_TS2, 0xc0 },	{ TDA10048_CONF_TRISTATE1, 0x21 },	{ TDA10048_CONF_TRISTATE2, 0x00 },	{ TDA10048_CONF_POLARITY, 0x00 },	{ TDA10048_CONF_C4_2, 0x04 },	{ TDA10048_CONF_ADC, 0x60 },	{ TDA10048_CONF_ADC_2, 0x10 },	{ TDA10048_CONF_ADC, 0x60 },	{ TDA10048_CONF_ADC_2, 0x00 },	{ TDA10048_CONF_C1_1, 0xa8 },	{ TDA10048_UNCOR_CTRL, 0x00 },	{ TDA10048_CONF_C4_2, 0x04 },};static int tda10048_writereg(struct tda10048_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 };	dprintk(2, "%s(reg = 0x%02x, data = 0x%02x)\n", __func__, reg, data);	ret = i2c_transfer(state->i2c, &msg, 1);	if (ret != 1)		printk("%s: writereg error (ret == %i)\n", __func__, ret);	return (ret != 1) ? -1 : 0;}static u8 tda10048_readreg(struct tda10048_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 } };	dprintk(2, "%s(reg = 0x%02x)\n", __func__, reg);	ret = i2c_transfer(state->i2c, msg, 2);	if (ret != 2)		printk(KERN_ERR "%s: readreg error (ret == %i)\n",			__func__, ret);	return b1[0];}static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg,				 const u8 *data, u16 len){	int ret = -EREMOTEIO;	struct i2c_msg msg;	u8 *buf;	dprintk(2, "%s(%d, ?, len = %d)\n", __func__, reg, len);	buf = kmalloc(len + 1, GFP_KERNEL);	if (buf == NULL) {		ret = -ENOMEM;		goto error;	}	*buf = reg;	memcpy(buf + 1, data, len);	msg.addr = state->config->demod_address;	msg.flags = 0;	msg.buf = buf;	msg.len = len + 1;	dprintk(2, "%s():  write len = %d\n",		__func__, msg.len);	ret = i2c_transfer(state->i2c, &msg, 1);	if (ret != 1) {		printk(KERN_ERR "%s(): writereg error err %i\n",			 __func__, ret);		ret = -EREMOTEIO;	}error:	kfree(buf);	return ret;}static int tda10048_firmware_upload(struct dvb_frontend *fe){	struct tda10048_state *state = fe->demodulator_priv;	const struct firmware *fw;	int ret;	int pos = 0;	int cnt;	u8 wlen = state->config->fwbulkwritelen;	if ((wlen != TDA10048_BULKWRITE_200) && (wlen != TDA10048_BULKWRITE_50))		wlen = TDA10048_BULKWRITE_200;	/* request the firmware, this will block and timeout */	printk(KERN_INFO "%s: waiting for firmware upload (%s)...\n",		__func__,		TDA10048_DEFAULT_FIRMWARE);	ret = request_firmware(&fw, TDA10048_DEFAULT_FIRMWARE,		&state->i2c->dev);	if (ret) {		printk(KERN_ERR "%s: Upload failed. (file not found?)\n",			__func__);		return -EIO;	} else {		printk(KERN_INFO "%s: firmware read %Zu bytes.\n",			__func__,			fw->size);		ret = 0;	}	if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) {		printk(KERN_ERR "%s: firmware incorrect size\n", __func__);		ret = -EIO;	} else {		printk(KERN_INFO "%s: firmware uploading\n", __func__);		/* Soft reset */		tda10048_writereg(state, TDA10048_CONF_TRISTATE1,			tda10048_readreg(state, TDA10048_CONF_TRISTATE1)				& 0xfe);		tda10048_writereg(state, TDA10048_CONF_TRISTATE1,			tda10048_readreg(state, TDA10048_CONF_TRISTATE1)				| 0x01);		/* Put the demod into host download mode */		tda10048_writereg(state, TDA10048_CONF_C4_1,			tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xf9);		/* Boot the DSP */		tda10048_writereg(state, TDA10048_CONF_C4_1,			tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x08);		/* Prepare for download */		tda10048_writereg(state, TDA10048_DSP_CODE_CPT, 0);		/* Download the firmware payload */		while (pos < fw->size) {			if ((fw->size - pos) > wlen)				cnt = wlen;			else				cnt = fw->size - pos;			tda10048_writeregbulk(state, TDA10048_DSP_CODE_IN,				&fw->data[pos], cnt);			pos += cnt;		}		ret = -EIO;		/* Wait up to 250ms for the DSP to boot */		for (cnt = 0; cnt < 250 ; cnt += 10) {			msleep(10);			if (tda10048_readreg(state, TDA10048_SYNC_STATUS)				& 0x40) {				ret = 0;				break;			}		}	}	release_firmware(fw);	if (ret == 0) {		printk(KERN_INFO "%s: firmware uploaded\n", __func__);		state->fwloaded = 1;	} else		printk(KERN_ERR "%s: firmware upload failed\n", __func__);	return ret;}static int tda10048_set_inversion(struct dvb_frontend *fe, int inversion){	struct tda10048_state *state = fe->demodulator_priv;	dprintk(1, "%s(%d)\n", __func__, inversion);	if (inversion == TDA10048_INVERSION_ON)		tda10048_writereg(state, TDA10048_CONF_C1_1,			tda10048_readreg(state, TDA10048_CONF_C1_1) | 0x20);	else		tda10048_writereg(state, TDA10048_CONF_C1_1,			tda10048_readreg(state, TDA10048_CONF_C1_1) & 0xdf);	return 0;}/* Retrieve the demod settings */static int tda10048_get_tps(struct tda10048_state *state,	struct dvb_ofdm_parameters *p){	u8 val;	/* Make sure the TPS regs are valid */	if (!(tda10048_readreg(state, TDA10048_AUTO) & 0x01))		return -EAGAIN;	val = tda10048_readreg(state, TDA10048_OUT_CONF2);	switch ((val & 0x60) >> 5) {	case 0:		p->constellation = QPSK;		break;	case 1:		p->constellation = QAM_16;		break;	case 2:		p->constellation = QAM_64;		break;	}	switch ((val & 0x18) >> 3) {	case 0:		p->hierarchy_information = HIERARCHY_NONE;		break;	case 1:		p->hierarchy_information = HIERARCHY_1;		break;	case 2:		p->hierarchy_information = HIERARCHY_2;		break;	case 3:		p->hierarchy_information = HIERARCHY_4;		break;	}	switch (val & 0x07) {	case 0:		p->code_rate_HP = FEC_1_2;		break;	case 1:		p->code_rate_HP = FEC_2_3;		break;	case 2:		p->code_rate_HP = FEC_3_4;		break;	case 3:		p->code_rate_HP = FEC_5_6;		break;	case 4:		p->code_rate_HP = FEC_7_8;		break;	}	val = tda10048_readreg(state, TDA10048_OUT_CONF3);	switch (val & 0x07) {	case 0:		p->code_rate_LP = FEC_1_2;		break;	case 1:		p->code_rate_LP = FEC_2_3;		break;	case 2:		p->code_rate_LP = FEC_3_4;

⌨️ 快捷键说明

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