dib7000m.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 1,446 行 · 第 1/3 页

C
1,446
字号
		0,		0,		0,		0,		0,		0,		0,		0,	1, 182,		8192, // P_fft_nb_to_cut	2, 195,		0x0ccd, // P_pha3_thres		0,      // P_cti_use_cpe, P_cti_use_prog	1, 205,		0x200f, // P_cspu_regul, P_cspu_win_cut	5, 214,		0x023d, // P_adp_regul_cnt		0x00a4, // P_adp_noise_cnt		0x00a4, // P_adp_regul_ext		0x7ff0, // P_adp_noise_ext		0x3ccc, // P_adp_fil	1, 226,		0, // P_2d_byp_ti_num	1, 255,		0x800, // P_equal_thres_wgn	1, 263,		0x0001,	1, 281,		0x0010, // P_fec_*	1, 294,		0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard	0};static u16 dib7000m_defaults[] ={	/* set ADC level to -16 */	11, 76,		(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,	// Tuner IO bank: max drive (14mA)	1, 912,		0x2c8a,	1, 1817,		1,	0,};static int dib7000m_demod_reset(struct dib7000m_state *state){	dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);	/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */	dib7000m_set_adc_state(state, DIBX000_VBG_ENABLE);	/* restart all parts */	dib7000m_write_word(state,  898, 0xffff);	dib7000m_write_word(state,  899, 0xffff);	dib7000m_write_word(state,  900, 0xff0f);	dib7000m_write_word(state,  901, 0xfffc);	dib7000m_write_word(state,  898, 0);	dib7000m_write_word(state,  899, 0);	dib7000m_write_word(state,  900, 0);	dib7000m_write_word(state,  901, 0);	if (state->revision == 0x4000)		dib7000m_reset_pll(state);	else		dib7000mc_reset_pll(state);	if (dib7000m_reset_gpio(state) != 0)		dprintk( "GPIO reset was not successful.");	if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0)		dprintk( "OUTPUT_MODE could not be reset.");	/* unforce divstr regardless whether i2c enumeration was done or not */	dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) );	dib7000m_set_bandwidth(state, 8000);	dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON);	dib7000m_sad_calib(state);	dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF);	if (state->cfg.dvbt_mode)		dib7000m_write_word(state, 1796, 0x0); // select DVB-T output	if (state->cfg.mobile_mode)		dib7000m_write_word(state, 261 + state->reg_offs, 2);	else		dib7000m_write_word(state, 224 + state->reg_offs, 1);	// P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...	if(state->cfg.tuner_is_baseband)		dib7000m_write_word(state, 36, 0x0755);	else		dib7000m_write_word(state, 36, 0x1f55);	// P_divclksel=3 P_divbitsel=1	if (state->revision == 0x4000)		dib7000m_write_word(state, 909, (3 << 10) | (1 << 6));	else		dib7000m_write_word(state, 909, (3 << 4) | 1);	dib7000m_write_tab(state, dib7000m_defaults_common);	dib7000m_write_tab(state, dib7000m_defaults);	dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY);	state->internal_clk = state->cfg.bw->internal;	return 0;}static void dib7000m_restart_agc(struct dib7000m_state *state){	// P_restart_iqc & P_restart_agc	dib7000m_write_word(state, 898, 0x0c00);	dib7000m_write_word(state, 898, 0x0000);}static int dib7000m_agc_soft_split(struct dib7000m_state *state){	u16 agc,split_offset;	if(!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)		return 0;	// n_agc_global	agc = dib7000m_read_word(state, 390);	if (agc > state->current_agc->split.min_thres)		split_offset = state->current_agc->split.min;	else if (agc < state->current_agc->split.max_thres)		split_offset = state->current_agc->split.max;	else		split_offset = state->current_agc->split.max *			(agc - state->current_agc->split.min_thres) /			(state->current_agc->split.max_thres - state->current_agc->split.min_thres);	dprintk( "AGC split_offset: %d",split_offset);	// P_agc_force_split and P_agc_split_offset	return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset);}static int dib7000m_update_lna(struct dib7000m_state *state){	u16 dyn_gain;	if (state->cfg.update_lna) {		// read dyn_gain here (because it is demod-dependent and not fe)		dyn_gain = dib7000m_read_word(state, 390);		if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed			dib7000m_restart_agc(state);			return 1;		}	}	return 0;}static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band){	struct dibx000_agc_config *agc = NULL;	int i;	if (state->current_band == band && state->current_agc != NULL)		return 0;	state->current_band = band;	for (i = 0; i < state->cfg.agc_config_count; i++)		if (state->cfg.agc[i].band_caps & band) {			agc = &state->cfg.agc[i];			break;		}	if (agc == NULL) {		dprintk( "no valid AGC configuration found for band 0x%02x",band);		return -EINVAL;	}	state->current_agc = agc;	/* AGC */	dib7000m_write_word(state, 72 ,  agc->setup);	dib7000m_write_word(state, 73 ,  agc->inv_gain);	dib7000m_write_word(state, 74 ,  agc->time_stabiliz);	dib7000m_write_word(state, 97 , (agc->alpha_level << 12) | agc->thlock);	// Demod AGC loop configuration	dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp);	dib7000m_write_word(state, 99, (agc->beta_mant  << 6) | agc->beta_exp);	dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);	/* AGC continued */	if (state->wbd_ref != 0)		dib7000m_write_word(state, 102, state->wbd_ref);	else // use default		dib7000m_write_word(state, 102, agc->wbd_ref);	dib7000m_write_word(state, 103, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) );	dib7000m_write_word(state, 104,  agc->agc1_max);	dib7000m_write_word(state, 105,  agc->agc1_min);	dib7000m_write_word(state, 106,  agc->agc2_max);	dib7000m_write_word(state, 107,  agc->agc2_min);	dib7000m_write_word(state, 108, (agc->agc1_pt1 << 8) | agc->agc1_pt2 );	dib7000m_write_word(state, 109, (agc->agc1_slope1 << 8) | agc->agc1_slope2);	dib7000m_write_word(state, 110, (agc->agc2_pt1 << 8) | agc->agc2_pt2);	dib7000m_write_word(state, 111, (agc->agc2_slope1 << 8) | agc->agc2_slope2);	if (state->revision > 0x4000) { // settings for the MC		dib7000m_write_word(state, 71,   agc->agc1_pt3);//		dprintk( "929: %x %d %d",//			(dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel);		dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2));	} else {		// wrong default values		u16 b[9] = { 676, 696, 717, 737, 758, 778, 799, 819, 840 };		for (i = 0; i < 9; i++)			dib7000m_write_word(state, 88 + i, b[i]);	}	return 0;}static void dib7000m_update_timf(struct dib7000m_state *state){	u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437);	state->timf = timf * 160 / (state->current_bandwidth / 50);	dib7000m_write_word(state, 23, (u16) (timf >> 16));	dib7000m_write_word(state, 24, (u16) (timf & 0xffff));	dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default);}static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch){	struct dib7000m_state *state = demod->demodulator_priv;	u16 cfg_72 = dib7000m_read_word(state, 72);	int ret = -1;	u8 *agc_state = &state->agc_state;	u8 agc_split;	switch (state->agc_state) {		case 0:			// set power-up level: interf+analog+AGC			dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC);			dib7000m_set_adc_state(state, DIBX000_ADC_ON);			if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)				return -1;			ret = 7; /* ADC power up */			(*agc_state)++;			break;		case 1:			/* AGC initialization */			if (state->cfg.agc_control)				state->cfg.agc_control(&state->demod, 1);			dib7000m_write_word(state, 75, 32768);			if (!state->current_agc->perform_agc_softsplit) {				/* we are using the wbd - so slow AGC startup */				dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */				(*agc_state)++;				ret = 5;			} else {				/* default AGC startup */				(*agc_state) = 4;				/* wait AGC rough lock time */				ret = 7;			}			dib7000m_restart_agc(state);			break;		case 2: /* fast split search path after 5sec */			dib7000m_write_word(state,  72, cfg_72 | (1 << 4)); /* freeze AGC loop */			dib7000m_write_word(state, 103, 2 << 9);            /* fast split search 0.25kHz */			(*agc_state)++;			ret = 14;			break;	case 3: /* split search ended */			agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */			dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */			dib7000m_write_word(state, 72,  cfg_72 & ~(1 << 4));   /* std AGC loop */			dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */			dib7000m_restart_agc(state);			dprintk( "SPLIT %p: %hd", demod, agc_split);			(*agc_state)++;			ret = 5;			break;		case 4: /* LNA startup */			/* wait AGC accurate lock time */			ret = 7;			if (dib7000m_update_lna(state))				// wait only AGC rough lock time				ret = 5;			else				(*agc_state)++;			break;		case 5:			dib7000m_agc_soft_split(state);			if (state->cfg.agc_control)				state->cfg.agc_control(&state->demod, 0);			(*agc_state)++;			break;		default:			break;	}	return ret;}static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_frontend_parameters *ch, u8 seq){	u16 value, est[4];	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));	/* nfft, guard, qam, alpha */	value = 0;	switch (ch->u.ofdm.transmission_mode) {		case TRANSMISSION_MODE_2K: value |= (0 << 7); break;		case /* 4K MODE */ 255: value |= (2 << 7); break;		default:		case TRANSMISSION_MODE_8K: value |= (1 << 7); break;	}	switch (ch->u.ofdm.guard_interval) {		case GUARD_INTERVAL_1_32: value |= (0 << 5); break;		case GUARD_INTERVAL_1_16: value |= (1 << 5); break;		case GUARD_INTERVAL_1_4:  value |= (3 << 5); break;		default:		case GUARD_INTERVAL_1_8:  value |= (2 << 5); break;	}	switch (ch->u.ofdm.constellation) {		case QPSK:  value |= (0 << 3); break;		case QAM_16: value |= (1 << 3); break;		default:		case QAM_64: value |= (2 << 3); break;	}	switch (HIERARCHY_1) {		case HIERARCHY_2: value |= 2; break;		case HIERARCHY_4: value |= 4; break;		default:		case HIERARCHY_1: value |= 1; break;	}	dib7000m_write_word(state, 0, value);	dib7000m_write_word(state, 5, (seq << 4));	/* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */	value = 0;	if (1 != 0)		value |= (1 << 6);	if (ch->u.ofdm.hierarchy_information == 1)		value |= (1 << 4);	if (1 == 1)		value |= 1;	switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {		case FEC_2_3: value |= (2 << 1); break;		case FEC_3_4: value |= (3 << 1); break;		case FEC_5_6: value |= (5 << 1); break;		case FEC_7_8: value |= (7 << 1); break;		default:		case FEC_1_2: value |= (1 << 1); break;	}	dib7000m_write_word(state, 267 + state->reg_offs, value);	/* offset loop parameters */	/* P_timf_alpha = 6, P_corm_alpha=6, P_corm_thres=0x80 */	dib7000m_write_word(state, 26, (6 << 12) | (6 << 8) | 0x80);	/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=1, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */	dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (1 << 9) | (3 << 5) | (1 << 4) | (0x3));	/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max=3 */	dib7000m_write_word(state, 32, (0 << 4) | 0x3);	/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step=5 */	dib7000m_write_word(state, 33, (0 << 4) | 0x5);	/* P_dvsy_sync_wait */	switch (ch->u.ofdm.transmission_mode) {		case TRANSMISSION_MODE_8K: value = 256; break;		case /* 4K MODE */ 255: value = 128; break;		case TRANSMISSION_MODE_2K:		default: value = 64; break;	}	switch (ch->u.ofdm.guard_interval) {		case GUARD_INTERVAL_1_16: value *= 2; break;		case GUARD_INTERVAL_1_8:  value *= 4; break;		case GUARD_INTERVAL_1_4:  value *= 8; break;		default:		case GUARD_INTERVAL_1_32: value *= 1; break;	}	state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO	/* deactive the possibility of diversity reception if extended interleave - not for 7000MC */	/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */	if (1 == 1 || state->revision > 0x4000)		state->div_force_off = 0;	else		state->div_force_off = 1;	dib7000m_set_diversity_in(&state->demod, state->div_state);	/* channel estimation fine configuration */	switch (ch->u.ofdm.constellation) {		case QAM_64:			est[0] = 0x0148;       /* P_adp_regul_cnt 0.04 */			est[1] = 0xfff0;       /* P_adp_noise_cnt -0.002 */			est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */			est[3] = 0xfff8;       /* P_adp_noise_ext -0.001 */			break;		case QAM_16:			est[0] = 0x023d;       /* P_adp_regul_cnt 0.07 */			est[1] = 0xffdf;       /* P_adp_noise_cnt -0.004 */			est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */			est[3] = 0xfff0;       /* P_adp_noise_ext -0.002 */			break;		default:			est[0] = 0x099a;       /* P_adp_regul_cnt 0.3 */			est[1] = 0xffae;       /* P_adp_noise_cnt -0.01 */			est[2] = 0x0333;       /* P_adp_regul_ext 0.1 */			est[3] = 0xfff8;       /* P_adp_noise_ext -0.002 */			break;	}	for (value = 0; value < 4; value++)		dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]);	// set power-up level: autosearch	dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD);}static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch){	struct dib7000m_state *state = demod->demodulator_priv;	struct dvb_frontend_parameters schan;	int ret = 0;	u32 value, factor;	schan = *ch;	schan.u.ofdm.constellation = QAM_64;	schan.u.ofdm.guard_interval        = GUARD_INTERVAL_1_32;	schan.u.ofdm.transmission_mode         = TRANSMISSION_MODE_8K;

⌨️ 快捷键说明

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