📄 mx21_pmp_fm.c
字号:
/************************************************************************ * File Name : tea5767hn.c * Description : * Implementation of fm driver * History : * 14-Sep-04 Aaron Shen New * 12-Oct-2004 Gary Gao Modify ************************************************************************ */#include <linux/kernel.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/init.h>#include <asm/uaccess.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/fs.h>#include <linux/mm.h>#include <linux/miscdevice.h>#include <linux/pm.h>#include <linux/types.h>#include <linux/i2c.h>#include <asm/arch/apmc.h>#include "asm/arch/mx2.h"#include "asm/arch/platform.h"#define TEA5767HN_IOC_TEST_I2CRW 12 #define TEA5767HN_IOC_SET_BAND 14 #define TEA5767HN_IOC_STEP_SEARCH_UP 16#define TEA5767HN_IOC_STANDBY 17 /*********************************************************************** * HARDWARE SPECIFIC *********************************************************************** *///Write byte 1#define BIT_MUTE 0x80#define BIT_SM 0x40#define BIT_HIGH_PLL 0x3F //Also used for read mode//Write byte 2#define BIT_LOW_PLL 0xFF //Also used for read mode//Write byte 3#define BIT_SUD 0x80#define BIT_SSL 0x60#define BIT_HLSI 0x10#define BIT_MUTE_STEREO 0x08#define BIT_MUTE_LEFT 0x04#define BIT_MUTE_RIGHT 0x02#define BIT_SWP1 0x01//Write byte 4#define BIT_SWP2 0x80#define BIT_STANDBY 0x40#define BIT_BAND_LIMIT 0x20 // BL=1 then Japanese FM band, =0 then US/Europe FM band, We use US/Europe FM band.#define BIT_XTAL 0x10#define BIT_SMUTE 0x08 // Soft Mute#define BIT_HCC 0x04 // High cut control#define BIT_SNC 0x02 // Stereo noise canceling#define BIT_SI 0x01 // Search Indicator//Write byte 5#define BIT_PLLREF 0x80#define BIT_DTC 0x40//Read byte 1#define BIT_READY_FLAG 0x80#define BIT_BAND_LIMIT_FLAG 0x40//Read byte 3#define BIT_STEREO 0x80#define BIT_IF_COUNTER 0x7F//Read byte 4#define BIT_LEV 0xF0#define BIT_CI 0x0E#define REFERENCE_FREQ 32768#define FM_MINOR 18#define STOP_LEVEL_LOW 1#define STOP_LEVEL_MID 2#define STOP_LEVEL_HIGH 3//#define HLSI_LOW 0//global staticstatic u8 g_tea5767hn_busy = 0; static struct pm_dev *pmdev;static struct apmc_user *g_tea5767hn_apmc;static u8 val[5];static int tea5767hn_open(struct inode *inode, struct file *filp);static int tea5767hn_release(struct inode *inode, struct file *filp);static int tea5767hn_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static int tea5767hn_pm_handler(struct pm_dev *pmdev, pm_request_t rqst, void *data);static void tea5767hn_hw_init(void);static void tea5767hn_hw_cleanup(void);static void stop_search(void);static u32 make_display_freq(u32 freq); static u32 step_search_level_up(u32 freq, u8 level); static u32 step_search_station_up(u32 preset_freq); static int tea5767hn_reach_band_limit(void);static int tea5767hn_station_detected(void);static void tea5767hn_calculate_pll(u8 *tPLL, u32 freq);static u32 tea5767hn_calculate_frequency(u8 *tPLL);static u32 tea5767hn_search_next_up(u32 preset, u8 flag); static void tea5767hn_hard_standby_control(u8 flag);/************************************************************************ * * i2c related * ************************************************************************///The address of the TEA5767 on I2c BUS#define I2C_ADDR_TEA5767HN 0xc0//Define the ID, Need new value, Aaron#define I2C_DRIVERID_I2C_TEA5767HN 0xF000#define I2C_M_READ 0x02 #define I2C_M_WRITE 0x04 #define I2C_NEED_ACK 0x0100static int i2c_fm_write (u8 *data);static int i2c_fm_read (u8 *data);static int i2c_fm_attach_adapter (struct i2c_adapter * adap);static struct i2c_driver i2c_fm_driver = { name: "i2c-fm client driver", id: I2C_DRIVERID_I2C_TEA5767HN, flags: I2C_DF_DUMMY | I2C_DF_NOTIFY, attach_adapter: i2c_fm_attach_adapter, detach_client: NULL, /*i2c_fm_detach_client,*/ command: NULL};static struct i2c_client i2c_fm_client = { name: "i2c-fm client", id: 1, flags: 0, addr: -1, adapter: NULL, driver: &i2c_fm_driver, data: NULL};/** *@brief This function is called when the associated driver is to install to the I2C system. * It shall check whether it can handle the adapter. * *@param adap point to the adapter structure * *@return @li 0 Success * @li -1 Failure */static int i2c_fm_attach_adapter (struct i2c_adapter * adap){ /* find out the adapter for the I2C module in the DBMX21*/ if (memcmp(adap->name, "DBMX I2C Adapter", 16) != 0 ) return -ENODEV; /* store the adapter to the client driver */ i2c_fm_client.adapter = adap; return 0;}/** *@brief This function initializes the I2C client driver * It is called when the module is being loaded to the system * *@return @li 0 Success * @li -1 Failure */static void i2c_fm_init (void){ /* * set the address of the FM radio to the client */ i2c_fm_client.addr = I2C_ADDR_TEA5767HN; /* * call the i2c_add_driver() to register the driver to the Linux I2C system */ if ((i2c_add_driver( &i2c_fm_driver ))) { printk("I2C addr driver failed\n"); return; } /* * attach the client to the adapter by calling the i2c_attach_client() * function of the Linux I2C system */ if ((i2c_attach_client(&i2c_fm_client )) != 0 ) { printk("I2C attach client failed\n"); i2c_del_driver(&i2c_fm_driver); return; }}/** *@brief This function is to read the data from the I2C slave through the I2C bus. * Before the access to the I2C bus, the driver should be opened first. * *@param data the buffer to store the data *@param reg the register number in the I2C slave (SSI sensor) * *@return @li number of byte received Success * @li -1 Failure */static int i2c_fm_read(u8 *data){ struct i2c_msg msg; char buf[5]; int i, ret; for (i=0; i<5; i++) buf[i]=0; //initialize the message structure msg.addr = 0xc1; //i2c_fm_client.addr; msg.flags = I2C_M_READ | I2C_NEED_ACK; msg.len = 5; msg.buf = buf; ret = i2c_transfer( i2c_fm_client.adapter, &msg, 1 ); for (i=0; i<5; i++) *data++ = buf[i]; //*p++ = buf[i]; return ret;}/** *@brief This function is to write the data to the I2C slave through the I2C bus. * Before the access to the I2C bus, the driver should be opened first. * *@param data the buffer to store the data *@param reg the register number in the I2C slave (FM) * *@return @li number of byte received Success * @li -1 Failure */static int i2c_fm_write (u8 *data){ struct i2c_msg msg; char buf[5]; int i, ret; /* * store the register value to the first address of the buffer * the adapter/algorithm driver will regard the first byte * as the register value */ for(i=0;i<5;i++) buf[i] = *data++; //initialize the message structure msg.addr = i2c_fm_client.addr; msg.flags = I2C_M_WRITE | I2C_NEED_ACK; msg.len = 5; msg.buf = buf; ret = i2c_transfer( i2c_fm_client.adapter, &msg, 1 ); return ret;}/*----------------------------------------------------------------------- * SINT16 i2c_fm_cleanup( void ) * This routine is called when the driver is uninstalled. * * Parameters : * None * Return : * Success 0 * Failure -1 *----------------------------------------------------------------------*/static void i2c_fm_cleanup(void){ /* * detach the client to the adapter */ i2c_detach_client(&i2c_fm_client); /* * deregister the driver from the Linux I2C system */ i2c_del_driver(&i2c_fm_driver);}static int tea5767hn_reach_band_limit(void){ u8 bl_val[5]; int i; for(i=0; i<5; i++) bl_val[i]=0; i2c_fm_read(bl_val); if(bl_val[0] & BIT_BAND_LIMIT_FLAG) //band limit has been reached { //printk("reach band_limit! \n"); return 1; } else return 0;}static int tea5767hn_station_detected(void){ u8 local_val[5]; int i; for(i=0; i<5; i++) local_val[i]=0; i2c_fm_read(local_val); if( local_val[0] & BIT_READY_FLAG ) //a station has been found { //printk("station detected! \n"); return 1; } else return 0;}static void tea5767hn_calculate_pll(u8 *tPLL, u32 freq) { u32 twPLL =0; //Dec u8 tbTmp1; u8 tbTmp2; // calcu1ate frequency dataword bits from given station frequency BCD: twPLL = (u32)(((freq-225)*4*1000)/REFERENCE_FREQ); //convert word to byte f. tbTmp1 =(u8)(twPLL%256); //6789=Hex1A85 -->133=Hex85
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -