📄 mx21_pmp_fm.c
字号:
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 + -