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

📄 dib7000p.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC). * * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) * * 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, version 2. */#include <linux/kernel.h>#include <linux/i2c.h>#include "compat.h"#include "dvb_frontend.h"#include "dib7000p.h"static int debug;module_param(debug, int, 0644);MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");static int buggy_sfn_workaround;module_param(buggy_sfn_workaround, int, 0644);MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)struct dib7000p_state {	struct dvb_frontend demod;    struct dib7000p_config cfg;	u8 i2c_addr;	struct i2c_adapter   *i2c_adap;	struct dibx000_i2c_master i2c_master;	u16 wbd_ref;	u8  current_band;	u32 current_bandwidth;	struct dibx000_agc_config *current_agc;	u32 timf;	u8 div_force_off : 1;	u8 div_state : 1;	u16 div_sync_wait;	u8 agc_state;	u16 gpio_dir;	u16 gpio_val;	u8 sfn_workaround_active :1;};enum dib7000p_power_mode {	DIB7000P_POWER_ALL = 0,	DIB7000P_POWER_ANALOG_ADC,	DIB7000P_POWER_INTERFACE_ONLY,};static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg){	u8 wb[2] = { reg >> 8, reg & 0xff };	u8 rb[2];	struct i2c_msg msg[2] = {		{ .addr = state->i2c_addr >> 1, .flags = 0,        .buf = wb, .len = 2 },		{ .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },	};	if (i2c_transfer(state->i2c_adap, msg, 2) != 2)		dprintk("i2c read error on %d",reg);	return (rb[0] << 8) | rb[1];}static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val){	u8 b[4] = {		(reg >> 8) & 0xff, reg & 0xff,		(val >> 8) & 0xff, val & 0xff,	};	struct i2c_msg msg = {		.addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4	};	return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;}static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf){	u16 l = 0, r, *n;	n = buf;	l = *n++;	while (l) {		r = *n++;		do {			dib7000p_write_word(state, r, *n++);			r++;		} while (--l);		l = *n++;	}}static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode){	int    ret = 0;	u16 outreg, fifo_threshold, smo_mode;	outreg = 0;	fifo_threshold = 1792;	smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1);	dprintk( "setting output mode for demod %p to %d",			&state->demod, mode);	switch (mode) {		case OUTMODE_MPEG2_PAR_GATED_CLK:   // STBs with parallel gated clock			outreg = (1 << 10);  /* 0x0400 */			break;		case OUTMODE_MPEG2_PAR_CONT_CLK:    // STBs with parallel continues clock			outreg = (1 << 10) | (1 << 6); /* 0x0440 */			break;		case OUTMODE_MPEG2_SERIAL:          // STBs with serial input			outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */			break;		case OUTMODE_DIVERSITY:			if (state->cfg.hostbus_diversity)				outreg = (1 << 10) | (4 << 6); /* 0x0500 */			else				outreg = (1 << 11);			break;		case OUTMODE_MPEG2_FIFO:            // e.g. USB feeding			smo_mode |= (3 << 1);			fifo_threshold = 512;			outreg = (1 << 10) | (5 << 6);			break;		case OUTMODE_ANALOG_ADC:			outreg = (1 << 10) | (3 << 6);			break;		case OUTMODE_HIGH_Z:  // disable			outreg = 0;			break;		default:			dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod);			break;	}	if (state->cfg.output_mpeg2_in_188_bytes)		smo_mode |= (1 << 5) ;	ret |= dib7000p_write_word(state,  235, smo_mode);	ret |= dib7000p_write_word(state,  236, fifo_threshold); /* synchronous fread */	ret |= dib7000p_write_word(state, 1286, outreg);         /* P_Div_active */	return ret;}static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff){	struct dib7000p_state *state = demod->demodulator_priv;	if (state->div_force_off) {		dprintk( "diversity combination deactivated - forced by COFDM parameters");		onoff = 0;	}	state->div_state = (u8)onoff;	if (onoff) {		dib7000p_write_word(state, 204, 6);		dib7000p_write_word(state, 205, 16);		/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */		dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));	} else {		dib7000p_write_word(state, 204, 1);		dib7000p_write_word(state, 205, 0);		dib7000p_write_word(state, 207, 0);	}	return 0;}static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode){	/* by default everything is powered off */	u16 reg_774 = 0xffff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899  = 0x0003,		reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);	/* now, depending on the requested mode, we power on */	switch (mode) {		/* power up everything in the demod */		case DIB7000P_POWER_ALL:			reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff;			break;		case DIB7000P_POWER_ANALOG_ADC:			/* dem, cfg, iqc, sad, agc */			reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));			/* nud */			reg_776 &= ~((1 << 0));			/* Dout */			reg_1280 &= ~((1 << 11));			/* fall through wanted to enable the interfaces */		/* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */		case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */			reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));			break;/* TODO following stuff is just converted from the dib7000-driver - check when is used what */#if 0		case DIB7000_POWER_LEVEL_INTERF_ANALOG_AGC:			/* dem, cfg, iqc, sad, agc */			reg_774  &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));			/* sdio, i2c, gpio */			reg_1280 &= ~((1 << 13) | (1 << 12) | (1 << 10));			break;		case DIB7000_POWER_LEVEL_DOWN_COR4_DINTLV_ICIRM_EQUAL_CFROD:			reg_774   = 0;			/* power down: cor4 dintlv equal */			reg_775   = (1 << 15) | (1 << 6) | (1 << 5);			reg_776   = 0;			reg_899   = 0;			reg_1280 &= 0x01ff;			break;		case DIB7000_POWER_LEVEL_DOWN_COR4_CRY_ESRAM_MOUT_NUD:			reg_774   = 0;			/* power down: cor4 */			reg_775   = (1 << 15);			/* nud */			reg_776   = (1 <<  0);			reg_899   = 0;			reg_1280 &= 0x01ff;			break;#endif	}	dib7000p_write_word(state,  774,  reg_774);	dib7000p_write_word(state,  775,  reg_775);	dib7000p_write_word(state,  776,  reg_776);	dib7000p_write_word(state,  899,  reg_899);	dib7000p_write_word(state, 1280, reg_1280);	return 0;}static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no){	u16 reg_908 = dib7000p_read_word(state, 908),	       reg_909 = dib7000p_read_word(state, 909);	switch (no) {		case DIBX000_SLOW_ADC_ON:			reg_909 |= (1 << 1) | (1 << 0);			dib7000p_write_word(state, 909, reg_909);			reg_909 &= ~(1 << 1);			break;		case DIBX000_SLOW_ADC_OFF:			reg_909 |=  (1 << 1) | (1 << 0);			break;		case DIBX000_ADC_ON:			reg_908 &= 0x0fff;			reg_909 &= 0x0003;			break;		case DIBX000_ADC_OFF: // leave the VBG voltage on			reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);			reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);			break;		case DIBX000_VBG_ENABLE:			reg_908 &= ~(1 << 15);			break;		case DIBX000_VBG_DISABLE:			reg_908 |= (1 << 15);			break;		default:			break;	}//	dprintk( "908: %x, 909: %x\n", reg_908, reg_909);	dib7000p_write_word(state, 908, reg_908);	dib7000p_write_word(state, 909, reg_909);}static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw){	u32 timf;	// store the current bandwidth for later use	state->current_bandwidth = bw;	if (state->timf == 0) {		dprintk( "using default timf");		timf = state->cfg.bw->timf;	} else {		dprintk( "using updated timf");		timf = state->timf;	}	timf = timf * (bw / 50) / 160;	dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));	dib7000p_write_word(state, 24, (u16) ((timf      ) & 0xffff));	return 0;}static int dib7000p_sad_calib(struct dib7000p_state *state){/* internal *///	dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth	dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));	dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096	/* do the calibration */	dib7000p_write_word(state, 73, (1 << 0));	dib7000p_write_word(state, 73, (0 << 0));	msleep(1);	return 0;}int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value){	struct dib7000p_state *state = demod->demodulator_priv;	if (value > 4095)		value = 4095;	state->wbd_ref = value;	return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);}EXPORT_SYMBOL(dib7000p_set_wbd_ref);static void dib7000p_reset_pll(struct dib7000p_state *state){	struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];	u16 clk_cfg0;	/* force PLL bypass */	clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |		(bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) |		(bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);	dib7000p_write_word(state, 900, clk_cfg0);	/* P_pll_cfg */	dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);	clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);	dib7000p_write_word(state, 900, clk_cfg0);	dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));	dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000       ) & 0xffff));	dib7000p_write_word(state, 21, (u16) ( (bw->ifreq          >> 16) & 0xffff));	dib7000p_write_word(state, 22, (u16) ( (bw->ifreq               ) & 0xffff));	dib7000p_write_word(state, 72, bw->sad_cfg);}static int dib7000p_reset_gpio(struct dib7000p_state *st){	/* reset the GPIOs */	dprintk( "gpio dir: %x: val: %x, pwm_pos: %x",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos);	dib7000p_write_word(st, 1029, st->gpio_dir);	dib7000p_write_word(st, 1030, st->gpio_val);	/* TODO 1031 is P_gpio_od */	dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);	dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);	return 0;}static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val){	st->gpio_dir = dib7000p_read_word(st, 1029);	st->gpio_dir &= ~(1 << num);         /* reset the direction bit */	st->gpio_dir |=  (dir & 0x1) << num; /* set the new direction */	dib7000p_write_word(st, 1029, st->gpio_dir);	st->gpio_val = dib7000p_read_word(st, 1030);	st->gpio_val &= ~(1 << num);          /* reset the direction bit */	st->gpio_val |=  (val & 0x01) << num; /* set the new value */	dib7000p_write_word(st, 1030, st->gpio_val);	return 0;}int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val){	struct dib7000p_state *state = demod->demodulator_priv;	return dib7000p_cfg_gpio(state, num, dir, val);}EXPORT_SYMBOL(dib7000p_set_gpio);static u16 dib7000p_defaults[] ={	// auto search configuration	3, 2,		0x0004,		0x1000,		0x0814, /* Equal Lock */	12, 6,		0x001b,		0x7740,		0x005b,		0x8d80,		0x01c9,		0xc380,		0x0000,		0x0080,		0x0000,		0x0090,		0x0001,		0xd4c0,	1, 26,		0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26	/* set ADC level to -16 */	11, 79,		(1 << 13) - 825 - 117,		(1 << 13) - 837 - 117,		(1 << 13) - 811 - 117,		(1 << 13) - 766 - 117,		(1 << 13) - 737 - 117,		(1 << 13) - 693 - 117,		(1 << 13) - 648 - 117,		(1 << 13) - 619 - 117,		(1 << 13) - 575 - 117,		(1 << 13) - 531 - 117,		(1 << 13) - 501 - 117,	1, 142,		0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16	/* disable power smoothing */	8, 145,		0,		0,		0,		0,		0,		0,		0,		0,	1, 154,		1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0	1, 168,		0x0ccd, // P_pha3_thres, default 0x3000//	1, 169,//		0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010	1, 183,		0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005	5, 187,		0x023d, // P_adp_regul_cnt=573, default: 410		0x00a4, // P_adp_noise_cnt=		0x00a4, // P_adp_regul_ext		0x7ff0, // P_adp_noise_ext		0x3ccc, // P_adp_fil

⌨️ 快捷键说明

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