dib3000mc.c

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

C
935
字号
	dib3000mc_write_word(state, 95,0);	dib3000mc_write_word(state, 96,0);	dib3000mc_write_word(state, 97,0);	dib3000mc_write_word(state, 98,0);	dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode);	value = 0;	switch (ch->u.ofdm.transmission_mode) {		case TRANSMISSION_MODE_2K: value |= (0 << 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;	}	dib3000mc_write_word(state, 0, value);	dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4));	value = 0;	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;	}	dib3000mc_write_word(state, 181, value);	// diversity synchro delay add 50% SFN margin	switch (ch->u.ofdm.transmission_mode) {		case TRANSMISSION_MODE_8K: value = 256; 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;	}	value <<= 4;	value |= dib3000mc_read_word(state, 180) & 0x000f;	dib3000mc_write_word(state, 180, value);	// restart demod	value = dib3000mc_read_word(state, 0);	dib3000mc_write_word(state, 0, value | (1 << 9));	dib3000mc_write_word(state, 0, value);	msleep(30);	dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode);}static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan){	struct dib3000mc_state *state = demod->demodulator_priv;	u16 reg;//	u32 val;	struct dvb_frontend_parameters schan;	schan = *chan;	/* TODO what is that ? */#if 0	if (boost) {		val  = (dib3000mc_read_word(state, 6) << 16) | dib3000mc_read_word(state, 7);		val *= 85;		val >>= 7;		dib3000mc_write_word(state, 6, (val >> 16) & 0xffff);		dib3000mc_write_word(state, 7, (val      ) & 0xffff);	}#endif	/* a channel for autosearch */	schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;	schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;	schan.u.ofdm.constellation = QAM_64;	schan.u.ofdm.code_rate_HP = FEC_2_3;	schan.u.ofdm.code_rate_LP = FEC_2_3;	schan.u.ofdm.hierarchy_information = 0;	dib3000mc_set_channel_cfg(state, &schan, 11);	reg = dib3000mc_read_word(state, 0);	dib3000mc_write_word(state, 0, reg | (1 << 8));	dib3000mc_read_word(state, 511);	dib3000mc_write_word(state, 0, reg);	return 0;}static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod){	struct dib3000mc_state *state = demod->demodulator_priv;	u16 irq_pending = dib3000mc_read_word(state, 511);	if (irq_pending & 0x1) // failed		return 1;	if (irq_pending & 0x2) // succeeded		return 2;	return 0; // still pending}static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch){	struct dib3000mc_state *state = demod->demodulator_priv;	// ** configure demod **	dib3000mc_set_channel_cfg(state, ch, 0);	// activates isi	if (state->sfn_workaround_active) {		dprintk("SFN workaround is active\n");		dib3000mc_write_word(state, 29, 0x1273);		dib3000mc_write_word(state, 108, 0x4000); // P_pha3_force_pha_shift	} else {		dib3000mc_write_word(state, 29, 0x1073);		dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift	}	dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation);	if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) {		dib3000mc_write_word(state, 26, 38528);		dib3000mc_write_word(state, 33, 8);	} else {		dib3000mc_write_word(state, 26, 30336);		dib3000mc_write_word(state, 33, 6);	}	if (dib3000mc_read_word(state, 509) & 0x80)		dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1);	return 0;}struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating){	struct dib3000mc_state *st = demod->demodulator_priv;	return dibx000_get_i2c_adapter(&st->i2c_master, DIBX000_I2C_INTERFACE_TUNER, gating);}EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master);static int dib3000mc_get_frontend(struct dvb_frontend* fe,				struct dvb_frontend_parameters *fep){	struct dib3000mc_state *state = fe->demodulator_priv;	u16 tps = dib3000mc_read_word(state,458);	fep->inversion = INVERSION_AUTO;	fep->u.ofdm.bandwidth = state->current_bandwidth;	switch ((tps >> 8) & 0x1) {		case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;		case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;	}	switch (tps & 0x3) {		case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;		case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;		case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;		case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;	}	switch ((tps >> 13) & 0x3) {		case 0: fep->u.ofdm.constellation = QPSK; break;		case 1: fep->u.ofdm.constellation = QAM_16; break;		case 2:		default: fep->u.ofdm.constellation = QAM_64; break;	}	/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */	/* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */	fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;	switch ((tps >> 5) & 0x7) {		case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;		case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;		case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;		case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;		case 7:		default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;	}	switch ((tps >> 2) & 0x7) {		case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;		case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;		case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;		case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;		case 7:		default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;	}	return 0;}static int dib3000mc_set_frontend(struct dvb_frontend* fe,				struct dvb_frontend_parameters *fep){	struct dib3000mc_state *state = fe->demodulator_priv;    int ret;	dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);	state->current_bandwidth = fep->u.ofdm.bandwidth;	dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));	/* maybe the parameter has been changed */	state->sfn_workaround_active = buggy_sfn_workaround;	if (fe->ops.tuner_ops.set_params) {		fe->ops.tuner_ops.set_params(fe, fep);		msleep(100);	}	if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||		fep->u.ofdm.guard_interval    == GUARD_INTERVAL_AUTO ||		fep->u.ofdm.constellation     == QAM_AUTO ||		fep->u.ofdm.code_rate_HP      == FEC_AUTO) {		int i = 1000, found;		dib3000mc_autosearch_start(fe, fep);		do {			msleep(1);			found = dib3000mc_autosearch_is_irq(fe);		} while (found == 0 && i--);		dprintk("autosearch returns: %d\n",found);		if (found == 0 || found == 1)			return 0; // no channel found		dib3000mc_get_frontend(fe, fep);	}    ret = dib3000mc_tune(fe, fep);	/* make this a config parameter */	dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);    return ret;}static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat){	struct dib3000mc_state *state = fe->demodulator_priv;	u16 lock = dib3000mc_read_word(state, 509);	*stat = 0;	if (lock & 0x8000)		*stat |= FE_HAS_SIGNAL;	if (lock & 0x3000)		*stat |= FE_HAS_CARRIER;	if (lock & 0x0100)		*stat |= FE_HAS_VITERBI;	if (lock & 0x0010)		*stat |= FE_HAS_SYNC;	if (lock & 0x0008)		*stat |= FE_HAS_LOCK;	return 0;}static int dib3000mc_read_ber(struct dvb_frontend *fe, u32 *ber){	struct dib3000mc_state *state = fe->demodulator_priv;	*ber = (dib3000mc_read_word(state, 500) << 16) | dib3000mc_read_word(state, 501);	return 0;}static int dib3000mc_read_unc_blocks(struct dvb_frontend *fe, u32 *unc){	struct dib3000mc_state *state = fe->demodulator_priv;	*unc = dib3000mc_read_word(state, 508);	return 0;}static int dib3000mc_read_signal_strength(struct dvb_frontend *fe, u16 *strength){	struct dib3000mc_state *state = fe->demodulator_priv;	u16 val = dib3000mc_read_word(state, 392);	*strength = 65535 - val;	return 0;}static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr){	*snr = 0x0000;	return 0;}static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune){	tune->min_delay_ms = 1000;	return 0;}static void dib3000mc_release(struct dvb_frontend *fe){	struct dib3000mc_state *state = fe->demodulator_priv;	dibx000_exit_i2c_master(&state->i2c_master);	kfree(state);}int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff){	struct dib3000mc_state *state = fe->demodulator_priv;	dib3000mc_write_word(state, 212 + index,  onoff ? (1 << 13) | pid : 0);	return 0;}EXPORT_SYMBOL(dib3000mc_pid_control);int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff){	struct dib3000mc_state *state = fe->demodulator_priv;	u16 tmp = dib3000mc_read_word(state, 206) & ~(1 << 4);	tmp |= (onoff << 4);	return dib3000mc_write_word(state, 206, tmp);}EXPORT_SYMBOL(dib3000mc_pid_parse);void dib3000mc_set_config(struct dvb_frontend *fe, struct dib3000mc_config *cfg){	struct dib3000mc_state *state = fe->demodulator_priv;	state->cfg = cfg;}EXPORT_SYMBOL(dib3000mc_set_config);int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib3000mc_config cfg[]){	struct dib3000mc_state st = { .i2c_adap = i2c };	int k;	u8 new_addr;	static u8 DIB3000MC_I2C_ADDRESS[] = {20,22,24,26};	for (k = no_of_demods-1; k >= 0; k--) {		st.cfg = &cfg[k];		/* designated i2c address */		new_addr          = DIB3000MC_I2C_ADDRESS[k];		st.i2c_addr = new_addr;		if (dib3000mc_identify(&st) != 0) {			st.i2c_addr = default_addr;			if (dib3000mc_identify(&st) != 0) {				dprintk("-E-  DiB3000P/MC #%d: not identified\n", k);				return -ENODEV;			}		}		dib3000mc_set_output_mode(&st, OUTMODE_MPEG2_PAR_CONT_CLK);		// set new i2c address and force divstr (Bit 1) to value 0 (Bit 0)		dib3000mc_write_word(&st, 1024, (new_addr << 3) | 0x1);		st.i2c_addr = new_addr;	}	for (k = 0; k < no_of_demods; k++) {		st.cfg = &cfg[k];		st.i2c_addr = DIB3000MC_I2C_ADDRESS[k];		dib3000mc_write_word(&st, 1024, st.i2c_addr << 3);		/* turn off data output */		dib3000mc_set_output_mode(&st, OUTMODE_HIGH_Z);	}	return 0;}EXPORT_SYMBOL(dib3000mc_i2c_enumeration);static struct dvb_frontend_ops dib3000mc_ops;struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg){	struct dvb_frontend *demod;	struct dib3000mc_state *st;	st = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);	if (st == NULL)		return NULL;	st->cfg = cfg;	st->i2c_adap = i2c_adap;	st->i2c_addr = i2c_addr;	demod                   = &st->demod;	demod->demodulator_priv = st;	memcpy(&st->demod.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));	if (dib3000mc_identify(st) != 0)		goto error;	dibx000_init_i2c_master(&st->i2c_master, DIB3000MC, st->i2c_adap, st->i2c_addr);	dib3000mc_write_word(st, 1037, 0x3130);	return demod;error:	kfree(st);	return NULL;}EXPORT_SYMBOL(dib3000mc_attach);static struct dvb_frontend_ops dib3000mc_ops = {	.info = {		.name = "DiBcom 3000MC/P",		.type = FE_OFDM,		.frequency_min      = 44250000,		.frequency_max      = 867250000,		.frequency_stepsize = 62500,		.caps = FE_CAN_INVERSION_AUTO |			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |			FE_CAN_TRANSMISSION_MODE_AUTO |			FE_CAN_GUARD_INTERVAL_AUTO |			FE_CAN_RECOVER |			FE_CAN_HIERARCHY_AUTO,	},	.release              = dib3000mc_release,	.init                 = dib3000mc_init,	.sleep                = dib3000mc_sleep,	.set_frontend         = dib3000mc_set_frontend,	.get_tune_settings    = dib3000mc_fe_get_tune_settings,	.get_frontend         = dib3000mc_get_frontend,	.read_status          = dib3000mc_read_status,	.read_ber             = dib3000mc_read_ber,	.read_signal_strength = dib3000mc_read_signal_strength,	.read_snr             = dib3000mc_read_snr,	.read_ucblocks        = dib3000mc_read_unc_blocks,};MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");MODULE_DESCRIPTION("Driver for the DiBcom 3000MC/P COFDM demodulator");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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