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

📄 tda1004x.c

📁 h内核
💻 C
📖 第 1 页 / 共 3 页
字号:
  /*     Driver for Philips tda1004xh OFDM Demodulator     (c) 2003, 2004 Andrew de Quincey & Robert Schlabbach     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.   *//* * This driver needs external firmware. Please use the commands * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045", * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to * download/extract them, and then copy them to /usr/lib/hotplug/firmware. */#define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw"#define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw"#include <linux/init.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/device.h>#include "dvb_frontend.h"#include "tda1004x.h"#define TDA1004X_DEMOD_TDA10045 0#define TDA1004X_DEMOD_TDA10046 1struct tda1004x_state{	struct i2c_adapter* i2c;	struct dvb_frontend_ops ops;	const struct tda1004x_config* config;	struct dvb_frontend frontend;	/* private demod data */	u8 initialised:1;	u8 demod_type;};static int debug;#define dprintk(args...) \	do { \		if (debug) printk(KERN_DEBUG "tda1004x: " args); \	} while (0)#define TDA1004X_CHIPID		 0x00#define TDA1004X_AUTO		 0x01#define TDA1004X_IN_CONF1	 0x02#define TDA1004X_IN_CONF2	 0x03#define TDA1004X_OUT_CONF1	 0x04#define TDA1004X_OUT_CONF2	 0x05#define TDA1004X_STATUS_CD	 0x06#define TDA1004X_CONFC4		 0x07#define TDA1004X_DSSPARE2	 0x0C#define TDA10045H_CODE_IN	 0x0D#define TDA10045H_FWPAGE	 0x0E#define TDA1004X_SCAN_CPT	 0x10#define TDA1004X_DSP_CMD	 0x11#define TDA1004X_DSP_ARG	 0x12#define TDA1004X_DSP_DATA1	 0x13#define TDA1004X_DSP_DATA2	 0x14#define TDA1004X_CONFADC1	 0x15#define TDA1004X_CONFC1		 0x16#define TDA10045H_S_AGC		 0x1a#define TDA10046H_AGC_TUN_LEVEL	 0x1a#define TDA1004X_SNR		 0x1c#define TDA1004X_CONF_TS1	 0x1e#define TDA1004X_CONF_TS2	 0x1f#define TDA1004X_CBER_RESET	 0x20#define TDA1004X_CBER_MSB	 0x21#define TDA1004X_CBER_LSB	 0x22#define TDA1004X_CVBER_LUT	 0x23#define TDA1004X_VBER_MSB	 0x24#define TDA1004X_VBER_MID	 0x25#define TDA1004X_VBER_LSB	 0x26#define TDA1004X_UNCOR		 0x27#define TDA10045H_CONFPLL_P	 0x2D#define TDA10045H_CONFPLL_M_MSB	 0x2E#define TDA10045H_CONFPLL_M_LSB	 0x2F#define TDA10045H_CONFPLL_N	 0x30#define TDA10046H_CONFPLL1	 0x2D#define TDA10046H_CONFPLL2	 0x2F#define TDA10046H_CONFPLL3	 0x30#define TDA10046H_TIME_WREF1	 0x31#define TDA10046H_TIME_WREF2	 0x32#define TDA10046H_TIME_WREF3	 0x33#define TDA10046H_TIME_WREF4	 0x34#define TDA10046H_TIME_WREF5	 0x35#define TDA10045H_UNSURW_MSB	 0x31#define TDA10045H_UNSURW_LSB	 0x32#define TDA10045H_WREF_MSB	 0x33#define TDA10045H_WREF_MID	 0x34#define TDA10045H_WREF_LSB	 0x35#define TDA10045H_MUXOUT	 0x36#define TDA1004X_CONFADC2	 0x37#define TDA10045H_IOFFSET	 0x38#define TDA10046H_CONF_TRISTATE1 0x3B#define TDA10046H_CONF_TRISTATE2 0x3C#define TDA10046H_CONF_POLARITY	 0x3D#define TDA10046H_FREQ_OFFSET	 0x3E#define TDA10046H_GPIO_OUT_SEL	 0x41#define TDA10046H_GPIO_SELECT	 0x42#define TDA10046H_AGC_CONF	 0x43#define TDA10046H_AGC_GAINS	 0x46#define TDA10046H_AGC_TUN_MIN	 0x47#define TDA10046H_AGC_TUN_MAX	 0x48#define TDA10046H_AGC_IF_MIN	 0x49#define TDA10046H_AGC_IF_MAX	 0x4A#define TDA10046H_FREQ_PHY2_MSB	 0x4D#define TDA10046H_FREQ_PHY2_LSB	 0x4E#define TDA10046H_CVBER_CTRL	 0x4F#define TDA10046H_AGC_IF_LEVEL	 0x52#define TDA10046H_CODE_CPT	 0x57#define TDA10046H_CODE_IN	 0x58static int tda1004x_write_byteI(struct tda1004x_state *state, int reg, int data){	int ret;	u8 buf[] = { reg, data };	struct i2c_msg msg = { .addr=0, .flags=0, .buf=buf, .len=2 };	dprintk("%s: reg=0x%x, data=0x%x\n", __FUNCTION__, reg, data);	msg.addr = state->config->demod_address;	ret = i2c_transfer(state->i2c, &msg, 1);	if (ret != 1)		dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",			__FUNCTION__, reg, data, ret);	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __FUNCTION__,		reg, data, ret);	return (ret != 1) ? -1 : 0;}static int tda1004x_read_byte(struct tda1004x_state *state, int reg){	int ret;	u8 b0[] = { reg };	u8 b1[] = { 0 };	struct i2c_msg msg[] = {{ .addr=0, .flags=0, .buf=b0, .len=1},				{ .addr=0, .flags=I2C_M_RD, .buf=b1, .len = 1}};	dprintk("%s: reg=0x%x\n", __FUNCTION__, reg);	msg[0].addr = state->config->demod_address;	msg[1].addr = state->config->demod_address;	ret = i2c_transfer(state->i2c, msg, 2);	if (ret != 2) {		dprintk("%s: error reg=0x%x, ret=%i\n", __FUNCTION__, reg,			ret);		return -1;	}	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __FUNCTION__,		reg, b1[0], ret);	return b1[0];}static int tda1004x_write_mask(struct tda1004x_state *state, int reg, int mask, int data){	int val;	dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __FUNCTION__, reg,		mask, data);	// read a byte and check	val = tda1004x_read_byte(state, reg);	if (val < 0)		return val;	// mask if off	val = val & ~mask;	val |= data & 0xff;	// write it out again	return tda1004x_write_byteI(state, reg, val);}static int tda1004x_write_buf(struct tda1004x_state *state, int reg, unsigned char *buf, int len){	int i;	int result;	dprintk("%s: reg=0x%x, len=0x%x\n", __FUNCTION__, reg, len);	result = 0;	for (i = 0; i < len; i++) {		result = tda1004x_write_byteI(state, reg + i, buf[i]);		if (result != 0)			break;	}	return result;}static int tda1004x_enable_tuner_i2c(struct tda1004x_state *state){	int result;	dprintk("%s\n", __FUNCTION__);	result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2);	msleep(1);	return result;}static int tda1004x_disable_tuner_i2c(struct tda1004x_state *state){	dprintk("%s\n", __FUNCTION__);	return tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 0);}static int tda10045h_set_bandwidth(struct tda1004x_state *state,				   fe_bandwidth_t bandwidth){	static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f };	static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb };	static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 };	switch (bandwidth) {	case BANDWIDTH_6_MHZ:		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz));		break;	case BANDWIDTH_7_MHZ:		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz));		break;	case BANDWIDTH_8_MHZ:		tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz));		break;	default:		return -EINVAL;	}	tda1004x_write_byteI(state, TDA10045H_IOFFSET, 0);	return 0;}static int tda10046h_set_bandwidth(struct tda1004x_state *state,				   fe_bandwidth_t bandwidth){	static u8 bandwidth_6mhz[] = { 0x80, 0x15, 0xfe, 0xab, 0x8e };	static u8 bandwidth_7mhz[] = { 0x6e, 0x02, 0x53, 0xc8, 0x25 };	static u8 bandwidth_8mhz[] = { 0x60, 0x12, 0xa8, 0xe4, 0xbd };	switch (bandwidth) {	case BANDWIDTH_6_MHZ:		tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz));		break;	case BANDWIDTH_7_MHZ:		tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz));		break;	case BANDWIDTH_8_MHZ:		tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz));		break;	default:		return -EINVAL;	}	return 0;}static int tda1004x_do_upload(struct tda1004x_state *state,			      unsigned char *mem, unsigned int len,			      u8 dspCodeCounterReg, u8 dspCodeInReg){	u8 buf[65];	struct i2c_msg fw_msg = {.addr = 0,.flags = 0,.buf = buf,.len = 0 };	int tx_size;	int pos = 0;	/* clear code counter */	tda1004x_write_byteI(state, dspCodeCounterReg, 0);	fw_msg.addr = state->config->demod_address;	buf[0] = dspCodeInReg;	while (pos != len) {		// work out how much to send this time		tx_size = len - pos;		if (tx_size > 0x10) {			tx_size = 0x10;		}		// send the chunk		memcpy(buf + 1, mem + pos, tx_size);		fw_msg.len = tx_size + 1;		if (i2c_transfer(state->i2c, &fw_msg, 1) != 1) {			printk("tda1004x: Error during firmware upload\n");			return -EIO;		}		pos += tx_size;		dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, pos);	}	return 0;}static int tda1004x_check_upload_ok(struct tda1004x_state *state, u8 dspVersion){	u8 data1, data2;	// check upload was OK	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP	tda1004x_write_byteI(state, TDA1004X_DSP_CMD, 0x67);	data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1);	data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2);	if (data1 != 0x67 || data2 != dspVersion) {		return -EIO;	}	return 0;}static int tda10045_fwupload(struct dvb_frontend* fe){	struct tda1004x_state* state = fe->demodulator_priv;	int ret;	const struct firmware *fw;	/* don't re-upload unless necessary */	if (tda1004x_check_upload_ok(state, 0x2c) == 0) return 0;	/* request the firmware, this will block until someone uploads it */	printk("tda1004x: waiting for firmware upload...\n");	ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);	if (ret) {		printk("tda1004x: no firmware upload (timeout or file not found?)\n");	   	return ret;	}	/* reset chip */	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0);	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8);	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0);	msleep(10);	/* set parameters */	tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ);	ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN);	if (ret)		return ret;	/* wait for DSP to initialise */	/* DSPREADY doesn't seem to work on the TDA10045H */	msleep(100);	return tda1004x_check_upload_ok(state, 0x2c);}static int tda10046_fwupload(struct dvb_frontend* fe){	struct tda1004x_state* state = fe->demodulator_priv;	unsigned long timeout;	int ret;	const struct firmware *fw;	/* reset + wake up chip */	tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0);	tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);	msleep(100);	/* don't re-upload unless necessary */	if (tda1004x_check_upload_ok(state, 0x20) == 0) return 0;	/* request the firmware, this will block until someone uploads it */	printk("tda1004x: waiting for firmware upload...\n");	ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);	if (ret) {		printk("tda1004x: no firmware upload (timeout or file not found?)\n");   	   	return ret;	}

⌨️ 快捷键说明

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