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

📄 cx24110.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		/* set AcqVitDis bit */		if(rate[fec]>0) {			cx24110_writereg(i2c,0x05,(cx24110_readreg(i2c,0x05)&0xf0)|rate[fec]);			/* set nominal Viterbi rate */			cx24110_writereg(i2c,0x22,(cx24110_readreg(i2c,0x22)&0xf0)|rate[fec]);			/* set current Viterbi rate */			cx24110_writereg(i2c,0x1a,g1[fec]);			cx24110_writereg(i2c,0x1b,g2[fec]);			/* not sure if this is the right way: I always used AutoAcq mode */           } else		   return -EOPNOTSUPP;/* fixme (low): which is the correct return code? */        };	return 0;}static fe_code_rate_t cx24110_get_fec (struct dvb_i2c_bus *i2c){	int i;	i=cx24110_readreg(i2c,0x22)&0x0f;	if(!(i&0x08)) {		return FEC_1_2 + i - 1;	} else {/* fixme (low): a special code rate has been selected. In theory, we need to   return a denominator value, a numerator value, and a pair of puncture   maps to correctly describe this mode. But this should never happen in   practice, because it cannot be set by cx24110_get_fec. */	   return FEC_NONE;	}}static int cx24110_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate){/* fixme (low): add error handling */        u32 ratio;        u32 tmp, fclk, BDRI;        static const u32 bands[]={5000000UL,15000000UL,90999000UL/2};        static const u32 vca[]={0x80f03800,0x81f0f800,0x83f1f800};        static const u32 vga[]={0x5f8fc000,0x580f0000,0x500c0000};        static const u8  filtune[]={0xa2,0xcc,0x66};        int i;dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);        if (srate>90999000UL/2)                srate=90999000UL/2;        if (srate<500000)                srate=500000;        for(i=0;(i<sizeof(bands)/sizeof(bands[0]))&&(srate>bands[i]);i++)		;        /* first, check which sample rate is appropriate: 45, 60 80 or 90 MHz,           and set the PLL accordingly (R07[1:0] Fclk, R06[7:4] PLLmult,           R06[3:0] PLLphaseDetGain */        tmp=cx24110_readreg(i2c,0x07)&0xfc;        if(srate<90999000UL/4) { /* sample rate 45MHz*/		cx24110_writereg(i2c,0x07,tmp);		cx24110_writereg(i2c,0x06,0x78);		fclk=90999000UL/2;        } else if(srate<60666000UL/2) { /* sample rate 60MHz */		cx24110_writereg(i2c,0x07,tmp|0x1);		cx24110_writereg(i2c,0x06,0xa5);		fclk=60666000UL;        } else if(srate<80888000UL/2) { /* sample rate 80MHz */		cx24110_writereg(i2c,0x07,tmp|0x2);		cx24110_writereg(i2c,0x06,0x87);		fclk=80888000UL;        } else { /* sample rate 90MHz */		cx24110_writereg(i2c,0x07,tmp|0x3);		cx24110_writereg(i2c,0x06,0x78);		fclk=90999000UL;        };        dprintk("cx24110 debug: fclk %d Hz\n",fclk);        /* we need to divide two integers with approx. 27 bits in 32 bit           arithmetic giving a 25 bit result */        /* the maximum dividend is 90999000/2, 0x02b6446c, this number is           also the most complex divisor. Hence, the dividend has,           assuming 32bit unsigned arithmetic, 6 clear bits on top, the           divisor 2 unused bits at the bottom. Also, the quotient is           always less than 1/2. Borrowed from VES1893.c, of course */        tmp=srate<<6;        BDRI=fclk>>2;        ratio=(tmp/BDRI);        tmp=(tmp%BDRI)<<8;        ratio=(ratio<<8)+(tmp/BDRI);        tmp=(tmp%BDRI)<<8;        ratio=(ratio<<8)+(tmp/BDRI);        tmp=(tmp%BDRI)<<1;        ratio=(ratio<<1)+(tmp/BDRI);        dprintk("srate= %d (range %d, up to %d)\n", srate,i,bands[i]);        dprintk("fclk = %d\n", fclk);        dprintk("ratio= %08x\n", ratio);        cx24110_writereg(i2c, 0x1, (ratio>>16)&0xff);        cx24110_writereg(i2c, 0x2, (ratio>>8)&0xff);        cx24110_writereg(i2c, 0x3, (ratio)&0xff);        /* please see the cx24108 data sheet, this controls tuner gain           and bandwidth settings depending on the symbol rate */        cx24108_write(i2c,vga[i]);        cx24108_write(i2c,vca[i]); /* gain is set on tuner chip */        cx24110_writereg(i2c,0x56,filtune[i]); /* bw is contolled by filtune voltage */        return 0;}static int cx24110_set_voltage (struct dvb_i2c_bus *i2c, fe_sec_voltage_t voltage){	switch (voltage) {	case SEC_VOLTAGE_13:		return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&0x3b)|0xc0);	case SEC_VOLTAGE_18:		return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&0x3b)|0x40);	default:		return -EINVAL;	};}static void sendDiSEqCMessage(struct dvb_i2c_bus *i2c, struct dvb_diseqc_master_cmd *pCmd){	int i, rv;	for (i = 0; i < pCmd->msg_len; i++)		cx24110_writereg(i2c, 0x79 + i, pCmd->msg[i]);	rv = cx24110_readreg(i2c, 0x76);	cx24110_writereg(i2c, 0x76, ((rv & 0x90) | 0x40) | ((pCmd->msg_len-3) & 3));	for (i=500; i-- > 0 && !(cx24110_readreg(i2c,0x76)&0x40);)		; /* wait for LNB ready */}static int cx24110_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg){	struct dvb_i2c_bus *i2c = fe->i2c;	static int lastber=0, lastbyer=0,lastbler=0, lastesn0=0, sum_bler=0;        switch (cmd) {        case FE_GET_INFO:		memcpy (arg, &cx24110_info, sizeof(struct dvb_frontend_info));		break;        case FE_READ_STATUS:	{		fe_status_t *status = arg;		int sync = cx24110_readreg (i2c, 0x55);		*status = 0;		if (sync & 0x10)			*status |= FE_HAS_SIGNAL;		if (sync & 0x08)			*status |= FE_HAS_CARRIER;		sync = cx24110_readreg (i2c, 0x08);		if (sync & 0x40)			*status |= FE_HAS_VITERBI;		if (sync & 0x20)			*status |= FE_HAS_SYNC;		if ((sync & 0x60) == 0x60)			*status |= FE_HAS_LOCK;		if(cx24110_readreg(i2c,0x10)&0x40) {			/* the RS error counter has finished one counting window */			cx24110_writereg(i2c,0x10,0x60); /* select the byer reg */			lastbyer=cx24110_readreg(i2c,0x12)|				(cx24110_readreg(i2c,0x13)<<8)|				(cx24110_readreg(i2c,0x14)<<16);			cx24110_writereg(i2c,0x10,0x70); /* select the bler reg */			lastbler=cx24110_readreg(i2c,0x12)|				(cx24110_readreg(i2c,0x13)<<8)|				(cx24110_readreg(i2c,0x14)<<16);			cx24110_writereg(i2c,0x10,0x20); /* start new count window */			sum_bler += lastbler;		}		if(cx24110_readreg(i2c,0x24)&0x10) {			/* the Viterbi error counter has finished one counting window */			cx24110_writereg(i2c,0x24,0x04); /* select the ber reg */			lastber=cx24110_readreg(i2c,0x25)|				(cx24110_readreg(i2c,0x26)<<8);			cx24110_writereg(i2c,0x24,0x04); /* start new count window */			cx24110_writereg(i2c,0x24,0x14);		}		if(cx24110_readreg(i2c,0x6a)&0x80) {			/* the Es/N0 error counter has finished one counting window */			lastesn0=cx24110_readreg(i2c,0x69)|				(cx24110_readreg(i2c,0x68)<<8);			cx24110_writereg(i2c,0x6a,0x84); /* start new count window */		}		break;	}        case FE_READ_BER:	{		u32 *ber = (u32 *) arg;		*ber = lastber;/* fixme (maybe): value range is 16 bit. Scale? */		break;	}        case FE_READ_SIGNAL_STRENGTH:	{/* 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 (i2c, 0x27)+128;		*((u16*) arg) = (signal << 8) | signal;		break;	}        case FE_READ_SNR:	{/* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */		*(u16*) arg = lastesn0;		break;	}	case FE_READ_UNCORRECTED_BLOCKS:	{		*(u16*) arg = sum_bler&0xffff;		sum_bler=0;		break;	}        case FE_SET_FRONTEND:        {		struct dvb_frontend_parameters *p = arg;		cx24108_set_tv_freq (i2c, p->frequency);		cx24110_set_inversion (i2c, p->inversion);		cx24110_set_fec (i2c, p->u.qpsk.fec_inner);		cx24110_set_symbolrate (i2c, p->u.qpsk.symbol_rate);		cx24110_writereg(i2c,0x04,0x05); /* start aquisition */                break;        }	case FE_GET_FRONTEND:	{		struct dvb_frontend_parameters *p = arg;		s32 afc; unsigned sclk;/* cannot read back tuner settings (freq). Need to have some private storage */		sclk = cx24110_readreg (i2c, 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 (i2c, 0x44)&0x1f)+		      ((sclk*cx24110_readreg (i2c, 0x45))>>8)+		      ((sclk*cx24110_readreg (i2c, 0x46))>>16);		p->frequency += afc;		p->inversion = (cx24110_readreg (i2c, 0x22) & 0x10) ?					INVERSION_ON : INVERSION_OFF;		p->u.qpsk.fec_inner = cx24110_get_fec (i2c);		break;	}        case FE_SLEEP:/* cannot do this from the FE end. How to communicate this to the place where it can be done? */		break;        case FE_INIT:		return cx24110_init (i2c);	case FE_SET_TONE:		return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&~0x10)|((((fe_sec_tone_mode_t) arg)==SEC_TONE_ON)?0x10:0));	case FE_SET_VOLTAGE:		return cx24110_set_voltage (i2c, (fe_sec_voltage_t) arg);	case FE_DISEQC_SEND_MASTER_CMD:		sendDiSEqCMessage(i2c, (struct dvb_diseqc_master_cmd*) arg);		return 0;	default:		return -EOPNOTSUPP;        };        return 0;}static int cx24110_attach (struct dvb_i2c_bus *i2c, void **data){	u8 sig;	sig=cx24110_readreg (i2c, 0x00);	if ( sig != 0x5a && sig != 0x69 )		return -ENODEV;	return dvb_register_frontend (cx24110_ioctl, i2c, NULL, &cx24110_info);}static void cx24110_detach (struct dvb_i2c_bus *i2c, void *data){	dvb_unregister_frontend (cx24110_ioctl, i2c);}static int __init init_cx24110 (void){	return dvb_register_i2c_device (THIS_MODULE, cx24110_attach, cx24110_detach);}static void __exit exit_cx24110 (void){	dvb_unregister_i2c_device (cx24110_attach);}module_init(init_cx24110);module_exit(exit_cx24110);MODULE_DESCRIPTION("DVB Frontend driver module for the Conexant cx24108/cx24110 chipset");MODULE_AUTHOR("Peter Hettkamp");MODULE_LICENSE("GPL");MODULE_PARM(debug,"i");

⌨️ 快捷键说明

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