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

📄 mx21_pmp_fm.c

📁 调频收音芯片TEA5767在mx21上的linux驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	tbTmp2 =(u8)(twPLL/256);	//             -->26=Hex1A	*tPLL = tbTmp2;	//high block	*(tPLL+1) = tbTmp1;	return;}static u32 tea5767hn_calculate_frequency(u8 *tPLL) {	u32	twPLL =0;		//Dec 	u8 tbTmp1 = tPLL[1];	u8 tbTmp2 = tPLL[0];	u32 freq2;	u32 temp;	tbTmp2 &= 0x3f;	twPLL = tbTmp2*256 + tbTmp1;	// calculate searched station frequency from dataword bits 	temp = (twPLL*REFERENCE_FREQ)/4000;	freq2 = temp+225;	return freq2;} static u32 tea5767hn_search_next_up(u32 preset, u8 flag){	u8 read_val[5];	u8 sPLL[2];	u32 freq=0;	u32 level1, level2;	u8 IFC;         //IF counter result	int i;	if((preset < 87500) || (preset > 108000))		return 0;		for(i=0;i<5;i++)	      read_val[i] = 0;	tea5767hn_calculate_pll(sPLL, preset);   	val[0] = sPLL[0];	   //bit 13~8 of PLL	val[0] |= (BIT_SM | BIT_MUTE);	   //set search mode, audio channel mute.		val[1] = sPLL[1];	   //bit 7~0 of PLL	val[2] &= ~BIT_HLSI;	//High side LO injection: 1: Search down;  Low side LO injection: 0: Search up	val[2] |= BIT_SUD;   //search up: 1;  search down: 0;	val[2] |= (flag << 5);	i2c_fm_write(val);		while(!tea5767hn_reach_band_limit() && !tea5767hn_station_detected());		mdelay(30);  //need delay before read		//add code to permit reach band limit twice, to optimise	if(!tea5767hn_reach_band_limit() && tea5767hn_station_detected()) {	//a station detected		//Calculate the tuned frequency after a search stop		i2c_fm_read(read_val);				sPLL[1] = read_val[1];   		sPLL[0] = (read_val[0] & 0x3F);  		freq = tea5767hn_calculate_frequency(sPLL);  	 		//check_freq_valid();   //by check HILO		level1 = freq;		val[2] |= BIT_HLSI;		i2c_fm_write(val);		mdelay(30);		i2c_fm_read(read_val);				sPLL[1] = read_val[1];    		sPLL[0] = (read_val[0] & 0x3F);  		level2 = tea5767hn_calculate_frequency(sPLL);		IFC = (read_val[2] & 0x7f);		//printk("before level1 = %d, level2 = %d, IFC = 0x%x. \n", level1, level2, IFC );		if (((level1 - level2) < 2) && (IFC > 0x31) && (IFC < 0x3e)) {			printk("level1 = %d, level2 = %d, IFC = 0x%x. \n", level1, level2, IFC );			return freq;		}		else 			return 0;	}		return 0;} static void tea5767hn_hard_standby_control(u8 flag){	if(flag)		tea5767hn_hw_cleanup();	else             tea5767hn_hw_init();		return;}static int tea5767hn_open(struct inode *inode, struct file *filp){	tea5767hn_hw_init();	MOD_INC_USE_COUNT;	return 0;}static int tea5767hn_release(struct inode *inode, struct file *filp){      MOD_DEC_USE_COUNT;	return 0;	}static int tea5767hn_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){	switch(cmd) {		      	case TEA5767HN_IOC_TEST_I2CRW:	  	test_i2c_rw();               break; 	      	case TEA5767HN_IOC_STEP_SEARCH_UP:		return step_search_station_up(arg); 			case TEA5767HN_IOC_SET_BAND:		set_searched_station(arg);		break;			case TEA5767HN_IOC_STANDBY:		tea5767hn_hard_standby_control((u8)arg);		break;	default:		return -1;	}	return 0;}static void stop_search(void){	val[0] &= ~BIT_MUTE;	//unmute audio output	val[0] &= ~BIT_SM;    //not search	val[2] &= ~BIT_MUTE_LEFT;      // both audio channel are not muted	val[2] &= ~BIT_MUTE_RIGHT;		val[2] &= ~BIT_SSL;		i2c_fm_write(val);} void set_searched_station(u32 freq){	u8 sPLL[2];	tea5767hn_calculate_pll(sPLL, freq);	val[0] = sPLL[0];	//bit 13~8 of PLL	val[0] &= 0x3f;	//set not search, unmute audio output	val[1] = sPLL[1];	//bit 7~0 of PLL	val[2] = 0x48;  //HLSI=0,SSL=01,	val[3] = 0x17;	val[4] = 0x00;	i2c_fm_write(val);	return;}void test_i2c_rw(void){      u8 datain[5];	int i;		val[0]=0x31;   	val[1]=0xDD;  	val[2]=0x48;  //HLSI=0,SSL=01,	val[3]=0x17;	val[4]=0x00;		i2c_fm_write(val);	mdelay(30);	i2c_fm_read(datain);	for(i=0;i<5;i++)	     printk("Write Datas[%d] = 0x%02X\n", i, val[i]);              for(i=0;i<5;i++)	     printk("Read Data2[%d] = 0x%02X\n", i, datain[i]);      }static u32 make_display_freq(u32 freq)   //get frequency to display{      u32 u1, u2;	u1 = freq/100;	u2 = freq%100;	if ((u2 > 75) && (u2 < 100)) {	      u2 = 0;		u1 += 1;	} else if ((u2 > 25) && (u2 < 76))             u2 = 50;	else if ((u2 > 0) && (u2 < 26))             u2 = 0;	return (u1*100 + u2);}  static u32 step_search_level_up(u32 freq, u8 level){	u32 search_freq = 0;	u32 count = 0;	while (!tea5767hn_reach_band_limit()) {	      if(((freq + (count*50)) < 108001) && ((freq + (count*50)) > 87499)) {  //FM 87.5 MHz ~ 108.0 MHz			search_freq = tea5767hn_search_next_up((freq + count*50), level);			count++;			if (search_freq > 0) {			    freq = search_freq;			    stop_search();			    return make_display_freq(search_freq);			}	      	}	}	stop_search();	return 0;} static u32 step_search_station_up(u32 preset_freq){      u32 freq;	stop_search();	freq = step_search_level_up(preset_freq, STOP_LEVEL_HIGH) ;		if (freq == 0) {	      printk("no found in high stop level \n");	      freq = step_search_level_up(preset_freq, STOP_LEVEL_MID);		if ( freq == 0) {		      printk("no found in middle stop level \n");		      freq = step_search_level_up(preset_freq, STOP_LEVEL_LOW);			if ( freq == 0)				return 0;			else				return freq;		} else			return freq;	} else		return freq;}static int tea5767hn_pm_handler(struct pm_dev *pmdev, pm_request_t rqst, void *data){	switch (rqst) {	case PM_SUSPEND:		if(g_tea5767hn_busy)			return 1;      //does not allow suspend when i2c bus is running and configuring the sensor		else {			tea5767hn_hard_standby_control(1);     //put FM into standby mode by gpio			printk("tea5767hn suspend\n");		}		break;			case PM_RESUME:		tea5767hn_hard_standby_control(0);		printk("tea5767hn resume\n");		break;	}	return 0;}static void tea5767hn_hw_init(void){	_reg_GPIO_GIUS(GPIOB) |= 0x80;       // PB7 config for GPIO function.       _reg_GPIO_DDIR(GPIOB) |= 0x80;       // PB7 config for output.       _reg_GPIO_OCR1(GPIOB) |= 0x0000c000;      // PB7 config for data register, controlled by us with Data Register.       _reg_GPIO_DR(GPIOB) |= 0x80;         //TEA5767HN bus enable       _reg_GPIO_PUEN(GPIOB) |= 0x80;     //PB7 Pull up high	return;}static void tea5767hn_hw_cleanup(void){       _reg_GPIO_DR(GPIOB) &= ~0x80;   //TEA5767HN bus disable	return;}struct file_operations tea5767hn_fops = {	open:		tea5767hn_open,	release:	      tea5767hn_release,	ioctl:		tea5767hn_ioctl,};static struct miscdevice tea5767_dev={      FM_MINOR,	"tea5767hn",	&tea5767hn_fops};static int __init tea5767hn_init(){      int i;      int result;	  	printk("FM Radio TEA5767HN driver for i.MX21, Gary. \n");		i2c_fm_init();      result = misc_register(&tea5767_dev);   //register character device      if( result < 0 ) {		printk("FM Radio TEA5767hn failed to register the device. \n");		return result;	}  	g_tea5767hn_busy = 0;	//power management	pmdev = pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, tea5767hn_pm_handler);	if (pmdev == NULL)	{		printk("tea5767hn error: failed to register PM... continuing with driver init\n");	}	g_tea5767hn_apmc = apmc_register(APMC_LEVEL_HIGHEST);	val[0]=0x31;   //104.8 MHz	val[1]=0xDD;  	val[2]=0x48;  //HLSI=0,SSL=01,	val[3]=0x17;	val[4]=0x00;	return 0;}static void __exit tea5767hn_cleanup(){	i2c_fm_cleanup();	apmc_unregister(g_tea5767hn_apmc);	pm_unregister(pmdev);	misc_deregister(&tea5767_dev);	printk("Tea5767hn driver unloaded sucessfully\n");	return;}module_init(tea5767hn_init);module_exit(tea5767hn_cleanup);

⌨️ 快捷键说明

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