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

📄 af9013.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver * * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> * * Thanks to Afatech who kindly provided information. * *    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/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/firmware.h>#include "dvb_frontend.h"#include "af9013_priv.h"#include "af9013.h"int af9013_debug;struct af9013_state {	struct i2c_adapter *i2c;	struct dvb_frontend frontend;	struct af9013_config config;	u16 signal_strength;	u32 ber;	u32 ucblocks;	u16 snr;	u32 frequency;	unsigned long next_statistics_check;};static u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };static int af9013_write_regs(struct af9013_state *state, u8 mbox, u16 reg,	u8 *val, u8 len){	u8 buf[3+len];	struct i2c_msg msg = {		.addr = state->config.demod_address,		.flags = 0,		.len = sizeof(buf),		.buf = buf };	buf[0] = reg >> 8;	buf[1] = reg & 0xff;	buf[2] = mbox;	memcpy(&buf[3], val, len);	if (i2c_transfer(state->i2c, &msg, 1) != 1) {		warn("I2C write failed reg:%04x len:%d", reg, len);		return -EREMOTEIO;	}	return 0;}static int af9013_write_ofdm_regs(struct af9013_state *state, u16 reg, u8 *val,	u8 len){	u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(0 << 6)|(0 << 7);	return af9013_write_regs(state, mbox, reg, val, len);}static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val,	u8 len){	u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(1 << 6)|(1 << 7);	return af9013_write_regs(state, mbox, reg, val, len);}/* write single register */static int af9013_write_reg(struct af9013_state *state, u16 reg, u8 val){	return af9013_write_ofdm_regs(state, reg, &val, 1);}/* read single register */static int af9013_read_reg(struct af9013_state *state, u16 reg, u8 *val){	u8 obuf[3] = { reg >> 8, reg & 0xff, 0 };	u8 ibuf[1];	struct i2c_msg msg[2] = {		{			.addr = state->config.demod_address,			.flags = 0,			.len = sizeof(obuf),			.buf = obuf		}, {			.addr = state->config.demod_address,			.flags = I2C_M_RD,			.len = sizeof(ibuf),			.buf = ibuf		}	};	if (i2c_transfer(state->i2c, msg, 2) != 2) {		warn("I2C read failed reg:%04x", reg);		return -EREMOTEIO;	}	*val = ibuf[0];	return 0;}static int af9013_write_reg_bits(struct af9013_state *state, u16 reg, u8 pos,	u8 len, u8 val){	int ret;	u8 tmp, mask;	ret = af9013_read_reg(state, reg, &tmp);	if (ret)		return ret;	mask = regmask[len - 1] << pos;	tmp = (tmp & ~mask) | ((val << pos) & mask);	return af9013_write_reg(state, reg, tmp);}static int af9013_read_reg_bits(struct af9013_state *state, u16 reg, u8 pos,	u8 len, u8 *val){	int ret;	u8 tmp;	ret = af9013_read_reg(state, reg, &tmp);	if (ret)		return ret;	*val = (tmp >> pos) & regmask[len - 1];	return 0;}static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval){	int ret;	u8 pos;	u16 addr;	deb_info("%s: gpio:%d gpioval:%02x\n", __func__, gpio, gpioval);/* GPIO0 & GPIO1 0xd735   GPIO2 & GPIO3 0xd736 */	switch (gpio) {	case 0:	case 1:		addr = 0xd735;		break;	case 2:	case 3:		addr = 0xd736;		break;	default:		err("invalid gpio:%d\n", gpio);		ret = -EINVAL;		goto error;	};	switch (gpio) {	case 0:	case 2:		pos = 0;		break;	case 1:	case 3:	default:		pos = 4;		break;	};	ret = af9013_write_reg_bits(state, addr, pos, 4, gpioval);error:	return ret;}static u32 af913_div(u32 a, u32 b, u32 x){	u32 r = 0, c = 0, i;	deb_info("%s: a:%d b:%d x:%d\n", __func__, a, b, x);	if (a > b) {		c = a / b;		a = a - c * b;	}	for (i = 0; i < x; i++) {		if (a >= b) {			r += 1;			a -= b;		}		a <<= 1;		r <<= 1;	}	r = (c << (u32)x) + r;	deb_info("%s: a:%d b:%d x:%d r:%d r:%x\n", __func__, a, b, x, r, r);	return r;}static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw){	int ret = 0;	u8 i = 0;	u8 buf[24];	u32 ns_coeff1_2048nu;	u32 ns_coeff1_8191nu;	u32 ns_coeff1_8192nu;	u32 ns_coeff1_8193nu;	u32 ns_coeff2_2k;	u32 ns_coeff2_8k;	deb_info("%s: adc_clock:%d bw:%d\n", __func__,		state->config.adc_clock, bw);	switch (state->config.adc_clock) {	case 28800: /* 28.800 MHz */		switch (bw) {		case BANDWIDTH_6_MHZ:			ns_coeff1_2048nu = 0x01e79e7a;			ns_coeff1_8191nu = 0x0079eb6e;			ns_coeff1_8192nu = 0x0079e79e;			ns_coeff1_8193nu = 0x0079e3cf;			ns_coeff2_2k     = 0x00f3cf3d;			ns_coeff2_8k     = 0x003cf3cf;			break;		case BANDWIDTH_7_MHZ:			ns_coeff1_2048nu = 0x0238e38e;			ns_coeff1_8191nu = 0x008e3d55;			ns_coeff1_8192nu = 0x008e38e4;			ns_coeff1_8193nu = 0x008e3472;			ns_coeff2_2k     = 0x011c71c7;			ns_coeff2_8k     = 0x00471c72;			break;		case BANDWIDTH_8_MHZ:			ns_coeff1_2048nu = 0x028a28a3;			ns_coeff1_8191nu = 0x00a28f3d;			ns_coeff1_8192nu = 0x00a28a29;			ns_coeff1_8193nu = 0x00a28514;			ns_coeff2_2k     = 0x01451451;			ns_coeff2_8k     = 0x00514514;			break;		default:			ret = -EINVAL;		}		break;	case 20480: /* 20.480 MHz */		switch (bw) {		case BANDWIDTH_6_MHZ:			ns_coeff1_2048nu = 0x02adb6dc;			ns_coeff1_8191nu = 0x00ab7313;			ns_coeff1_8192nu = 0x00ab6db7;			ns_coeff1_8193nu = 0x00ab685c;			ns_coeff2_2k     = 0x0156db6e;			ns_coeff2_8k     = 0x0055b6dc;			break;		case BANDWIDTH_7_MHZ:			ns_coeff1_2048nu = 0x03200001;			ns_coeff1_8191nu = 0x00c80640;			ns_coeff1_8192nu = 0x00c80000;			ns_coeff1_8193nu = 0x00c7f9c0;			ns_coeff2_2k     = 0x01900000;			ns_coeff2_8k     = 0x00640000;			break;		case BANDWIDTH_8_MHZ:			ns_coeff1_2048nu = 0x03924926;			ns_coeff1_8191nu = 0x00e4996e;			ns_coeff1_8192nu = 0x00e49249;			ns_coeff1_8193nu = 0x00e48b25;			ns_coeff2_2k     = 0x01c92493;			ns_coeff2_8k     = 0x00724925;			break;		default:			ret = -EINVAL;		}		break;	case 28000: /* 28.000 MHz */		switch (bw) {		case BANDWIDTH_6_MHZ:			ns_coeff1_2048nu = 0x01f58d10;			ns_coeff1_8191nu = 0x007d672f;			ns_coeff1_8192nu = 0x007d6344;			ns_coeff1_8193nu = 0x007d5f59;			ns_coeff2_2k     = 0x00fac688;			ns_coeff2_8k     = 0x003eb1a2;			break;		case BANDWIDTH_7_MHZ:			ns_coeff1_2048nu = 0x02492492;			ns_coeff1_8191nu = 0x00924db7;			ns_coeff1_8192nu = 0x00924925;			ns_coeff1_8193nu = 0x00924492;			ns_coeff2_2k     = 0x01249249;			ns_coeff2_8k     = 0x00492492;			break;		case BANDWIDTH_8_MHZ:			ns_coeff1_2048nu = 0x029cbc15;			ns_coeff1_8191nu = 0x00a7343f;			ns_coeff1_8192nu = 0x00a72f05;			ns_coeff1_8193nu = 0x00a729cc;			ns_coeff2_2k     = 0x014e5e0a;			ns_coeff2_8k     = 0x00539783;			break;		default:			ret = -EINVAL;		}		break;	case 25000: /* 25.000 MHz */		switch (bw) {		case BANDWIDTH_6_MHZ:			ns_coeff1_2048nu = 0x0231bcb5;			ns_coeff1_8191nu = 0x008c7391;			ns_coeff1_8192nu = 0x008c6f2d;			ns_coeff1_8193nu = 0x008c6aca;			ns_coeff2_2k     = 0x0118de5b;			ns_coeff2_8k     = 0x00463797;			break;		case BANDWIDTH_7_MHZ:			ns_coeff1_2048nu = 0x028f5c29;			ns_coeff1_8191nu = 0x00a3dc29;			ns_coeff1_8192nu = 0x00a3d70a;			ns_coeff1_8193nu = 0x00a3d1ec;			ns_coeff2_2k     = 0x0147ae14;			ns_coeff2_8k     = 0x0051eb85;			break;		case BANDWIDTH_8_MHZ:			ns_coeff1_2048nu = 0x02ecfb9d;			ns_coeff1_8191nu = 0x00bb44c1;			ns_coeff1_8192nu = 0x00bb3ee7;			ns_coeff1_8193nu = 0x00bb390d;			ns_coeff2_2k     = 0x01767dce;			ns_coeff2_8k     = 0x005d9f74;			break;		default:			ret = -EINVAL;		}		break;	default:		err("invalid xtal");		return -EINVAL;	}	if (ret) {		err("invalid bandwidth");		return ret;	}	buf[i++] = (u8) ((ns_coeff1_2048nu & 0x03000000) >> 24);	buf[i++] = (u8) ((ns_coeff1_2048nu & 0x00ff0000) >> 16);	buf[i++] = (u8) ((ns_coeff1_2048nu & 0x0000ff00) >> 8);	buf[i++] = (u8) ((ns_coeff1_2048nu & 0x000000ff));	buf[i++] = (u8) ((ns_coeff2_2k     & 0x01c00000) >> 22);	buf[i++] = (u8) ((ns_coeff2_2k     & 0x003fc000) >> 14);	buf[i++] = (u8) ((ns_coeff2_2k     & 0x00003fc0) >> 6);	buf[i++] = (u8) ((ns_coeff2_2k     & 0x0000003f));	buf[i++] = (u8) ((ns_coeff1_8191nu & 0x03000000) >> 24);	buf[i++] = (u8) ((ns_coeff1_8191nu & 0x00ffc000) >> 16);	buf[i++] = (u8) ((ns_coeff1_8191nu & 0x0000ff00) >> 8);	buf[i++] = (u8) ((ns_coeff1_8191nu & 0x000000ff));	buf[i++] = (u8) ((ns_coeff1_8192nu & 0x03000000) >> 24);	buf[i++] = (u8) ((ns_coeff1_8192nu & 0x00ffc000) >> 16);	buf[i++] = (u8) ((ns_coeff1_8192nu & 0x0000ff00) >> 8);	buf[i++] = (u8) ((ns_coeff1_8192nu & 0x000000ff));	buf[i++] = (u8) ((ns_coeff1_8193nu & 0x03000000) >> 24);	buf[i++] = (u8) ((ns_coeff1_8193nu & 0x00ffc000) >> 16);	buf[i++] = (u8) ((ns_coeff1_8193nu & 0x0000ff00) >> 8);	buf[i++] = (u8) ((ns_coeff1_8193nu & 0x000000ff));	buf[i++] = (u8) ((ns_coeff2_8k     & 0x01c00000) >> 22);	buf[i++] = (u8) ((ns_coeff2_8k     & 0x003fc000) >> 14);	buf[i++] = (u8) ((ns_coeff2_8k     & 0x00003fc0) >> 6);	buf[i++] = (u8) ((ns_coeff2_8k     & 0x0000003f));	deb_info("%s: coeff:", __func__);	debug_dump(buf, sizeof(buf), deb_info);	/* program */	for (i = 0; i < sizeof(buf); i++) {		ret = af9013_write_reg(state, 0xae00 + i, buf[i]);		if (ret)			break;	}	return ret;}static int af9013_set_adc_ctrl(struct af9013_state *state){	int ret;	u8 buf[3], tmp, i;	u32 adc_cw;	deb_info("%s: adc_clock:%d\n", __func__, state->config.adc_clock);	/* adc frequency type */	switch (state->config.adc_clock) {	case 28800: /* 28.800 MHz */		tmp = 0;		break;	case 20480: /* 20.480 MHz */		tmp = 1;		break;	case 28000: /* 28.000 MHz */		tmp = 2;		break;	case 25000: /* 25.000 MHz */		tmp = 3;		break;	default:		err("invalid xtal");		return -EINVAL;	}	adc_cw = af913_div(state->config.adc_clock*1000, 1000000ul, 19ul);	buf[0] = (u8) ((adc_cw & 0x000000ff));	buf[1] = (u8) ((adc_cw & 0x0000ff00) >> 8);	buf[2] = (u8) ((adc_cw & 0x00ff0000) >> 16);	deb_info("%s: adc_cw:", __func__);	debug_dump(buf, sizeof(buf), deb_info);	/* program */	for (i = 0; i < sizeof(buf); i++) {		ret = af9013_write_reg(state, 0xd180 + i, buf[i]);		if (ret)			goto error;	}	ret = af9013_write_reg_bits(state, 0x9bd2, 0, 4, tmp);error:	return ret;}static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw){	int ret;	u16 addr;	u8 buf[3], i, j;	u32 adc_freq, freq_cw;	s8 bfs_spec_inv;	int if_sample_freq;	for (j = 0; j < 3; j++) {		if (j == 0) {			addr = 0xd140; /* fcw normal */			bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1;		} else if (j == 1) {			addr = 0x9be7; /* fcw dummy ram */			bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1;		} else {			addr = 0x9bea; /* fcw inverted */			bfs_spec_inv = state->config.rf_spec_inv ? 1 : -1;		}		adc_freq       = state->config.adc_clock * 1000;		if_sample_freq = state->config.tuner_if * 1000;		/* TDA18271 uses different sampling freq for every bw */		if (state->config.tuner == AF9013_TUNER_TDA18271) {			switch (bw) {			case BANDWIDTH_6_MHZ:				if_sample_freq = 3300000; /* 3.3 MHz */				break;			case BANDWIDTH_7_MHZ:				if_sample_freq = 3800000; /* 3.8 MHz */				break;			case BANDWIDTH_8_MHZ:			default:				if_sample_freq = 4300000; /* 4.3 MHz */				break;			}		}		while (if_sample_freq > (adc_freq / 2))			if_sample_freq = if_sample_freq - adc_freq;		if (if_sample_freq >= 0)			bfs_spec_inv = bfs_spec_inv * (-1);		else			if_sample_freq = if_sample_freq * (-1);		freq_cw = af913_div(if_sample_freq, adc_freq, 23ul);		if (bfs_spec_inv == -1)			freq_cw = 0x00800000 - freq_cw;		buf[0] = (u8) ((freq_cw & 0x000000ff));		buf[1] = (u8) ((freq_cw & 0x0000ff00) >> 8);		buf[2] = (u8) ((freq_cw & 0x007f0000) >> 16);		deb_info("%s: freq_cw:", __func__);		debug_dump(buf, sizeof(buf), deb_info);		/* program */		for (i = 0; i < sizeof(buf); i++) {			ret = af9013_write_reg(state, addr++, buf[i]);			if (ret)				goto error;		}	}error:	return ret;}static int af9013_set_ofdm_params(struct af9013_state *state,	struct dvb_ofdm_parameters *params, u8 *auto_mode){	int ret;	u8 i, buf[3] = {0, 0, 0};	*auto_mode = 0; /* set if parameters are requested to auto set */	switch (params->transmission_mode) {	case TRANSMISSION_MODE_AUTO:		*auto_mode = 1;	case TRANSMISSION_MODE_2K:		break;	case TRANSMISSION_MODE_8K:		buf[0] |= (1 << 0);		break;	default:		return -EINVAL;	}	switch (params->guard_interval) {	case GUARD_INTERVAL_AUTO:		*auto_mode = 1;	case GUARD_INTERVAL_1_32:		break;	case GUARD_INTERVAL_1_16:		buf[0] |= (1 << 2);		break;	case GUARD_INTERVAL_1_8:		buf[0] |= (2 << 2);		break;	case GUARD_INTERVAL_1_4:		buf[0] |= (3 << 2);		break;	default:		return -EINVAL;	}	switch (params->hierarchy_information) {	case HIERARCHY_AUTO:		*auto_mode = 1;

⌨️ 快捷键说明

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