diff options
Diffstat (limited to 'drivers/media/radio/si4709/radio-si4709_dev.c')
-rw-r--r-- | drivers/media/radio/si4709/radio-si4709_dev.c | 2563 |
1 files changed, 2563 insertions, 0 deletions
diff --git a/drivers/media/radio/si4709/radio-si4709_dev.c b/drivers/media/radio/si4709/radio-si4709_dev.c new file mode 100644 index 0000000..6a65da9 --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_dev.c @@ -0,0 +1,2563 @@ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/time.h> +#include <linux/workqueue.h> + +#include <mach/gpio.h> +#include <plat/gpio-cfg.h> +#include <../../../arch/arm/mach-s5pv210/include/mach/gpio-aries.h> + +#include "radio-si4709_regs.h" +#include "radio-si4709_main.h" +#include "radio-si4709_dev.h" +#include "radio-si4709_common.h" + +enum +{ + eTRUE, + eFALSE, +}dev_struct_status_t; + +/*dev_state*/ +/*power_state*/ +#define RADIO_ON 1 +#define RADIO_POWERDOWN 0 +/*seek_state*/ +#define RADIO_SEEK_ON 1 +#define RADIO_SEEK_OFF 0 + +#define FREQ_87500_kHz 8750 +#define FREQ_76000_kHz 7600 + +#define RSSI_seek_th_MAX 0x7F +#define RSSI_seek_th_MIN 0x00 + +#define seek_SNR_th_DISB 0x00 +#define seek_SNR_th_MIN 0x01 /*most stops*/ +#define seek_SNR_th_MAX 0x0F /*fewest stops*/ + +#define seek_FM_ID_th_DISB 0x00 +#define seek_FM_ID_th_MAX 0x01 /*most stops*/ +#define seek_FM_ID_th_MIN 0x0F /*fewest stops*/ + +#define TUNE_RSSI_THRESHOLD 0x00 +#define TUNE_SNR_THRESHOLD 0x01 +#define TUNE_CNT_THRESHOLD 0x00 + +typedef struct +{ + u32 frequency; + u8 rsssi_val; +}channel_into_t; + +typedef struct +{ + u16 band; + u32 bottom_of_band; + u16 channel_spacing; + u32 timeout_RDS; /****For storing the jiffy value****/ + u32 seek_preset[NUM_SEEK_PRESETS]; + u8 curr_snr; + u8 curr_rssi_th; +}dev_settings_t; + +typedef struct +{ + /*Any function which + - views/modifies the fields of this structure + - does i2c communication + should lock the mutex before doing so. + Recursive locking should not be done. + In this file all the exported functions will take care + of this. The static functions will not deal with the + mutex*/ + struct mutex lock; + + struct i2c_client const *client; + + dev_state_t state; + + dev_settings_t settings; + + channel_into_t rssi_freq[50]; + + u16 registers[NUM_OF_REGISTERS]; + + /* This field will be checked by all the functions + exported by this file (except the init function), + to validate the the fields of this structure. + if eTRUE: the fileds are valid + if eFALSE: do not trust the values of the fields + of this structure*/ + unsigned short valid; + + /*will be true is the client ans state fields are correct*/ + unsigned short valid_client_state; +}Si4709_device_t; + + +/*extern functions*/ +/**********************************************/ +/*All the exported functions which view or modify the device + state/data, do i2c com will have to lock the mutex before + doing so*/ +/**********************************************/ +int Si4709_dev_init(struct i2c_client *); +int Si4709_dev_exit(void); + +void Si4709_dev_mutex_init(void); + +int Si4709_dev_suspend(void); +int Si4709_dev_resume(void); + +int Si4709_dev_powerup(void); +int Si4709_dev_powerdown(void); + +int Si4709_dev_band_set(int); +int Si4709_dev_ch_spacing_set(int); + +int Si4709_dev_chan_select(u32); +int Si4709_dev_chan_get(u32*); + +int Si4709_dev_seek_up(u32*); +int Si4709_dev_seek_down(u32*); +int Si4709_dev_seek_auto(u32*); + +int Si4709_dev_RSSI_seek_th_set(u8); +int Si4709_dev_seek_SNR_th_set(u8); +int Si4709_dev_seek_FM_ID_th_set(u8); +int Si4709_dev_cur_RSSI_get(rssi_snr_t*); +int Si4709_dev_VOLEXT_ENB(void); +int Si4709_dev_VOLEXT_DISB(void); +int Si4709_dev_volume_set(u8); +int Si4709_dev_volume_get(u8 *); +int Si4709_dev_DSMUTE_ON(void); +int Si4709_dev_DSMUTE_OFF(void); +int Si4709_dev_MUTE_ON(void); +int Si4709_dev_MUTE_OFF(void); +int Si4709_dev_MONO_SET(void); +int Si4709_dev_STEREO_SET(void); +int Si4709_dev_RDS_ENABLE(void); +int Si4709_dev_RDS_DISABLE(void); +int Si4709_dev_RDS_timeout_set(u32); +int Si4709_dev_rstate_get(dev_state_t*); +int Si4709_dev_RDS_data_get(radio_data_t*); +int Si4709_dev_device_id(device_id *); +int Si4709_dev_chip_id(chip_id *); +int Si4709_dev_sys_config2(sys_config2 *); +int Si4709_dev_power_config(power_config *); +int Si4709_dev_AFCRL_get(u8*); +int Si4709_dev_DE_set(u8); +/***********************************************/ + +#ifdef RDS_INTERRUPT_ON_ALWAYS +#define RDS_BUFFER_LENGTH 50 +static u16 *RDS_Block_Data_buffer; +static u8 *RDS_Block_Error_buffer; +static u8 RDS_Buffer_Index_read; //index number for last read data +static u8 RDS_Buffer_Index_write; //index number for last written data + +int Si4709_RDS_flag; +int RDS_Data_Available; +int RDS_Data_Lost; +int RDS_Groups_Available_till_now; +struct workqueue_struct *Si4709_wq; +struct work_struct Si4709_work; +#endif + +/*static functions*/ +/**********************************************/ +static void wait(void); + +static void wait_RDS(void ); + +static int powerup(void); +static int powerdown(void); + +static int seek(u32*, int); +static int tune_freq(u32); + +static void get_cur_chan_freq(u32 *, u16); + +static u16 freq_to_channel(u32); +static u32 channel_to_freq(u16); + +static int insert_preset(u32,u8,u8*); + +static int i2c_read(u8); +static int i2c_write(u8); +/**********************************************/ + +/*Si4709 device structure*/ +static Si4709_device_t Si4709_dev = +{ + .client = NULL, + .valid = eFALSE, + .valid_client_state = eFALSE, +}; + +/*Wait flag*/ +/*WAITING or WAIT_OVER or NO_WAIT*/ +int Si4709_dev_wait_flag = NO_WAIT; +#ifdef RDS_INTERRUPT_ON_ALWAYS +int Si4709_RDS_flag = NO_WAIT; +#endif + +int Si4709_dev_init(struct i2c_client *client) +{ + int ret = 0; + + debug("Si4709_dev_init called"); + + mutex_lock(&(Si4709_dev.lock)); + + Si4709_dev.client = client; + + /***reset the device here****/ + gpio_set_value(FM_RESET, GPIO_LEVEL_LOW); + mdelay(1); + gpio_set_value(FM_RESET, GPIO_LEVEL_HIGH); + mdelay(2); + + s3c_gpio_setpull(GPIO_FM_INT, S3C_GPIO_PULL_UP); + s3c_gpio_slp_setpull_updown(GPIO_FM_INT, S3C_GPIO_PULL_UP); + + Si4709_dev.state.power_state = RADIO_POWERDOWN; + Si4709_dev.state.seek_state = RADIO_SEEK_OFF; + + if( (ret = i2c_read(BOOTCONFIG) ) < 0 ) + { + debug("i2c_read failed"); + } + else + { + Si4709_dev.valid_client_state = eTRUE; + } + +#ifdef RDS_INTERRUPT_ON_ALWAYS + /*Creating Circular Buffer*/ + /*Single RDS_Block_Data buffer size is 4x16 bits*/ + RDS_Block_Data_buffer = kzalloc(RDS_BUFFER_LENGTH*8,GFP_KERNEL); + if(!RDS_Block_Data_buffer) + { + error("Not sufficient memory for creating RDS_Block_Data_buffer"); + ret = -ENOMEM; + goto EXIT; + } + + /*Single RDS_Block_Error buffer size is 4x8 bits*/ + RDS_Block_Error_buffer = kzalloc(RDS_BUFFER_LENGTH*4,GFP_KERNEL); + if(!RDS_Block_Error_buffer) + { + error("Not sufficient memory for creating RDS_Block_Error_buffer"); + ret = -ENOMEM; + kfree(RDS_Block_Data_buffer); + goto EXIT; + } + + /*Initialising read and write indices*/ + RDS_Buffer_Index_read= 0; + RDS_Buffer_Index_write= 0; + + /*Creating work-queue*/ + Si4709_wq = create_singlethread_workqueue("Si4709_wq"); + if(!Si4709_wq) + { + error("Not sufficient memory for Si4709_wq, work-queue"); + ret = -ENOMEM; + kfree(RDS_Block_Error_buffer); + kfree(RDS_Block_Data_buffer); + goto EXIT; + } + + /*Initialising work_queue*/ + INIT_WORK(&Si4709_work, Si4709_work_func); + + RDS_Data_Available = 0; + RDS_Data_Lost =0; + RDS_Groups_Available_till_now = 0; +EXIT: +#endif + + mutex_unlock(&(Si4709_dev.lock)); + + debug("Si4709_dev_init call over"); + + return ret; +} + +int Si4709_dev_exit(void) +{ + int ret = 0; + + debug("Si4709_dev_exit called"); + + mutex_lock(&(Si4709_dev.lock)); + + // Temporary blocked by abnormal function call(E-CIM 2657654) - DW Shim. 2010.03.04 + printk(KERN_ERR "Si4709_dev_exit() is called!!"); +// Si4709_dev.client = NULL; + +// Si4709_dev.valid_client_state = eFALSE; +// Si4709_dev.valid = eFALSE; + +#ifdef RDS_INTERRUPT_ON_ALWAYS + if(Si4709_wq) + destroy_workqueue(Si4709_wq); + + if(RDS_Block_Error_buffer) + kfree(RDS_Block_Error_buffer); + + if(RDS_Block_Data_buffer) + kfree(RDS_Block_Data_buffer); +#endif + + mutex_unlock(&(Si4709_dev.lock)); + + debug("Si4709_dev_exit call over"); + + return ret; +} + +void Si4709_dev_mutex_init(void) +{ + mutex_init(&(Si4709_dev.lock)); +} + +int Si4709_dev_powerup(void) +{ + int ret = 0; + u32 value = 100; + + debug("Si4709_dev_powerup called"); + + mutex_lock(&(Si4709_dev.lock)); + + if(!(RADIO_ON==Si4709_dev.state.power_state)) + { + if( (ret = powerup()) < 0 ) + { + debug("powerup failed"); + } + else if( Si4709_dev.valid_client_state == eFALSE ) + { + debug("Si4709_dev_powerup called when DS (state, client) is invalid"); + ret = -1; + } + else + { + /*initial settings*/ +#if 0 + POWERCFG_BITSET_RDSM_LOW(&Si4709_dev.registers[POWERCFG]); +#else + POWERCFG_BITSET_RDSM_HIGH(&Si4709_dev.registers[POWERCFG]); +#endif + // POWERCFG_BITSET_SKMODE_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_SKMODE_LOW(&Si4709_dev.registers[POWERCFG]); /*VNVS:18-NOV'09---- wrap at the upper and lower band limit and continue seeking*/ + SYSCONFIG1_BITSET_STCIEN_HIGH(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RDSIEN_LOW(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RDS_HIGH(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_DE_50(&Si4709_dev.registers[SYSCONFIG1]); /*VNVS:18-NOV'09--- Setting DE-Time Constant as 50us(Europe,Japan,Australia)*/ + SYSCONFIG1_BITSET_GPIO_STC_RDS_INT(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG1]); + + // SYSCONFIG2_BITSET_SEEKTH(&Si4709_dev.registers[SYSCONFIG2],2); + SYSCONFIG2_BITSET_SEEKTH(&Si4709_dev.registers[SYSCONFIG2], TUNE_RSSI_THRESHOLD); /*VNVS:18-NOV'09---- modified for detecting more stations of good quality*/ + SYSCONFIG2_BITSET_VOLUME(&Si4709_dev.registers[SYSCONFIG2],0x0F); + SYSCONFIG2_BITSET_BAND_87p5_108_MHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.band = BAND_87500_108000_kHz; + Si4709_dev.settings.bottom_of_band = FREQ_87500_kHz; + + SYSCONFIG2_BITSET_SPACE_100_KHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.channel_spacing = CHAN_SPACING_100_kHz; + + + // SYSCONFIG3_BITSET_SKSNR(&Si4709_dev.registers[SYSCONFIG3],3); + SYSCONFIG3_BITSET_SKSNR(&Si4709_dev.registers[SYSCONFIG3], TUNE_SNR_THRESHOLD);/*VNVS:18-NOV'09---- modified for detecting more stations of good quality*/ + SYSCONFIG3_BITSET_SKCNT(&Si4709_dev.registers[SYSCONFIG3], TUNE_CNT_THRESHOLD); + + SYSCONFIG3_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG3]); + + Si4709_dev.settings.timeout_RDS = msecs_to_jiffies(value); + Si4709_dev.settings.curr_snr = TUNE_SNR_THRESHOLD; + Si4709_dev.settings.curr_rssi_th = TUNE_RSSI_THRESHOLD; + + /*this will write all the above registers*/ + if( (ret = i2c_write(SYSCONFIG3)) < 0 ) + { + debug("Si4709_dev_powerup i2c_write 1 failed"); + } + else + { + Si4709_dev.valid = eTRUE; +#ifdef RDS_INTERRUPT_ON_ALWAYS + /*Initialising read and write indices*/ + RDS_Buffer_Index_read= 0; + RDS_Buffer_Index_write= 0; + + RDS_Data_Available = 0; + RDS_Data_Lost =0; + RDS_Groups_Available_till_now = 0; +#endif + } + + } + } + else + debug("Device already Powered-ON"); + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + +int Si4709_dev_powerdown(void) +{ + int ret = 0; + + msleep(500); // For avoiding turned off pop noise + debug("Si4709_dev_powerdown called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_powerdown called when DS is invalid"); + ret = -1; + } + else if ( ( ret = powerdown()) < 0 ) + { + debug("powerdown failed"); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_suspend(void) +{ + int ret = 0; + + debug("Si4709_dev_suspend called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid_client_state== eFALSE ) + { + debug("Si4709_dev_suspend called when DS (state, client) is invalid"); + ret = -1; + } +#if 0 + else if( Si4709_dev.state.power_state == RADIO_ON ) + { + ret = powerdown(); + } +#endif + + mutex_unlock(&(Si4709_dev.lock)); + + debug("Si4709_dev_enable call over"); + + return ret; +} + +int Si4709_dev_resume(void) +{ + int ret = 0; + +// debug("Si4709_dev_resume called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid_client_state == eFALSE ) + { + debug("Si4709_dev_resume called when DS (state, client) is invalid"); + ret = -1; + } +#if 0 + else if( Si4709_dev.state.power_state == RADIO_POWERDOWN ) + { + if( (ret = powerup()) < 0 ) + { + debug("powerup failed"); + } + } +#endif + + mutex_unlock(&(Si4709_dev.lock)); + +// debug("Si4709_dev_disable call over"); + + return ret; +} + +int Si4709_dev_band_set(int band) +{ + int ret = 0; + u16 sysconfig2 =0; + u16 prev_band = 0; + u32 prev_bottom_of_band = 0; + + debug("Si4709_dev_band_set called"); + + mutex_lock(&(Si4709_dev.lock)); + sysconfig2 = Si4709_dev.registers[SYSCONFIG2]; + prev_band = Si4709_dev.settings.band; + prev_bottom_of_band = Si4709_dev.settings.bottom_of_band; + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_band_set called when DS is invalid"); + ret = -1; + } + else + { + switch (band) + { + case BAND_87500_108000_kHz: + SYSCONFIG2_BITSET_BAND_87p5_108_MHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.band = BAND_87500_108000_kHz; + Si4709_dev.settings.bottom_of_band = FREQ_87500_kHz; + break; + + case BAND_76000_108000_kHz: + SYSCONFIG2_BITSET_BAND_76_108_MHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.band = BAND_76000_108000_kHz; + Si4709_dev.settings.bottom_of_band = FREQ_76000_kHz; + break; + + case BAND_76000_90000_kHz: + SYSCONFIG2_BITSET_BAND_76_90_MHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.band = BAND_76000_90000_kHz; + Si4709_dev.settings.bottom_of_band = FREQ_76000_kHz; + break; + + default: + ret = -1; + } + + if(ret == 0) + { + if( (ret = i2c_write(SYSCONFIG2)) < 0 ) + { + debug("Si4709_dev_band_set i2c_write 1 failed"); + Si4709_dev.settings.band = prev_band; + Si4709_dev.settings.bottom_of_band = prev_bottom_of_band; + Si4709_dev.registers[SYSCONFIG2] = sysconfig2; + } + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_ch_spacing_set(int ch_spacing) +{ + int ret = 0; + u16 sysconfig2 = 0; + u16 prev_ch_spacing = 0; + + debug("Si4709_dev_ch_spacing_set called"); + + mutex_lock(&(Si4709_dev.lock)); + sysconfig2 = Si4709_dev.registers[SYSCONFIG2]; + prev_ch_spacing = Si4709_dev.settings.channel_spacing; + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_ch_spacing_set called when DS is invalid"); + ret = -1; + } + else + { + switch (ch_spacing) + { + case CHAN_SPACING_200_kHz: + SYSCONFIG2_BITSET_SPACE_200_KHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.channel_spacing = CHAN_SPACING_200_kHz; + break; + + case CHAN_SPACING_100_kHz: + SYSCONFIG2_BITSET_SPACE_100_KHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.channel_spacing = CHAN_SPACING_100_kHz; + break; + + case CHAN_SPACING_50_kHz: + SYSCONFIG2_BITSET_SPACE_50_KHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.channel_spacing = CHAN_SPACING_50_kHz; + break; + + default: + ret = -1; + } + + if(ret == 0) + { + if( (ret = i2c_write(SYSCONFIG2)) < 0 ) + { + debug("Si4709_dev_ch_spacing_set i2c_write 1 failed"); + Si4709_dev.settings.channel_spacing = prev_ch_spacing; + Si4709_dev.registers[SYSCONFIG2] = sysconfig2; + } + + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_chan_select(u32 frequency) +{ + int ret = 0; + + debug("Si4709_dev_chan_select called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_chan_select called when DS is invalid"); + ret = -1; + } + else + { + Si4709_dev.state.seek_state = RADIO_SEEK_ON; + + ret = tune_freq(frequency); + debug("Si4709_dev_chan_select called1"); + Si4709_dev.state.seek_state = RADIO_SEEK_OFF; + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_chan_get(u32 *frequency) +{ + int ret = 0; + + + debug("Si4709_dev_chan_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_chan_get called when DS is invalid"); + ret = -1; + } + else if( (ret = i2c_read(READCHAN)) < 0 ) + { + debug("Si4709_dev_chan_get i2c_read failed"); + } + else + { + get_cur_chan_freq(frequency, Si4709_dev.registers[READCHAN]); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_seek_up(u32 *frequency) +{ + int ret = 0; + + debug("Si4709_dev_seek_up called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_seek_up called when DS is invalid"); + ret = -1; + } + else + { + Si4709_dev.state.seek_state = RADIO_SEEK_ON; + + ret = seek(frequency, 1); + + Si4709_dev.state.seek_state = RADIO_SEEK_OFF; + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_seek_down(u32 *frequency) +{ + int ret = 0; + + debug("Si4709_dev_seek_down called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_seek_down called when DS is invalid"); + ret = -1; + } + else + { + Si4709_dev.state.seek_state = RADIO_SEEK_ON; + + ret = seek(frequency, 0); + + Si4709_dev.state.seek_state = RADIO_SEEK_OFF; + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + +#if 0 +int Si4709_dev_seek_auto(u32 *seek_preset_user) +{ + u8 *rssi_seek; + int ret = 0; + int i =0; + int j = 0; + channel_into_t temp; + + debug("Si4709_dev_seek_auto called"); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_seek_auto called when DS is invalid"); + ret = -1; + } + + else if( (rssi_seek = (u8 *)kzalloc(sizeof(u8) * NUM_SEEK_PRESETS, GFP_KERNEL)) == NULL ) + { + debug("Si4709_ioctl: no memory"); + ret = -ENOMEM; + } + + else + { + + if( (ret = tune_freq(FREQ_87500_kHz)) == 0 ) + { + debug("Si4709_dev_seek_auto tune_freq success"); + get_cur_chan_freq(&(Si4709_dev.rssi_freq[0].frequency), Si4709_dev.registers[READCHAN]); + Si4709_dev_cur_RSSI_get(&(Si4709_dev.rssi_freq[0].rsssi_val)); + + } + else + { + debug("tunning failed, seek auto failed"); + ret =-1; + } + #if 0 + for(i=0;i<50; i++) + { + if( (ret = seek(&(Si4709_dev.settings.seek_preset[i]),1)) == 0 ) + { + get_cur_chan_freq(&(Si4709_dev.rssi_freq[i].frequency), Si4709_dev.registers[READCHAN]); + Si4709_dev_cur_RSSI_get(&(Si4709_dev.rssi_freq[i].rsssi_val)); + rssi_seek ++; + } + + else + { + debug("seek failed"); + + } + } + #endif + + + + /***new method ****/ + for(i=1;i<30; i++) + { + if( (ret = seek(&(Si4709_dev.settings.seek_preset[i]),1)) == 0 ) + { + get_cur_chan_freq(&(Si4709_dev.rssi_freq[i].frequency), Si4709_dev.registers[READCHAN]); + Si4709_dev_cur_RSSI_get(&(Si4709_dev.rssi_freq[i].rsssi_val)); + } + + else + { + debug("seek failed"); + + } + } + /***Sort the array of structures on the basis of RSSI value****/ + for(i=0;i<29;i++) + { + + for(j=i+1;j<30;j++) + { + + if( Si4709_dev.rssi_freq[j].rsssi_val>Si4709_dev.rssi_freq[i].rsssi_val) + { + temp=Si4709_dev.rssi_freq[i]; + Si4709_dev.rssi_freq[i]=Si4709_dev.rssi_freq[j]; + Si4709_dev.rssi_freq[j]=temp; + } + + } + + } + + /***Store the frequency in Array*****/ + for(i=0;i<19;i++) + { + Si4709_dev.settings.seek_preset[i]=Si4709_dev.rssi_freq[i].frequency; + } + + + + } + memcpy(seek_preset_user, Si4709_dev.settings.seek_preset , sizeof(int)*NUM_SEEK_PRESETS); + kfree(rssi_seek); + return ret; +} +#endif + + + +int Si4709_dev_RSSI_seek_th_set(u8 seek_th) +{ + int ret = 0; + u16 sysconfig2 = 0; + + debug("Si4709_dev_RSSI_seek_th_set called"); + + mutex_lock(&(Si4709_dev.lock)); + sysconfig2 = Si4709_dev.registers[SYSCONFIG2]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_RSSI_seek_th_set called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG2_BITSET_SEEKTH(&Si4709_dev.registers[SYSCONFIG2], seek_th); + Si4709_dev.settings.curr_rssi_th=seek_th; + if( (ret = i2c_write( SYSCONFIG2 )) < 0 ) + { + debug("Si4709_dev_RSSI_seek_th_set i2c_write 1 failed"); + Si4709_dev.registers[SYSCONFIG2] = sysconfig2; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_seek_SNR_th_set(u8 seek_SNR) +{ + int ret = 0; + u16 sysconfig3 = 0; + + debug("Si4709_dev_seek_SNR_th_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig3 = Si4709_dev.registers[SYSCONFIG3]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_seek_SNR_th_set called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG3_BITSET_SKSNR(&Si4709_dev.registers[SYSCONFIG3], seek_SNR); + SYSCONFIG3_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG3]); + Si4709_dev.settings.curr_snr=seek_SNR; + + if( (ret = i2c_write( SYSCONFIG3 )) < 0 ) + { + debug("Si4709_dev_seek_SNR_th_set i2c_write 1 failed"); + Si4709_dev.registers[SYSCONFIG3] = sysconfig3; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_seek_FM_ID_th_set(u8 seek_FM_ID_th) +{ + int ret = 0; + u16 sysconfig3 = 0; + + debug("Si4709_dev_seek_FM_ID_th_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig3 = Si4709_dev.registers[SYSCONFIG3]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_seek_SNR_th_set called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG3_BITSET_SKCNT(&Si4709_dev.registers[SYSCONFIG3], seek_FM_ID_th); + SYSCONFIG3_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG3]); + + if( (ret = i2c_write( SYSCONFIG3 )) < 0 ) + { + debug("Si4709_dev_seek_FM_ID_th_set i2c_write 1 failed"); + sysconfig3 = Si4709_dev.registers[SYSCONFIG3]; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_cur_RSSI_get(rssi_snr_t *cur_RSSI) +{ + int ret = 0; + + debug("Si4709_dev_cur_RSSI_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_cur_RSSI_get called when DS is invalid"); + ret = -1; + } + else + { + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("Si4709_dev_cur_RSSI_get i2c_read 1 failed"); + } + else + { + + cur_RSSI->curr_rssi= STATUSRSSI_RSSI_SIGNAL_STRENGTH(Si4709_dev.registers[STATUSRSSI]); + cur_RSSI->curr_rssi_th=Si4709_dev.settings.curr_rssi_th; + cur_RSSI->curr_snr=Si4709_dev.settings.curr_snr; + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +/*VNVS:START 13-OCT'09---- Functions which reads device-id,chip-id,power configuration, system configuration2 registers */ +int Si4709_dev_device_id(device_id *dev_id) +{ + int ret = 0; + + debug("Si4709_dev_device_id called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_device_id called when DS is invalid"); + ret = -1; + } + else + { + if( (ret = i2c_read(DEVICE_ID)) < 0 ) + { + debug("Si4709_dev_device_id i2c_read failed"); + } + else + { + + dev_id->part_number= DEVICE_ID_PART_NUMBER(Si4709_dev.registers[DEVICE_ID]); + dev_id->manufact_number = DEVICE_ID_MANUFACT_NUMBER(Si4709_dev.registers[DEVICE_ID]); + + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_chip_id(chip_id *chp_id) +{ + int ret = 0; + + debug("Si4709_dev_chip_id called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_chip_id called when DS is invalid"); + ret = -1; + } + else + { + if( (ret = i2c_read(CHIP_ID)) < 0 ) + { + debug("Si4709_dev_chip_id i2c_read failed"); + } + else + { + + chp_id->chip_version= CHIP_ID_CHIP_VERSION(Si4709_dev.registers[CHIP_ID]); + chp_id->device = CHIP_ID_DEVICE(Si4709_dev.registers[CHIP_ID]); + chp_id->firmware_version = CHIP_ID_FIRMWARE_VERSION(Si4709_dev.registers[CHIP_ID]); + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_sys_config2(sys_config2 *sys_conf2) +{ + int ret = 0; + + debug("Si4709_sys_config2 called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_sys_config2 called when DS is invalid"); + ret = -1; + } + else + { + if((ret = i2c_read(SYSCONFIG2)) < 0) + { + debug("Si4709_sys_config2 i2c_read failed"); + } + else + { + sys_conf2->rssi_th =SYS_CONFIG2_RSSI_TH(Si4709_dev.registers[SYSCONFIG2]); + sys_conf2->fm_band = SYS_CONFIG2_FM_BAND(Si4709_dev.registers[SYSCONFIG2]); + sys_conf2->fm_chan_spac = SYS_CONFIG2_FM_CHAN_SPAC(Si4709_dev.registers[SYSCONFIG2]); + sys_conf2->fm_vol = SYS_CONFIG2_FM_VOL(Si4709_dev.registers[SYSCONFIG2]); + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_sys_config3(sys_config3 *sys_conf3) +{ + int ret = 0; + + debug("Si4709_sys_config3 called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_sys_config3 called when DS is invalid"); + ret = -1; + } + else + { + if((ret = i2c_read(SYSCONFIG3)) < 0) + { + debug("Si4709_sys_config3 i2c_read failed"); + } + else + { + sys_conf3->smmute = (Si4709_dev.registers[SYSCONFIG3] & 0xC000) >> 14; + sys_conf3->smutea = (Si4709_dev.registers[SYSCONFIG3] & 0x3000) >> 12; + sys_conf3->volext = (Si4709_dev.registers[SYSCONFIG3] & 0x0100) >> 8; + sys_conf3->sksnr = (Si4709_dev.registers[SYSCONFIG3] & 0x00F0) >> 4; + sys_conf3->skcnt = (Si4709_dev.registers[SYSCONFIG3] & 0x000F); + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_status_rssi(status_rssi *status) +{ + int ret = 0; + + debug("Si4709_dev_status_rssi called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_status_rssi called when DS is invalid"); + ret = -1; + } + else + { + if((ret = i2c_read(STATUSRSSI)) < 0) + { + debug("Si4709_sys_config3 i2c_read failed"); + } + else + { + status->rdsr = (Si4709_dev.registers[STATUSRSSI] & 0x8000) >> 15; + status->stc = (Si4709_dev.registers[STATUSRSSI] & 0x4000) >> 14; + status->sfbl = (Si4709_dev.registers[STATUSRSSI] & 0x2000) >> 13; + status->afcrl = (Si4709_dev.registers[STATUSRSSI] & 0x1000) >> 12; + status->rdss = (Si4709_dev.registers[STATUSRSSI] & 0x0800) >> 11; + status->blera = (Si4709_dev.registers[STATUSRSSI] & 0x0600) >> 9; + status->st = (Si4709_dev.registers[STATUSRSSI] & 0x0100) >> 8; + status->rssi = (Si4709_dev.registers[STATUSRSSI] & 0x00FF); + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_sys_config2_set(sys_config2 *sys_conf2) +{ + int ret = 0; + u16 register_bak = 0; + + debug("Si4709_dev_sys_config2_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + register_bak = Si4709_dev.registers[SYSCONFIG2]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_sys_config2_set called when DS is invalid"); + ret = -1; + } + else + { + printk(KERN_ERR "Si4709_dev_sys_config2_set() : Register Value = [0x%X], rssi-th = [%X]\n", Si4709_dev.registers[SYSCONFIG2], sys_conf2->rssi_th); + Si4709_dev.registers[SYSCONFIG2] = (Si4709_dev.registers[SYSCONFIG2] & 0x00FF) | ((sys_conf2->rssi_th) << 8); + Si4709_dev.registers[SYSCONFIG2] = (Si4709_dev.registers[SYSCONFIG2] & 0xFF3F) | ((sys_conf2->fm_band) << 6); + Si4709_dev.registers[SYSCONFIG2] = (Si4709_dev.registers[SYSCONFIG2] & 0xFFCF) | ((sys_conf2->fm_chan_spac) << 4); + Si4709_dev.registers[SYSCONFIG2] = (Si4709_dev.registers[SYSCONFIG2] & 0xFFF0) | (sys_conf2->fm_vol); + printk(KERN_ERR "Si4709_dev_sys_config2_set() : After Register Value = [0x%X]\n", Si4709_dev.registers[SYSCONFIG2]); + + if( (ret = i2c_write( SYSCONFIG2 )) < 0 ) + { + debug("Si4709_dev_sys_config2_set i2c_write 1 failed"); + Si4709_dev.registers[SYSCONFIG2] = register_bak; + } + else + printk(KERN_ERR "Si4709_dev_sys_config2_set() : Write Sucess!!"); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_sys_config3_set(sys_config3 *sys_conf3) +{ + int ret = 0; + u16 register_bak = 0; + + debug("Si4709_dev_sys_config3_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + register_bak = Si4709_dev.registers[SYSCONFIG3]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_sys_config3_set called when DS is invalid"); + ret = -1; + } + else + { + printk(KERN_ERR "Si4709_dev_sys_config3_set() : Register Value = [0x%X], sksnrth = [%X]\n", Si4709_dev.registers[SYSCONFIG3], sys_conf3->sksnr); + Si4709_dev.registers[SYSCONFIG3] = (Si4709_dev.registers[SYSCONFIG3] & 0x3FFF) | ((sys_conf3->smmute) << 14); + Si4709_dev.registers[SYSCONFIG3] = (Si4709_dev.registers[SYSCONFIG3] & 0xCFFF) | ((sys_conf3->smutea) << 12); + Si4709_dev.registers[SYSCONFIG3] = (Si4709_dev.registers[SYSCONFIG3] & 0xFEFF) | ((sys_conf3->volext) << 8); + Si4709_dev.registers[SYSCONFIG3] = (Si4709_dev.registers[SYSCONFIG3] & 0xFF0F) | ((sys_conf3->sksnr) << 4); + Si4709_dev.registers[SYSCONFIG3] = (Si4709_dev.registers[SYSCONFIG3] & 0xFFF0) | (sys_conf3->skcnt); + printk(KERN_ERR "Si4709_dev_sys_config3_set() : After Register Value = [0x%X]\n", Si4709_dev.registers[SYSCONFIG3]); + + if((ret = i2c_write( SYSCONFIG3)) < 0) + { + debug("Si4709_dev_sys_config3_set i2c_write 1 failed"); + Si4709_dev.registers[SYSCONFIG3] = register_bak; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_power_config(power_config *pow_conf) +{ + int ret =0; + + debug("Si4709_dev_power_config called"); + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_power_config called when DS is invalid"); + ret = -1; + } + else + { + if( (ret = i2c_read(POWERCFG)) < 0 ) + { + debug("Si4709_dev_power_config i2c_read failed"); + } + else + { + + pow_conf->dsmute =POWER_CONFIG_SOFTMUTE_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->dmute =POWER_CONFIG_MUTE_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->mono =POWER_CONFIG_MONO_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->rds_mode =POWER_CONFIG_RDS_MODE_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->sk_mode =POWER_CONFIG_SKMODE_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->seek_up =POWER_CONFIG_SEEKUP_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->seek =POWER_CONFIG_SEEK_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->power_disable =POWER_CONFIG_DISABLE_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->power_enable =POWER_CONFIG_ENABLE_STATUS(Si4709_dev.registers[POWERCFG]); + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} +/*VNVS:END*/ + +/*VNVS:START 18-NOV'09*/ +/*Reading AFCRL Bit*/ +int Si4709_dev_AFCRL_get(u8 *afc) +{ + int ret = 0; + + debug("Si4709_dev_AFCRL_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_AFCRL_get called when DS is invalid"); + ret = -1; + } + else + { + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("Si4709_dev_AFCRL_get i2c_read failed"); + } + *afc = STATUSRSSI_AFC_RAIL_STATUS(Si4709_dev.registers[STATUSRSSI]); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} +/*Setting DE-emphasis time constant 50us(Europe,Japan,Australia) or 75us(USA)*/ +int Si4709_dev_DE_set(u8 de_tc) +{ + u16 sysconfig1 = 0; + int ret = 0; + + debug("Si4709_dev_DE_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig1 = Si4709_dev.registers[SYSCONFIG1]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_DE_set called when DS is invalid"); + ret = -1; + } + else + { + switch(de_tc) + { + case DE_TIME_CONSTANT_50: + SYSCONFIG1_BITSET_DE_50(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RESERVED( &Si4709_dev.registers[SYSCONFIG1] ); + break; + case DE_TIME_CONSTANT_75: + SYSCONFIG1_BITSET_DE_75(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RESERVED( &Si4709_dev.registers[SYSCONFIG1] ); + break; + default: + ret = -1; + } + + if(0==ret) + if( (ret = i2c_write(SYSCONFIG1)) < 0 ) + { + debug("Si4709_dev_DE_set i2c_write failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +/*Resetting the RDS Data Buffer*/ +int Si4709_dev_reset_rds_data() +{ + int ret = 0; + + debug_rds("Si4709_dev_reset_rds_data called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_reset_rds_data called when DS is invalid"); + ret = -1; + } + else + { + RDS_Buffer_Index_write = 0; + RDS_Buffer_Index_read = 0; + RDS_Data_Lost = 0; + RDS_Data_Available = 0; + memset(RDS_Block_Data_buffer,0,RDS_BUFFER_LENGTH*8); + memset(RDS_Block_Error_buffer,0,RDS_BUFFER_LENGTH*4); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} +/*VNVS:END*/ +int Si4709_dev_VOLEXT_ENB(void) +{ + int ret = 0; + u16 sysconfig3 = 0; + + debug("Si4709_dev_VOLEXT_ENB called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig3 = Si4709_dev.registers[SYSCONFIG3]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_VOLEXT_ENB called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG3_BITSET_VOLEXT_ENB(&Si4709_dev.registers[SYSCONFIG3]); + SYSCONFIG3_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG3]); + + if( (ret = i2c_write( SYSCONFIG3 )) < 0 ) + { + debug("Si4709_dev_VOLEXT_ENB i2c_write failed"); + Si4709_dev.registers[SYSCONFIG3] = sysconfig3; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_VOLEXT_DISB(void) +{ + int ret = 0; + u16 sysconfig3 = 0; + + debug("Si4709_dev_VOLEXT_DISB called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig3 = Si4709_dev.registers[SYSCONFIG3]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_VOLEXT_DISB called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG3_BITSET_VOLEXT_DISB(&Si4709_dev.registers[SYSCONFIG3]); + SYSCONFIG3_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG3]); + + if( (ret = i2c_write( SYSCONFIG3 )) < 0 ) + { + debug("Si4709_dev_VOLEXT_DISB i2c_write failed"); + Si4709_dev.registers[SYSCONFIG3] = sysconfig3; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_volume_set(u8 volume) +{ + int ret = 0; + u16 sysconfig2 = 0; + + debug("Si4709_dev_volume_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig2 = Si4709_dev.registers[SYSCONFIG2]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_volume_set called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG2_BITSET_VOLUME(&Si4709_dev.registers[SYSCONFIG2], volume); + + if( (ret = i2c_write( SYSCONFIG2 )) < 0 ) + { + debug("Si4709_dev_volume_set i2c_write failed"); + Si4709_dev.registers[SYSCONFIG2] = sysconfig2; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_volume_get(u8 *volume) +{ + int ret = 0; + + debug("Si4709_dev_volume_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_volume_get called when DS is invalid"); + ret = -1; + } + else + { + *volume = SYSCONFIG2_GET_VOLUME(Si4709_dev.registers[SYSCONFIG2]); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +/* + VNVS:START 19-AUG'10---- Adding DSMUTE ON/OFF feature.The Soft Mute feature is available to attenuate the audio + outputs and minimize audible noise in very weak signal conditions. + */ +int Si4709_dev_DSMUTE_ON(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_DSMUTE_ON called"); + + mutex_lock(&(Si4709_dev.lock)); + + powercfg = Si4709_dev.registers[POWERCFG]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_DSMUTE_ON called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_DSMUTE_LOW(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + error("Si4709_dev_DSMUTE_ON i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_DSMUTE_OFF(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_DSMUTE_OFF called"); + + mutex_lock(&(Si4709_dev.lock)); + + powercfg = Si4709_dev.registers[POWERCFG]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_DSMUTE_OFF called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_DSMUTE_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + error("Si4709_dev_DSMUTE_OFF i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} +/*VNVS:END*/ + +int Si4709_dev_MUTE_ON(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_MUTE_ON called"); + + mutex_lock(&(Si4709_dev.lock)); + powercfg = Si4709_dev.registers[POWERCFG]; + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_MUTE_ON called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_DMUTE_LOW(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + debug("Si4709_dev_MUTE_ON i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_MUTE_OFF(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_MUTE_OFF called"); + + mutex_lock(&(Si4709_dev.lock)); + + powercfg = Si4709_dev.registers[POWERCFG]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_MUTE_OFF called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_DMUTE_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + debug("Si4709_dev_MUTE_OFF i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_MONO_SET(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_MONO_SET called"); + + mutex_lock(&(Si4709_dev.lock)); + + powercfg = Si4709_dev.registers[POWERCFG]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_MONO_SET called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_MONO_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + debug("Si4709_dev_MONO_SET i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_STEREO_SET(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_STEREO_SET called"); + + mutex_lock(&(Si4709_dev.lock)); + + powercfg = Si4709_dev.registers[POWERCFG]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_STEREO_SET called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_MONO_LOW(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + debug("Si4709_dev_STEREO_SET i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_RDS_ENABLE(void) +{ + u16 sysconfig1 = 0; + int ret = 0; + + debug("Si4709_dev_RDS_ENABLE called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig1 = Si4709_dev.registers[SYSCONFIG1]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_RDS_ENABLE called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG1_BITSET_RDS_HIGH(&Si4709_dev.registers[SYSCONFIG1]); +#ifdef RDS_INTERRUPT_ON_ALWAYS + SYSCONFIG1_BITSET_RDSIEN_HIGH(&Si4709_dev.registers[SYSCONFIG1]); +#endif + SYSCONFIG1_BITSET_RESERVED( &Si4709_dev.registers[SYSCONFIG1] ); + if( (ret = i2c_write(SYSCONFIG1)) < 0 ) + { + debug("Si4709_dev_RDS_ENABLE i2c_write failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + } +#ifdef RDS_INTERRUPT_ON_ALWAYS + else + Si4709_RDS_flag = RDS_WAITING; +#endif + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + + +int Si4709_dev_RDS_DISABLE(void) +{ + u16 sysconfig1 = 0; + int ret = 0; + + debug("Si4709_dev_RDS_DISABLE called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig1 = Si4709_dev.registers[SYSCONFIG1]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_RDS_DISABLE called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG1_BITSET_RDS_LOW(&Si4709_dev.registers[SYSCONFIG1]); +#ifdef RDS_INTERRUPT_ON_ALWAYS + SYSCONFIG1_BITSET_RDSIEN_LOW(&Si4709_dev.registers[SYSCONFIG1]); +#endif + SYSCONFIG1_BITSET_RESERVED( &Si4709_dev.registers[SYSCONFIG1] ); + if( (ret = i2c_write(SYSCONFIG1)) < 0 ) + { + debug("Si4709_dev_RDS_DISABLE i2c_write failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + } +#ifdef RDS_INTERRUPT_ON_ALWAYS + else + Si4709_RDS_flag = NO_WAIT; +#endif + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + +int Si4709_dev_rstate_get(dev_state_t *dev_state) +{ + int ret = 0; + + debug("Si4709_dev_rstate_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_rstate_get called when DS is invalid"); + ret = -1; + } + else + { + dev_state->power_state = Si4709_dev.state.power_state; + dev_state->seek_state = Si4709_dev.state.seek_state; + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + +/*VNVS:START 7-JUNE'10 Function call for work-queue "Si4709_wq"*/ +#ifdef RDS_INTERRUPT_ON_ALWAYS +void Si4709_work_func(struct work_struct *work) +{ + int i,ret = 0; +#ifdef RDS_TESTING + u8 group_type; +#endif + debug_rds("%s",__func__); +// mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + error("Si4709_dev_RDS_data_get called when DS is invalid"); + ret = -1; + } + else + { + + if(RDS_Data_Lost > 1) + debug_rds("No_of_RDS_groups_Lost till now : %d",RDS_Data_Lost); + + + /*RDSR bit and RDS Block data, so reading the RDS registers*/ + if((ret = i2c_read(RDSD)) < 0) + error("Si4709_work_func i2c_read failed"); + else + { + /*Checking whether RDS Ready bit is set or not, if not set return immediately*/ + if(!(STATUSRSSI_RDS_READY_STATUS(Si4709_dev.registers[STATUSRSSI]))) + { + error("RDS Ready Bit Not set"); + return; + } + + debug_rds("RDS Ready bit is set"); + + debug_rds("No_of_RDS_groups_Available : %d",RDS_Data_Available); + + RDS_Data_Available = 0; + + debug_rds("RDS_Buffer_Index_write = %d",RDS_Buffer_Index_write); + + /*Writing into the Circular Buffer*/ + + /*Writing into RDS_Block_Data_buffer*/ + i = 0; + RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_write] = Si4709_dev.registers[RDSA]; + RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_write] = Si4709_dev.registers[RDSB]; + RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_write] = Si4709_dev.registers[RDSC]; + RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_write] = Si4709_dev.registers[RDSD]; + + /*Writing into RDS_Block_Error_buffer*/ + i = 0; + RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_write] = STATUSRSSI_RDS_BLOCK_A_ERRORS(Si4709_dev.registers[STATUSRSSI]); + RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_write] = READCHAN_BLOCK_B_ERRORS(Si4709_dev.registers[READCHAN]); + RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_write] = READCHAN_BLOCK_C_ERRORS(Si4709_dev.registers[READCHAN]); + RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_write] = READCHAN_BLOCK_D_ERRORS(Si4709_dev.registers[READCHAN]); + +#ifdef RDS_TESTING + if(RDS_Block_Error_buffer[0 + 4*RDS_Buffer_Index_write] < 3) + { + debug_rds("PI Code is %d",RDS_Block_Data_buffer[0 + 4*RDS_Buffer_Index_write]); + } + if(RDS_Block_Error_buffer[1 + 4*RDS_Buffer_Index_write] < 2) + { + group_type = RDS_Block_Data_buffer[1 + 4*RDS_Buffer_Index_write] >> 11; + + if (group_type & 0x01) + { + debug_rds("PI Code is %d",RDS_Block_Data_buffer[2 + 4*RDS_Buffer_Index_write]); + } + if(group_type == GROUP_TYPE_2A || group_type == GROUP_TYPE_2B ) + { + if(RDS_Block_Error_buffer[2 + 4*RDS_Buffer_Index_write] < 3) + { + debug_rds("Update RT with RDSC"); + } + else + { + debug_rds("RDS_Block_Error_buffer of Block C is greater than 3"); + } + } + } +#endif + RDS_Buffer_Index_write++; + + if(RDS_Buffer_Index_write >= RDS_BUFFER_LENGTH) + RDS_Buffer_Index_write = 0; + + debug_rds("RDS_Buffer_Index_write = %d",RDS_Buffer_Index_write); + } + } + +// mutex_unlock(&(Si4709_dev.lock)); +} +#endif +/*VNVS:END*/ + +int Si4709_dev_RDS_data_get(radio_data_t *data) +{ + int i,ret = 0; + u16 sysconfig1 = 0; + + debug_rds("Si4709_dev_RDS_data_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig1 = Si4709_dev.registers[SYSCONFIG1]; + + if( Si4709_dev.valid == eFALSE ) + { + error("Si4709_dev_RDS_data_get called when DS is invalid"); + ret = -1; + } + else + { +#ifdef RDS_INTERRUPT_ON_ALWAYS + + debug_rds("RDS_Buffer_Index_read = %d",RDS_Buffer_Index_read); + + /*If No New RDS Data is available return error*/ + if(RDS_Buffer_Index_read == RDS_Buffer_Index_write) + { + debug_rds("No_New_RDS_Data_is_available"); + if((ret = i2c_read(READCHAN)) < 0) + error("Si4709_dev_RDS_data_get i2c_read 1 failed"); + else + { + get_cur_chan_freq(&(data->curr_channel), Si4709_dev.registers[READCHAN]); + data->curr_rssi = STATUSRSSI_RSSI_SIGNAL_STRENGTH(Si4709_dev.registers[STATUSRSSI]); + debug_rds("curr_channel: %u, curr_rssi:%u",data->curr_channel,(u32)data->curr_rssi); + } + ret = -1; + } + else + { + if((ret = i2c_read(READCHAN)) < 0) + error("Si4709_dev_RDS_data_get i2c_read 2 failed"); + else + { + get_cur_chan_freq(&(data->curr_channel), Si4709_dev.registers[READCHAN]); + data->curr_rssi = STATUSRSSI_RSSI_SIGNAL_STRENGTH(Si4709_dev.registers[STATUSRSSI]); + debug_rds("curr_channel: %u, curr_rssi:%u",data->curr_channel,(u32)data->curr_rssi); + + /*Reading from RDS_Block_Data_buffer*/ + i = 0; + data->rdsa = RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->rdsb = RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->rdsc = RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->rdsd = RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_read]; + + /*Reading from RDS_Block_Error_buffer*/ + i = 0; + data->blera = RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->blerb = RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->blerc = RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->blerd = RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_read]; + + /*Flushing the read data*/ + memset(&RDS_Block_Data_buffer[0+4*RDS_Buffer_Index_read],0,8); + memset(&RDS_Block_Error_buffer[0+4*RDS_Buffer_Index_read],0,4); + + RDS_Buffer_Index_read++; + + if(RDS_Buffer_Index_read >= RDS_BUFFER_LENGTH) + RDS_Buffer_Index_read = 0; + } + } + + debug_rds("RDS_Buffer_Index_read = %d",RDS_Buffer_Index_read); + +#else + SYSCONFIG1_BITSET_RDSIEN_HIGH(&Si4709_dev.registers[SYSCONFIG1]); + + if((ret = i2c_write(SYSCONFIG1)) < 0) + { + debug("Si4709_dev_RDS_data_get i2c_write 1 failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + } + else + { + if( (ret=i2c_read(SYSCONFIG1)) < 0) + debug("Si4709_dev_RDS_data_get i2c_read 1 failed"); + + debug("sysconfig1: 0x%x",Si4709_dev.registers[SYSCONFIG1] ); + sysconfig1 = Si4709_dev.registers[SYSCONFIG1]; + + Si4709_dev_wait_flag = RDS_WAITING; + + wait_RDS(); + + if((ret=i2c_read(STATUSRSSI)) < 0) + debug("Si4709_dev_RDS_data_get i2c_read 2 failed"); + + debug("statusrssi: 0x%x",Si4709_dev.registers[STATUSRSSI] ); + SYSCONFIG1_BITSET_RDSIEN_LOW(&Si4709_dev.registers[SYSCONFIG1]); + + if ((ret = i2c_write(SYSCONFIG1)) < 0) + { + debug("Si4709_dev_RDS_data_get i2c_write 2 failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + } + else if(Si4709_dev_wait_flag == WAIT_OVER) + { + Si4709_dev_wait_flag = NO_WAIT; + + if((ret = i2c_read(RDSD)) < 0) + debug("Si4709_dev_RDS_data_get i2c_read 3 failed"); + else + { + data->rdsa = Si4709_dev.registers[RDSA]; + data->rdsb = Si4709_dev.registers[RDSB]; + data->rdsc = Si4709_dev.registers[RDSC]; + data->rdsd = Si4709_dev.registers[RDSD]; + + get_cur_chan_freq(&(data->curr_channel), Si4709_dev.registers[READCHAN]); + debug("curr_channel: %u",data->curr_channel); + data->curr_rssi = STATUSRSSI_RSSI_SIGNAL_STRENGTH(Si4709_dev.registers[STATUSRSSI]); + debug("curr_rssi:%u",(u32)data->curr_rssi); + data->blera = STATUSRSSI_RDS_BLOCK_A_ERRORS(Si4709_dev.registers[STATUSRSSI]); + data->blerb = READCHAN_BLOCK_B_ERRORS(Si4709_dev.registers[READCHAN]); + data->blerc = READCHAN_BLOCK_C_ERRORS(Si4709_dev.registers[READCHAN]); + data->blerd = READCHAN_BLOCK_D_ERRORS(Si4709_dev.registers[READCHAN]); + } + } + else + { + debug("Si4709_dev_RDS_data_get failure no interrupt or timeout"); + Si4709_dev_wait_flag = NO_WAIT; + ret = -1; + } + } +#endif + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_RDS_timeout_set(u32 time_out) +{ + int ret = 0; + u32 jiffy_count = 0; + + debug("Si4709_dev_RDS_timeout_set called"); + /****convert time_out(in milliseconds) into jiffies*****/ + + jiffy_count = msecs_to_jiffies(time_out); + + debug("jiffy_count%d",jiffy_count); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_RDS_timeout_set called when DS is invalid"); + ret = -1; + } + else + { + Si4709_dev.settings.timeout_RDS = jiffy_count; + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + +/**************************************************************/ +static int powerup(void) +{ + int ret=0; + u16 powercfg = Si4709_dev.registers[POWERCFG]; + int reg; + /****Resetting the device****/ + + gpio_set_value(FM_RESET, GPIO_LEVEL_LOW); + gpio_set_value(FM_RESET, GPIO_LEVEL_HIGH); + +#if 0 + /*Add the i2c driver*/ + if ( (ret = Si4709_i2c_drv_init() < 0) ) + { + debug("Si4709_i2c_drv_init failed"); + } +#endif + /*Resetting the Si4709_dev.registers[] array*/ + for(reg=0;reg < NUM_OF_REGISTERS;reg++) + Si4709_dev.registers[reg] = 0; + + debug("Resetting the Si4709_dev.registers[] array"); + + POWERCFG_BITSET_DMUTE_HIGH( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_ENABLE_HIGH( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_DISABLE_LOW( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_RESERVED( &Si4709_dev.registers[POWERCFG] ); + + if( (ret = i2c_write(POWERCFG)) < 0 ) + { + debug("powerup->i2c_write 1 failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + else + { + /*Si4709/09 datasheet: Table 7*/ + mdelay(110); + Si4709_dev.state.power_state = RADIO_ON; + } + + return ret; +} + +static int powerdown(void) +{ + int ret = 0; + u16 test1 = Si4709_dev.registers[TEST1], + sysconfig1 = Si4709_dev.registers[SYSCONFIG1], + powercfg = Si4709_dev.registers[POWERCFG]; + + if(!(RADIO_POWERDOWN==Si4709_dev.state.power_state)) + { + //TEST1_BITSET_AHIZEN_HIGH( &Si4709_dev.registers[TEST1] ); + //TEST1_BITSET_RESERVED( &Si4709_dev.registers[TEST1] ); + + SYSCONFIG1_BITSET_GPIO_LOW(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RESERVED( &Si4709_dev.registers[SYSCONFIG1] ); + /*VNVS: 13-OCT'09---- During Powerdown of the device RDS should be disabled + according to the Si4708/09 datasheet*/ + SYSCONFIG1_BITSET_RDS_LOW(&Si4709_dev.registers[SYSCONFIG1]); + + POWERCFG_BITSET_DMUTE_LOW( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_ENABLE_HIGH( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_DISABLE_HIGH( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_RESERVED( &Si4709_dev.registers[POWERCFG] ); + + /*this will write all the above registers*/ + if( (ret = i2c_write( TEST1 )) < 0 ) + { + debug("powerdown->i2c_write failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + Si4709_dev.registers[POWERCFG] = powercfg; + Si4709_dev.registers[TEST1] = test1; + } + else + { + Si4709_dev.state.power_state = RADIO_POWERDOWN; + } + + /****Resetting the device****/ + gpio_set_value(FM_RESET, GPIO_LEVEL_LOW); + gpio_set_value(FM_RESET, GPIO_LEVEL_HIGH); + gpio_set_value(FM_RESET, GPIO_LEVEL_LOW); + } + else + debug("Device already Powered-OFF"); + + return ret; +} + +static int seek(u32 *frequency, int up) +{ + int ret = 0; + u16 powercfg = Si4709_dev.registers[POWERCFG]; + u16 channel = 0; + int valid_station_found = 0; + + if( up ) + { + POWERCFG_BITSET_SEEKUP_HIGH(&Si4709_dev.registers[POWERCFG]); + } + else + { + POWERCFG_BITSET_SEEKUP_LOW(&Si4709_dev.registers[POWERCFG]); + } + + POWERCFG_BITSET_SKMODE_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_SEEK_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write(POWERCFG)) < 0 ) + { + debug("seek i2c_write 1 failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + else + { + Si4709_dev_wait_flag = SEEK_WAITING; + + wait(); + + if ( Si4709_dev_wait_flag == SEEK_CANCEL ) + { + powercfg = Si4709_dev.registers[POWERCFG]; + POWERCFG_BITSET_SEEK_LOW(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write(POWERCFG)) < 0 ) + { + debug("seek i2c_write 2 failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + + if( (ret = i2c_read( READCHAN )) < 0 ) + { + debug("seek i2c_read 1 failed"); + } + else + { + channel = READCHAN_GET_CHAN(Si4709_dev.registers[READCHAN]); + *frequency = channel_to_freq(channel); + } + *frequency = 0; + } + + Si4709_dev_wait_flag = NO_WAIT; + + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("seek i2c_read 2 failed"); + } + else + { + /*VNVS:START 13-OCT'09---- Checking the status of Seek/Tune Bit*/ +#ifdef TEST_FM + if(STATUSRSSI_SEEK_TUNE_STATUS(Si4709_dev.registers[STATUSRSSI]) == COMPLETE) + { + debug("Seek/Tune Status is set to 1 by device"); + if(STATUSRSSI_SF_BL_STATUS(Si4709_dev.registers[STATUSRSSI]) == SEEK_SUCCESSFUL) + { + debug("Seek Fail/Band Limit Status is set to 0 by device ---SeekUp Operation Completed"); + valid_station_found = 1; + } + else + debug("Seek Fail/Band Limit Status is set to 1 by device ---SeekUp Operation Not Completed"); + } + else + debug("Seek/Tune Status is set to 0 by device ---SeekUp Operation Not Completed"); + +#endif + /*VNVS:END*/ + + powercfg = Si4709_dev.registers[POWERCFG]; + + POWERCFG_BITSET_SEEK_LOW(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write(POWERCFG)) < 0 ) + { + debug("seek i2c_write 2 failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + else + { + do + { + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("seek i2c_read 3 failed"); + break; + } + }while( STATUSRSSI_SEEK_TUNE_STATUS(Si4709_dev.registers[STATUSRSSI]) != CLEAR ); + + if( ret == 0 && valid_station_found == 1 ) + { + if( (ret = i2c_read( READCHAN )) < 0 ) + { + debug("seek i2c_read 4 failed"); + } + else + { + channel = READCHAN_GET_CHAN(Si4709_dev.registers[READCHAN]); + *frequency = channel_to_freq(channel); + debug("Frequency after seek-up is %d \n",*frequency); + } + } + else + { + debug("Valid station not found \n"); + *frequency = 0; + } + } + } + } + + return ret; +} + +static int tune_freq(u32 frequency) +{ + int ret = 0; + u16 channel = Si4709_dev.registers[CHANNEL]; +#ifdef TEST_FM + u16 read_channel; +#endif + debug("tune_freq called"); + + Si4709_dev.registers[CHANNEL] = freq_to_channel(frequency); +#ifdef TEST_FM + read_channel = Si4709_dev.registers[CHANNEL]; + debug(" Input read_channel =%x",read_channel); +#endif + CHANNEL_BITSET_TUNE_HIGH(&Si4709_dev.registers[CHANNEL]); + CHANNEL_BITSET_RESERVED(&Si4709_dev.registers[CHANNEL]); + + if( (ret = i2c_write(CHANNEL)) < 0 ) + { + debug("tune_freq i2c_write 1 failed"); + Si4709_dev.registers[CHANNEL] = channel; + } + else + { + + Si4709_dev_wait_flag = TUNE_WAITING; + debug("Si4709_dev_wait_flag = TUNE_WAITING"); +#ifdef TEST_FM + if( (ret = i2c_read(READCHAN)) < 0 ) + { + debug("tune_freq i2c_read 1 failed"); + } + else + { + read_channel=READCHAN_GET_CHAN(Si4709_dev.registers[READCHAN]); + debug("curr_channel before tuning = %x",read_channel); + } +#endif + + wait(); + + Si4709_dev_wait_flag = NO_WAIT; + + /*VNVS:START 13-OCT'09---- Checking the status of Seek/Tune Bit*/ +#ifdef TEST_FM + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("tune_freq i2c_read 2 failed"); + + } + else if(STATUSRSSI_SEEK_TUNE_STATUS(Si4709_dev.registers[STATUSRSSI]) == COMPLETE) + debug("Seek/Tune Status is set to 1 by device ---Tuning Operation Completed"); + else + debug("Seek/Tune Status is set to 0 by device ---Tuning Operation Not Completed"); +#endif + /*VNVS:END*/ + + channel = Si4709_dev.registers[CHANNEL]; + + CHANNEL_BITSET_TUNE_LOW(&Si4709_dev.registers[CHANNEL]); + CHANNEL_BITSET_RESERVED(&Si4709_dev.registers[CHANNEL]); + + if( (ret = i2c_write(CHANNEL)) < 0 ) + { + debug("tune_freq i2c_write 2 failed"); + Si4709_dev.registers[CHANNEL] = channel; + } + else + { + do + { + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("tune_freq i2c_read 3 failed"); + break; + } + }while( STATUSRSSI_SEEK_TUNE_STATUS(Si4709_dev.registers[STATUSRSSI]) != CLEAR ); + + } + + /*VNVS:START 13-OCT'09---- Reading the READCHAN register after tuning operation*/ +#ifdef TEST_FM + if( (ret = i2c_read(READCHAN)) < 0 ) + { + debug("tune_freq i2c_read 2 failed"); + } + else + { + read_channel=READCHAN_GET_CHAN(Si4709_dev.registers[READCHAN]); + debug("curr_channel after tuning= %x",read_channel); + } +#endif + /*VNVS:END*/ + } + + return ret; +} + +static void get_cur_chan_freq(u32 *frequency, u16 readchan) +{ + + u16 channel = 0; + debug("get_cur_chan_freq called"); + + channel = READCHAN_GET_CHAN(readchan); + debug("read_channel=%x",channel); + + *frequency = channel_to_freq(channel); + + debug("frequency-> %u",*frequency); +} + +static u16 freq_to_channel(u32 frequency) +{ + u16 channel; + + if( frequency < Si4709_dev.settings.bottom_of_band ) + { + frequency = Si4709_dev.settings.bottom_of_band; + } + + channel = (frequency - Si4709_dev.settings.bottom_of_band) + / Si4709_dev.settings.channel_spacing; + + return channel; +} + +static u32 channel_to_freq(u16 channel) +{ + u32 frequency; + + frequency = Si4709_dev.settings.bottom_of_band + + Si4709_dev.settings.channel_spacing * channel; + + return frequency; +} + +/*Only one thread will be able to call this, since this function call is + protected by a mutex, so no race conditions can arise*/ +static void wait(void) +{ + wait_event_interruptible(Si4709_waitq, + (Si4709_dev_wait_flag == WAIT_OVER) || (Si4709_dev_wait_flag == SEEK_CANCEL)); +} + +static void wait_RDS(void) +{ + wait_event_interruptible_timeout(Si4709_waitq, + (Si4709_dev_wait_flag == WAIT_OVER),Si4709_dev.settings.timeout_RDS); +} + +/*i2c read function*/ +/*Si4709_dev.client should be set before calling this function. + If Si4709_dev.valid = eTRUE then Si4709_dev.client will b valid + This function should be called from the functions in this file. The + callers should check if Si4709_dev.valid = eTRUE before + calling this function. If it is eFALSE then this function should not + be called*/ +static int i2c_read( u8 reg ) +{ + u8 idx, reading_reg = STATUSRSSI; + u8 data[NUM_OF_REGISTERS * 2], data_high, data_low; + int msglen = 0, ret = 0; + + for(idx = 0; idx < NUM_OF_REGISTERS * 2; idx++) + { + data[idx] = 0x00; + } + + msglen = reg - reading_reg + 1; + + if(msglen > 0) + { + msglen = msglen * 2; + } + else + { + msglen = (msglen + NUM_OF_REGISTERS) * 2; + } + + ret = i2c_master_recv((struct i2c_client*)(Si4709_dev.client), data, msglen); + + if(ret == msglen) + { + idx = 0; + do + { + data_high = data[idx]; + data_low = data[idx+1]; + + Si4709_dev.registers[reading_reg] = 0x0000; + Si4709_dev.registers[reading_reg] = (data_high << 8) + data_low; + reading_reg = (reading_reg + 1) & RDSD; + idx = idx + 2; + } while(reading_reg != ((reg +1) & RDSD)); + + ret = 0; + } + else + { + ret = -1; + } + + return ret; +} + +/*i2c write function*/ +/*Si4709_dev.client should be set before calling this function. + If Si4709_dev.valid = eTRUE then Si4709_dev.client will b valid + This function should be called from the functions in this file. The + callers should check if Si4709_dev.valid = eTRUE before + calling this function. If it is eFALSE then this function should not + be called*/ +static int i2c_write( u8 reg ) +{ + u8 writing_reg = POWERCFG; + u8 data[NUM_OF_REGISTERS * 2]; + int i, msglen = 0, ret = 0; + + for(i = 0; i < NUM_OF_REGISTERS * 2; i++) + { + data[i] = 0x00; + } + + do + { + data[msglen++] = (u8)(Si4709_dev.registers[writing_reg] >> 8); + data[msglen++] = (u8)(Si4709_dev.registers[writing_reg] & 0xFF); + + writing_reg = (writing_reg +1) & RDSD; + } while(writing_reg != ((reg + 1) & RDSD)); + + ret = i2c_master_send((struct i2c_client*)(Si4709_dev.client), ( const char *)data, msglen); + + if(ret == msglen) + { + ret = 0; + } + else + { + ret = -1; + } + + return ret; +} + +static int insert_preset(u32 frequency,u8 rssi,u8 *seek_preset_rssi) +{ + u8 i; + u8 min_rssi = 0xff; + u8 min_rssi_preset=0; + int ret = 0; + + /* first find the minimum rssi and its location + this will always stop at the first location with a zero rssi */ + + debug("si4709 autoseek : insert preset\n"); + + for (i=0; i<NUM_SEEK_PRESETS; i++) + { + if (seek_preset_rssi[i] < min_rssi) + { + min_rssi = seek_preset_rssi[i]; + min_rssi_preset = i; + } + } + + if (rssi < min_rssi) + ret = -1; + + /***Delete the preset with the minimum rssi, and clear the last preset + since it would only be a copy of the second to last preset after + the deletion ***/ + for (i=min_rssi_preset; i<NUM_SEEK_PRESETS-1; i++) + { + Si4709_dev.settings.seek_preset[i]= Si4709_dev.settings.seek_preset[i+1]; + seek_preset_rssi[i] = seek_preset_rssi[i+1]; + } + + Si4709_dev.settings.seek_preset[i] = 0; + seek_preset_rssi[i] = 0; + + /*** Fill the first preset with a zero for the frequency. This will + always overwrite the last preset once all presets have been filled. ***/ + for (i=min_rssi_preset; i<NUM_SEEK_PRESETS; i++) + { + if(Si4709_dev.settings.seek_preset[i] == 0) + { + Si4709_dev.settings.seek_preset[i]= frequency; + seek_preset_rssi[i] = rssi; + break; + } + } + return ret; +} + + |