diff options
Diffstat (limited to 'drivers/samsung/fm_si4709/Si4709_dev.c')
-rw-r--r-- | drivers/samsung/fm_si4709/Si4709_dev.c | 2509 |
1 files changed, 2509 insertions, 0 deletions
diff --git a/drivers/samsung/fm_si4709/Si4709_dev.c b/drivers/samsung/fm_si4709/Si4709_dev.c new file mode 100644 index 0000000..32ef932 --- /dev/null +++ b/drivers/samsung/fm_si4709/Si4709_dev.c @@ -0,0 +1,2509 @@ +#include <linux/kernel.h> +#include <linux/i2c.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/time.h> +#include <linux/workqueue.h> +#include <linux/interrupt.h> + +#include <mach/gpio.h> +#include <plat/gpio-cfg.h> + +#include "Si4709_regs.h" +#include "Si4709_main.h" +#include "Si4709_dev.h" +#include "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 + +#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); + +#ifndef RDS_INTERRUPT_ON_ALWAYS +static void wait_RDS(void); +#endif + +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 struct 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 + +unsigned int Si4709_dev_int; +unsigned int Si4709_dev_irq; + +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; + + if (system_rev >= 0x7) { + Si4709_dev_int = GPIO_FM_INT_REV07; + Si4709_dev_irq = gpio_to_irq(GPIO_FM_INT_REV07); + } else { + Si4709_dev_int = GPIO_FM_INT; + Si4709_dev_irq = gpio_to_irq(GPIO_FM_INT); + } + + /***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(Si4709_dev_int, S3C_GPIO_PULL_UP); + /* register sleep GPIO setting in c1_sleep_gpio_table[] (mach-c1.c) */ + /* s3c_gpio_slp_setpull_updown(Si4709_dev_int, S3C_GPIO_PULL_UP); */ + + disable_irq(Si4709_dev_irq); + + Si4709_dev.state.power_state = RADIO_POWERDOWN; + Si4709_dev.state.seek_state = RADIO_SEEK_OFF; + + ret = i2c_read(BOOTCONFIG); + if (ret < 0) + error("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 */ + /* 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); + + kfree(RDS_Block_Error_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)) { + ret = powerup(); + if (ret < 0) { + error("powerup failed"); + } else if (Si4709_dev.valid_client_state == eFALSE) { + error("Si4709_dev_powerup called " + "when DS(state, client) is invalid"); + ret = -1; + } else { +/* initial settings */ +#ifdef _ENABLE_RDS_ +#if 0 + POWERCFG_BITSET_RDSM_LOW(&Si4709_dev. + registers[POWERCFG]); +#else + POWERCFG_BITSET_RDSM_HIGH(&Si4709_dev. + registers[POWERCFG]); +#endif +#endif + /* POWERCFG_BITSET_SKMODE_HIGH( */ + /* &Si4709_dev.registers[POWERCFG]); */ +/*VNVS:18-NOV'09 : wrap at the upper and lower band limit and continue seeking*/ + POWERCFG_BITSET_SKMODE_LOW(&Si4709_dev. + registers[POWERCFG]); + SYSCONFIG1_BITSET_STCIEN_HIGH(&Si4709_dev. + registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RDSIEN_LOW(&Si4709_dev. + registers[SYSCONFIG1]); +#ifdef _ENABLE_RDS_ + SYSCONFIG1_BITSET_RDS_HIGH(&Si4709_dev. + registers[SYSCONFIG1]); +#else + SYSCONFIG1_BITSET_RDS_LOW(&Si4709_dev. + registers[SYSCONFIG1]); +#endif +/*VNVS:18-NOV'09 : Setting DE-Time Constant as 50us(Europe,Japan,Australia)*/ + SYSCONFIG1_BITSET_DE_50(&Si4709_dev. + registers[SYSCONFIG1]); + 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); */ +/*VNVS:18-NOV'09 : modified for detecting more stations of good quality*/ + SYSCONFIG2_BITSET_SEEKTH(&Si4709_dev. + registers[SYSCONFIG2], + TUNE_RSSI_THRESHOLD); + 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); */ +/*VNVS:18-NOV'09 : modified for detecting more stations of good quality*/ + SYSCONFIG3_BITSET_SKSNR(&Si4709_dev. + registers[SYSCONFIG3], + TUNE_SNR_THRESHOLD); + 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 */ + ret = i2c_write(SYSCONFIG3); + if (ret < 0) + error("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"); + + enable_irq(Si4709_dev_irq); + + 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)); + + disable_irq(Si4709_dev_irq); + + if (Si4709_dev.valid == eFALSE) { + error("Si4709_dev_powerdown called when DS is invalid"); + ret = -1; + } else { + ret = powerdown(); + if (ret < 0) + error("powerdown failed"); + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_suspend(void) +{ + int ret = 0; + + debug("Si4709_dev_suspend called"); + +#ifndef _ENABLE_RDS_ + disable_irq(Si4709_dev_irq); +#endif + + mutex_lock(&(Si4709_dev.lock)); + + if (Si4709_dev.valid_client_state == eFALSE) { + error("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"); + +#ifndef _ENABLE_RDS_ +#if 0 + s3c_gpio_cfgpin(Si4709_dev_int, S3C_GPIO_SFN(0xF)); + s3c_gpio_setpull(Si4709_dev_int, S3C_GPIO_PULL_UP); + set_irq_type(Si4709_dev_irq, IRQ_TYPE_EDGE_FALLING); +#endif + + enable_irq(Si4709_dev_irq); +#endif + + mutex_lock(&(Si4709_dev.lock)); + + if (Si4709_dev.valid_client_state == eFALSE) { + error("Si4709_dev_resume called " + "when DS(state, client) is invalid"); + ret = -1; + } +#if 0 + else if (Si4709_dev.state.power_state == RADIO_POWERDOWN) { + ret = powerup(); + if (ret < 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) { + error("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) { + ret = i2c_write(SYSCONFIG2); + if (ret < 0) { + error("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) { + error("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) { + ret = i2c_write(SYSCONFIG2); + if (ret < 0) { + error("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) { + error("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) { + error("Si4709_dev_chan_get called when DS is invalid"); + ret = -1; + } else { + ret = i2c_read(READCHAN); + if (ret < 0) + error("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) { + error("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) { + error("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 { + rssi_seek = kzalloc(sizeof(u8) * NUM_SEEK_PRESETS, + GFP_KERNEL); + if (rssi_seek == NULL) { + debug("Si4709_ioctl: no memory"); + ret = -ENOMEM; + } else { + ret = tune_freq(FREQ_87500_kHz); + if (ret == 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++) { + ret = + seek(&(Si4709_dev.settings. + seek_preset[i]), + 1); + if (ret == 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++) { + ret = seek(&(Si4709_dev.settings. + seek_preset[i]), 1); + if (ret == 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) { + error("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; + + ret = i2c_write(SYSCONFIG2); + if (ret < 0) { + error("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) { + error("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; + + ret = i2c_write(SYSCONFIG3); + if (ret < 0) { + error("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) { + error("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]); + + ret = i2c_write(SYSCONFIG3); + if (ret < 0) { + error("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(struct 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) { + error("Si4709_dev_cur_RSSI_get called when DS is invalid"); + ret = -1; + } else { + ret = i2c_read(STATUSRSSI); + if (ret < 0) { + error("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(struct device_id *dev_id) +{ + int ret = 0; + + debug("Si4709_dev_device_id called"); + + mutex_lock(&(Si4709_dev.lock)); + + if (Si4709_dev.valid == eFALSE) { + error("Si4709_dev_device_id called when DS is invalid"); + ret = -1; + } else { + ret = i2c_read(DEVICE_ID); + if (ret < 0) { + error("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(struct chip_id *chp_id) +{ + int ret = 0; + + debug("Si4709_dev_chip_id called"); + + mutex_lock(&(Si4709_dev.lock)); + + if (Si4709_dev.valid == eFALSE) { + error("Si4709_dev_chip_id called when DS is invalid"); + ret = -1; + } else { + ret = i2c_read(CHIP_ID); + if (ret < 0) { + error("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(struct sys_config2 *sys_conf2) +{ + int ret = 0; + + debug("Si4709_sys_config2 called"); + + mutex_lock(&(Si4709_dev.lock)); + + if (Si4709_dev.valid == eFALSE) { + error("Si4709_sys_config2 called when DS is invalid"); + ret = -1; + } else { + ret = i2c_read(SYSCONFIG2); + if (ret < 0) { + error("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(struct sys_config3 *sys_conf3) +{ + int ret = 0; + + debug("Si4709_sys_config3 called"); + + mutex_lock(&(Si4709_dev.lock)); + + if (Si4709_dev.valid == eFALSE) { + error("Si4709_sys_config3 called when DS is invalid"); + mutex_unlock(&(Si4709_dev.lock)); + return -1; + } + ret = i2c_read(SYSCONFIG3); + if (ret < 0) { + error("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(struct status_rssi *status) +{ + int ret = 0; + + debug("Si4709_dev_status_rssi called"); + + mutex_lock(&(Si4709_dev.lock)); + + if (Si4709_dev.valid == eFALSE) { + error("Si4709_dev_status_rssi called when DS is invalid"); + mutex_unlock(&(Si4709_dev.lock)); + return -1; + } + ret = i2c_read(STATUSRSSI); + if (ret < 0) { + error("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(struct 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) { + error("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]); + + ret = i2c_write(SYSCONFIG2); + if (ret < 0) { + error("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(struct 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) { + error("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]); + + ret = i2c_write(SYSCONFIG3); + if (ret < 0) { + error("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(struct power_config *pow_conf) +{ + int ret = 0; + + debug("Si4709_dev_power_config called"); + + mutex_lock(&(Si4709_dev.lock)); + + if (Si4709_dev.valid == eFALSE) { + error("Si4709_dev_power_config called when DS is invalid"); + ret = -1; + } else { + ret = i2c_read(POWERCFG); + if (ret < 0) + error("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) { + error("Si4709_dev_AFCRL_get called when DS is invalid"); + ret = -1; + } else { + ret = i2c_read(STATUSRSSI); + if (ret < 0) + error("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) { + error("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) { + ret = i2c_write(SYSCONFIG1); + if (ret < 0) { + error("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) { + error("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) { + error("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]); + + ret = i2c_write(SYSCONFIG3); + if (ret < 0) { + error("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) { + error("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]); + + ret = i2c_write(SYSCONFIG3); + if (ret < 0) { + error("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) { + error("Si4709_dev_volume_set called when DS is invalid"); + ret = -1; + } else { + SYSCONFIG2_BITSET_VOLUME(&Si4709_dev.registers[SYSCONFIG2], + volume); + + ret = i2c_write(SYSCONFIG2); + if (ret < 0) { + error("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) { + error("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) { + error("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]); + + ret = i2c_write(POWERCFG); + if (ret < 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) { + error("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]); + + ret = i2c_write(POWERCFG); + if (ret < 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) { + error("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]); + + ret = i2c_write(POWERCFG); + if (ret < 0) { + error("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) { + error("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]); + + ret = i2c_write(POWERCFG); + if (ret < 0) { + error("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) { + error("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]); + + ret = i2c_write(POWERCFG); + if (ret < 0) { + error("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) { + error("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]); + + ret = i2c_write(POWERCFG); + if (ret < 0) { + error("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) { + error("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]); + ret = i2c_write(SYSCONFIG1); + if (ret < 0) { + error("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) { + error("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]); + ret = i2c_write(SYSCONFIG1); + if (ret < 0) { + error("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(struct dev_state_t *dev_state) +{ + int ret = 0; + + debug("Si4709_dev_rstate_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + if (Si4709_dev.valid == eFALSE) { + error("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"); + return; + } + + 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 */ + ret = i2c_read(RDSD); + if (ret < 0) { + error("Si4709_work_func i2c_read failed"); + return; + } + +/*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(struct 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"); + mutex_unlock(&(Si4709_dev.lock)); + return -1; + } +#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) { + error("No_New_RDS_Data_is_available"); + ret = i2c_read(READCHAN); + if (ret < 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); + } + mutex_unlock(&(Si4709_dev.lock)); + return -1; + } + ret = i2c_read(READCHAN); + + if (ret < 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]); + + ret = i2c_write(SYSCONFIG1); + if (ret < 0) { + error("Si4709_dev_RDS_data_get i2c_write 1 failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + } else { + ret = i2c_read(SYSCONFIG1); + if (ret < 0) + error("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(); + + ret = i2c_read(STATUSRSSI); + if (ret < 0) + error("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]); + + ret = i2c_write(SYSCONFIG1); + if (ret < 0) { + error("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; + + ret = i2c_read(RDSD); + if (ret < 0) + error("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 { + error("Si4709_dev_RDS_data_get failure " + "no interrupt or timeout"); + Si4709_dev_wait_flag = NO_WAIT; + mutex_unlock(&(Si4709_dev.lock)); + return -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) { + error("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 */ + ret = Si4709_i2c_drv_init(); + if (ret < 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]); + + ret = i2c_write(POWERCFG); + if (ret < 0) { + error("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 + */ +#ifdef _ENABLE_RDS_ + SYSCONFIG1_BITSET_RDS_LOW(&Si4709_dev.registers[SYSCONFIG1]); +#endif + 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 */ + ret = i2c_write(TEST1); + if (ret < 0) { + error("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]); + + ret = i2c_write(POWERCFG); + if (ret < 0) { + error("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]); + + ret = i2c_write(POWERCFG); + if (ret < 0) { + error("seek i2c_write 2 failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + + ret = i2c_read(READCHAN); + if (ret < 0) + error("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; + + ret = i2c_read(STATUSRSSI); + if (ret < 0) + error("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]); + + ret = i2c_write(POWERCFG); + if (ret < 0) { + error("seek i2c_write 2 failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } else { + do { + ret = i2c_read(STATUSRSSI); + if (ret < 0) { + error("seek i2c_read 3 failed"); + break; + } + } while (STATUSRSSI_SEEK_TUNE_STATUS + (Si4709_dev. + registers[STATUSRSSI]) != + CLEAR); + + if (ret == 0 && valid_station_found == 1) { + ret = i2c_read(READCHAN); + if (ret < 0) + error("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"); + } + } + } + + 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]); + + ret = i2c_write(CHANNEL); + if (ret < 0) { + error("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 + ret = i2c_read(READCHAN); + if (ret < 0) + error("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 + ret = i2c_read(STATUSRSSI); + if (ret < 0) + error("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]); + + ret = i2c_write(CHANNEL); + if (ret < 0) { + error("tune_freq i2c_write 2 failed"); + Si4709_dev.registers[CHANNEL] = channel; + } else { + do { + ret = i2c_read(STATUSRSSI); + if (ret < 0) { + error("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 + ret = i2c_read(READCHAN); + if (ret < 0) + error("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)); +} + +#ifndef RDS_INTERRUPT_ON_ALWAYS +static void wait_RDS(void) +{ + wait_event_interruptible_timeout(Si4709_waitq, + (Si4709_dev_wait_flag == WAIT_OVER), + Si4709_dev.settings.timeout_RDS); +} +#endif + +/* 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; +} + +#if 0 +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; +} +#endif |