aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/samsung/fm_si4709/Si4709_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/samsung/fm_si4709/Si4709_dev.c')
-rw-r--r--drivers/samsung/fm_si4709/Si4709_dev.c2509
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