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

📄 cx24110.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	/* write the topmost 8 bits */	cx24110_writereg(state,0x72,(data>>24)&0xff);	/* wait for the send to be completed */	while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)		;	/* send another 8 bytes */	cx24110_writereg(state,0x72,(data>>16)&0xff);	while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)		;	/* and the topmost 5 bits of this byte */	cx24110_writereg(state,0x72,(data>>8)&0xff);	while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)		;	/* now strobe the enable line once */	cx24110_writereg(state,0x6d,0x32);	cx24110_writereg(state,0x6d,0x30);	return 0;}static int cx24110_initfe(struct dvb_frontend* fe){	struct cx24110_state *state = fe->demodulator_priv;/* fixme (low): error handling */	int i;	dprintk("%s: init chip\n", __FUNCTION__);	for(i=0;i<sizeof(cx24110_regdata)/sizeof(cx24110_regdata[0]);i++) {		cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);	};	if (state->config->pll_init) state->config->pll_init(fe);	return 0;}static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage){	struct cx24110_state *state = fe->demodulator_priv;	switch (voltage) {	case SEC_VOLTAGE_13:		return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0xc0);	case SEC_VOLTAGE_18:		return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0x40);	default:		return -EINVAL;	};}static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst){	int rv, bit;	struct cx24110_state *state = fe->demodulator_priv;	unsigned long timeout;	if (burst == SEC_MINI_A)		bit = 0x00;	else if (burst == SEC_MINI_B)		bit = 0x08;	else		return -EINVAL;	rv = cx24110_readreg(state, 0x77);	if (!(rv & 0x04))		cx24110_writereg(state, 0x77, rv | 0x04);	rv = cx24110_readreg(state, 0x76);	cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40 | bit));	timeout = jiffies + msecs_to_jiffies(100);	while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40))		; /* wait for LNB ready */	return 0;}static int cx24110_send_diseqc_msg(struct dvb_frontend* fe,				   struct dvb_diseqc_master_cmd *cmd){	int i, rv;	struct cx24110_state *state = fe->demodulator_priv;	unsigned long timeout;	for (i = 0; i < cmd->msg_len; i++)		cx24110_writereg(state, 0x79 + i, cmd->msg[i]);	rv = cx24110_readreg(state, 0x77);	if (rv & 0x04) {		cx24110_writereg(state, 0x77, rv & ~0x04);		msleep(30); /* reportedly fixes switching problems */	}	rv = cx24110_readreg(state, 0x76);	cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3));	timeout = jiffies + msecs_to_jiffies(100);	while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40))		; /* wait for LNB ready */	return 0;}static int cx24110_read_status(struct dvb_frontend* fe, fe_status_t* status){	struct cx24110_state *state = fe->demodulator_priv;	int sync = cx24110_readreg (state, 0x55);	*status = 0;	if (sync & 0x10)		*status |= FE_HAS_SIGNAL;	if (sync & 0x08)		*status |= FE_HAS_CARRIER;	sync = cx24110_readreg (state, 0x08);	if (sync & 0x40)		*status |= FE_HAS_VITERBI;	if (sync & 0x20)		*status |= FE_HAS_SYNC;	if ((sync & 0x60) == 0x60)		*status |= FE_HAS_LOCK;	return 0;}static int cx24110_read_ber(struct dvb_frontend* fe, u32* ber){	struct cx24110_state *state = fe->demodulator_priv;	/* fixme (maybe): value range is 16 bit. Scale? */	if(cx24110_readreg(state,0x24)&0x10) {		/* the Viterbi error counter has finished one counting window */		cx24110_writereg(state,0x24,0x04); /* select the ber reg */		state->lastber=cx24110_readreg(state,0x25)|			(cx24110_readreg(state,0x26)<<8);		cx24110_writereg(state,0x24,0x04); /* start new count window */		cx24110_writereg(state,0x24,0x14);	}	*ber = state->lastber;	return 0;}static int cx24110_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength){	struct cx24110_state *state = fe->demodulator_priv;/* no provision in hardware. Read the frontend AGC accumulator. No idea how to scale this, but I know it is 2s complement */	u8 signal = cx24110_readreg (state, 0x27)+128;	*signal_strength = (signal << 8) | signal;	return 0;}static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr){	struct cx24110_state *state = fe->demodulator_priv;	/* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */	if(cx24110_readreg(state,0x6a)&0x80) {		/* the Es/N0 error counter has finished one counting window */		state->lastesn0=cx24110_readreg(state,0x69)|			(cx24110_readreg(state,0x68)<<8);		cx24110_writereg(state,0x6a,0x84); /* start new count window */	}	*snr = state->lastesn0;	return 0;}static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks){	struct cx24110_state *state = fe->demodulator_priv;	u32 lastbyer;	if(cx24110_readreg(state,0x10)&0x40) {		/* the RS error counter has finished one counting window */		cx24110_writereg(state,0x10,0x60); /* select the byer reg */		lastbyer=cx24110_readreg(state,0x12)|			(cx24110_readreg(state,0x13)<<8)|			(cx24110_readreg(state,0x14)<<16);		cx24110_writereg(state,0x10,0x70); /* select the bler reg */		state->lastbler=cx24110_readreg(state,0x12)|			(cx24110_readreg(state,0x13)<<8)|			(cx24110_readreg(state,0x14)<<16);		cx24110_writereg(state,0x10,0x20); /* start new count window */	}	*ucblocks = state->lastbler;	return 0;}static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p){	struct cx24110_state *state = fe->demodulator_priv;	state->config->pll_set(fe, p);	cx24110_set_inversion (state, p->inversion);	cx24110_set_fec (state, p->u.qpsk.fec_inner);	cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate);	cx24110_writereg(state,0x04,0x05); /* start aquisition */	return 0;}static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p){	struct cx24110_state *state = fe->demodulator_priv;	s32 afc; unsigned sclk;/* cannot read back tuner settings (freq). Need to have some private storage */	sclk = cx24110_readreg (state, 0x07) & 0x03;/* ok, real AFC (FEDR) freq. is afc/2^24*fsamp, fsamp=45/60/80/90MHz. * Need 64 bit arithmetic. Is thiss possible in the kernel? */	if (sclk==0) sclk=90999000L/2L;	else if (sclk==1) sclk=60666000L;	else if (sclk==2) sclk=80888000L;	else sclk=90999000L;	sclk>>=8;	afc = sclk*(cx24110_readreg (state, 0x44)&0x1f)+	      ((sclk*cx24110_readreg (state, 0x45))>>8)+	      ((sclk*cx24110_readreg (state, 0x46))>>16);	p->frequency += afc;	p->inversion = (cx24110_readreg (state, 0x22) & 0x10) ?				INVERSION_ON : INVERSION_OFF;	p->u.qpsk.fec_inner = cx24110_get_fec (state);	return 0;}static int cx24110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone){	struct cx24110_state *state = fe->demodulator_priv;	return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&~0x10)|(((tone==SEC_TONE_ON))?0x10:0));}static void cx24110_release(struct dvb_frontend* fe){	struct cx24110_state* state = fe->demodulator_priv;	kfree(state);}static struct dvb_frontend_ops cx24110_ops;struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,				    struct i2c_adapter* i2c){	struct cx24110_state* state = NULL;	int ret;	/* allocate memory for the internal state */	state = kmalloc(sizeof(struct cx24110_state), GFP_KERNEL);	if (state == NULL) goto error;	/* setup the state */	state->config = config;	state->i2c = i2c;	memcpy(&state->ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));	state->lastber = 0;	state->lastbler = 0;	state->lastesn0 = 0;	/* check if the demod is there */	ret = cx24110_readreg(state, 0x00);	if ((ret != 0x5a) && (ret != 0x69)) goto error;	/* create dvb_frontend */	state->frontend.ops = &state->ops;	state->frontend.demodulator_priv = state;	return &state->frontend;error:	kfree(state);	return NULL;}static struct dvb_frontend_ops cx24110_ops = {	.info = {		.name = "Conexant CX24110 DVB-S",		.type = FE_QPSK,		.frequency_min = 950000,		.frequency_max = 2150000,		.frequency_stepsize = 1011,  /* kHz for QPSK frontends */		.frequency_tolerance = 29500,		.symbol_rate_min = 1000000,		.symbol_rate_max = 45000000,		.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_RECOVER	},	.release = cx24110_release,	.init = cx24110_initfe,	.set_frontend = cx24110_set_frontend,	.get_frontend = cx24110_get_frontend,	.read_status = cx24110_read_status,	.read_ber = cx24110_read_ber,	.read_signal_strength = cx24110_read_signal_strength,	.read_snr = cx24110_read_snr,	.read_ucblocks = cx24110_read_ucblocks,	.diseqc_send_master_cmd = cx24110_send_diseqc_msg,	.set_tone = cx24110_set_tone,	.set_voltage = cx24110_set_voltage,	.diseqc_send_burst = cx24110_diseqc_send_burst,};module_param(debug, int, 0644);MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");MODULE_DESCRIPTION("Conexant CX24110 DVB-S Demodulator driver");MODULE_AUTHOR("Peter Hettkamp");MODULE_LICENSE("GPL");EXPORT_SYMBOL(cx24110_attach);EXPORT_SYMBOL(cx24110_pll_write);

⌨️ 快捷键说明

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