aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/samsung
diff options
context:
space:
mode:
authorcodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
committercodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
commitc6da2cfeb05178a11c6d062a06f8078150ee492f (patch)
treef3b4021d252c52d6463a9b3c1bb7245e399b009c /drivers/samsung
parentc6d7c4dbff353eac7919342ae6b3299a378160a6 (diff)
downloadkernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.zip
kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.gz
kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.bz2
samsung update 1
Diffstat (limited to 'drivers/samsung')
-rw-r--r--drivers/samsung/Kconfig31
-rw-r--r--drivers/samsung/Makefile7
-rw-r--r--drivers/samsung/fm_si4709/Makefile43
-rw-r--r--drivers/samsung/fm_si4709/Si4705_dev.c2064
-rw-r--r--drivers/samsung/fm_si4709/Si4705_main.c864
-rw-r--r--drivers/samsung/fm_si4709/Si4709_common.h49
-rw-r--r--drivers/samsung/fm_si4709/Si4709_dev.c2509
-rw-r--r--drivers/samsung/fm_si4709/Si4709_dev.h231
-rw-r--r--drivers/samsung/fm_si4709/Si4709_i2c_drv.c192
-rw-r--r--drivers/samsung/fm_si4709/Si4709_i2c_drv.h8
-rw-r--r--drivers/samsung/fm_si4709/Si4709_ioctl.h121
-rw-r--r--drivers/samsung/fm_si4709/Si4709_main.c844
-rw-r--r--drivers/samsung/fm_si4709/Si4709_main.h8
-rw-r--r--drivers/samsung/fm_si4709/Si4709_regs.h799
-rw-r--r--drivers/samsung/fm_si4709/commanddefs.h192
-rw-r--r--drivers/samsung/fm_si4709/propertydefs.h578
16 files changed, 8540 insertions, 0 deletions
diff --git a/drivers/samsung/Kconfig b/drivers/samsung/Kconfig
new file mode 100644
index 0000000..ab0026b
--- /dev/null
+++ b/drivers/samsung/Kconfig
@@ -0,0 +1,31 @@
+#
+#
+#
+
+menuconfig SAMSUNG_MODULES
+ tristate "Samsung Kernel Modules"
+ default n
+ help
+ Say Y to enable Samsung kernel modules. j4fs and param
+ modules are included.
+
+menuconfig FM_RADIO
+ tristate "FM Radio Driver"
+ depends on SAMSUNG_MODULES
+ default n
+ help
+ Say Y to enable FM Radio Driver
+
+menuconfig FM_SI4709
+ tristate "Si4709 FM radio"
+ depends on FM_RADIO
+ default n
+ help
+ Say Y to enable Si4709 FM radio support.
+
+ menuconfig FM_SI4705
+ tristate "Si4705 FM radio"
+ depends on FM_RADIO
+ default n
+ help
+ Say Y to enable Si4705 FM radio support.
diff --git a/drivers/samsung/Makefile b/drivers/samsung/Makefile
new file mode 100644
index 0000000..811c209
--- /dev/null
+++ b/drivers/samsung/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the kernel Sensor device drivers.
+#
+
+# Object files in subdirectories
+
+obj-$(CONFIG_FM_RADIO) += fm_si4709/
diff --git a/drivers/samsung/fm_si4709/Makefile b/drivers/samsung/fm_si4709/Makefile
new file mode 100644
index 0000000..80be6a7
--- /dev/null
+++ b/drivers/samsung/fm_si4709/Makefile
@@ -0,0 +1,43 @@
+##############################################################################
+# COPYRIGHT(C) : Samsung Electronics Co.Ltd, 2006-2011 ALL RIGHTS RESERVED
+# AUTHOR : Varun Mahajan <m.varun@samsung.com>
+##############################################################################
+# VERSION&DATE : Version 0.1
+##############################################################################
+
+ifneq ($(KERNELRELEASE), )
+
+MOD_NAME = Si4709_driver
+EXTRA_CFLAGS := -I$(PRJROOT)/modules/include
+
+ifneq ($(CONFIG_FM_SI4705),)
+obj-$(CONFIG_FM_SI4705) := $(MOD_NAME).o
+$(MOD_NAME)-y := Si4705_dev.o \
+ Si4709_i2c_drv.o \
+ Si4705_main.o
+else
+MOD_NAME = Si4709_driver
+obj-$(CONFIG_FM_SI4709) := $(MOD_NAME).o
+$(MOD_NAME)-y := Si4709_dev.o \
+ Si4709_i2c_drv.o \
+ Si4709_main.o
+endif
+
+else
+
+ifndef KDIR
+ KDIR :=$(PRJROOT)/linux-2.6.29
+endif
+
+all:
+ @$(MAKE) --no-print-directory -C $(KDIR) \
+ SUBDIRS=$(CURDIR) modules
+
+clean:
+ rm -f *.o *.ko *.mod.c *~ .*.cmd
+
+install:
+ @$(MAKE) --no-print-directory -C $(KDIR) \
+ SUBDIRS=$(CURDIR) modules_install
+
+endif
diff --git a/drivers/samsung/fm_si4709/Si4705_dev.c b/drivers/samsung/fm_si4709/Si4705_dev.c
new file mode 100644
index 0000000..0898882
--- /dev/null
+++ b/drivers/samsung/fm_si4709/Si4705_dev.c
@@ -0,0 +1,2064 @@
+#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"
+
+#if 1 /* To do */
+#include "commanddefs.h"
+#include "propertydefs.h"
+#endif
+
+
+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 10
+#define TUNE_SNR_THRESHOLD 4
+#define TUNE_CNT_THRESHOLD 0x00
+
+#define _ENABLE_RDS_
+
+#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
+
+u8 cmd[8];
+u8 rsp[13];
+u8 RsqInts;
+u8 Status;
+u8 SMUTE;
+u8 AFCRL;
+u8 Valid;
+u8 Pilot;
+u8 Blend;
+u16 Freq;
+u8 RSSI;
+u8 ASNR;
+u8 FreqOff;
+u8 STC;
+u8 BLTF;
+u16 AntCap;
+u8 RdsInts;
+u8 RdsSync;
+u8 GrpLost;
+u8 RdsFifoUsed;
+u16 BlockA;
+u16 BlockB;
+u16 BlockC;
+u16 BlockD;
+u8 BleA;
+u8 BleB;
+u8 BleC;
+u8 BleD;
+
+
+
+/*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, int);
+static int tune_freq(u32);
+static u16 freq_to_channel(u32);
+static void fmTuneStatus(u8 cancel, u8 intack);
+static void fmRsqStatus(u8 intack);
+static void si47xx_set_property(u16 propNumber, u16 propValue);
+static int si47xx_command(u8 cmd_size, u8 *cmd, u8 reply_size, u8 *reply);
+static void fmRdsStatus(u8 intack, u8 mtfifo);
+static void fmTuneFreq(u16 frequency);
+static void fmSeekStart(u8 seekUp, u8 wrap);
+static u8 si47xx_readStatus(void);
+static void si47xx_waitForCTS(void);
+static u8 getIntStatus(void);
+static int i2c_write(u8 number_bytes, u8 *data_out);
+static int i2c_read(u8 number_bytes, u8 *data_in);
+/**********************************************/
+
+/*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;
+
+#if defined(CONFIG_MACH_M0)
+unsigned int Si4709_dev_sw;
+#endif
+
+#if defined(CONFIG_MACH_M0_CTC)
+static const u16 rx_vol[] = {
+0x0, 0x15, 0x18, 0x1B, 0x1E, 0x21, 0x24, 0x27,
+0x2A, 0x2D, 0x30, 0x33, 0x36, 0x39, 0x3C, 0x3F};
+#else
+static const u16 rx_vol[] = {
+0x0, 0x13, 0x16, 0x19, 0x1C, 0x1F, 0x22, 0x25,
+0x28, 0x2B, 0x2E, 0x31, 0x34, 0x37, 0x3A, 0x3D};
+#endif
+
+
+int Si4709_dev_init(struct i2c_client *client)
+{
+ int ret = 0;
+
+ debug("Si4709_dev_init called");
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ Si4709_dev.client = client;
+
+#if defined(CONFIG_MACH_M0)
+ if (system_rev >= 15)
+ Si4709_dev_int = GPIO_FM_INT_REV15;
+ else
+#endif
+ Si4709_dev_int = GPIO_FM_INT;
+
+ Si4709_dev_irq = gpio_to_irq(Si4709_dev_int);
+
+#if defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_M0_CTC)
+ Si4709_dev_sw = GPIO_FM_MIC_SW;
+#endif
+
+ disable_irq(Si4709_dev_irq);
+
+ Si4709_dev.state.power_state = RADIO_POWERDOWN;
+ Si4709_dev.state.seek_state = RADIO_SEEK_OFF;
+ 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");
+
+ if (!(RADIO_ON == Si4709_dev.state.power_state)) {
+ ret = powerup();
+ if (ret < 0) {
+ debug("powerup failed");
+ } else if (Si4709_dev.valid_client_state == eFALSE) {
+ debug("Si4709_dev_powerup called "
+ "when DS(state, client) is invalid");
+ ret = -1;
+ } else {
+/* initial settings */
+#ifdef _ENABLE_RDS_
+ si47xx_set_property(FM_RDS_CONFIG, 1);
+ si47xx_set_property(GPO_IEN, GPO_IEN_STCIEN_MASK |
+ GPO_IEN_STCREP_MASK);
+ si47xx_set_property(GPO_IEN, GPO_IEN_STCIEN_MASK |
+ GPO_IEN_RDSIEN_MASK | GPO_IEN_STCREP_MASK);
+ si47xx_set_property(FM_RDS_INTERRUPT_SOURCE,
+ FM_RDS_INTERRUPT_SOURCE_RECV_MASK);
+ si47xx_set_property(FM_RDS_CONFIG,
+ FM_RDS_CONFIG_RDSEN_MASK |
+ (3 << FM_RDS_CONFIG_BLETHA_SHFT) |
+ (3 << FM_RDS_CONFIG_BLETHB_SHFT) |
+ (3 << FM_RDS_CONFIG_BLETHC_SHFT) |
+ (3 << FM_RDS_CONFIG_BLETHD_SHFT));
+#endif
+/*VNVS:18-NOV'09 : Setting DE-Time Constant as 50us(Europe,Japan,Australia)*/
+ si47xx_set_property(FM_DEEMPHASIS, FM_DEEMPH_50US);
+ /* SYSCONFIG2_BITSET_SEEKTH( */
+ /* &Si4709_dev.registers[SYSCONFIG2],2); */
+/*VNVS:18-NOV'09 : modified for detecting more stations of good quality*/
+ si47xx_set_property(FM_SEEK_TUNE_RSSI_THRESHOLD,
+ TUNE_RSSI_THRESHOLD);
+ si47xx_set_property(FM_SEEK_BAND_BOTTOM, 8750);
+ si47xx_set_property(FM_SEEK_BAND_TOP, 10800);
+ Si4709_dev.settings.band = BAND_87500_108000_kHz;
+ Si4709_dev.settings.bottom_of_band = FREQ_87500_kHz;
+ si47xx_set_property(FM_SEEK_FREQ_SPACING,
+ CHAN_SPACING_100_kHz);
+ 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*/
+ si47xx_set_property(FM_SEEK_TUNE_SNR_THRESHOLD,
+ TUNE_SNR_THRESHOLD);
+ 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;
+ Si4709_dev_STEREO_SET();
+
+/*this will write all the above registers */
+ if (ret < 0)
+ debug("Si4709_dev_powerup i2c_write 1 failed");
+ else {
+ Si4709_dev.valid = eTRUE;
+#ifdef RDS_INTERRUPT_ON_ALWAYS
+/*Initialising read and write indices */
+ RDS_Buffer_Index_read = 0;
+ RDS_Buffer_Index_write = 0;
+
+ RDS_Data_Available = 0;
+ RDS_Data_Lost = 0;
+ RDS_Groups_Available_till_now = 0;
+#endif
+ }
+ }
+ } else
+ debug("Device already Powered-ON");
+ enable_irq(Si4709_dev_irq);
+ si47xx_set_property(0xff00, 0);
+
+ 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) {
+ debug("Si4709_dev_powerdown called when DS is invalid");
+ ret = -1;
+ } else {
+ ret = powerdown();
+ if (ret < 0)
+ debug("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) {
+ debug("Si4709_dev_suspend called "
+ "when DS(state, client) is invalid");
+ ret = -1;
+ }
+ 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_
+ enable_irq(Si4709_dev_irq);
+#endif
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ if (Si4709_dev.valid_client_state == eFALSE) {
+ debug("Si4709_dev_resume called "
+ "when DS(state, client) is invalid");
+ ret = -1;
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+ debug("Si4709_dev_disable call over");
+
+ return ret;
+}
+
+int Si4709_dev_band_set(int band)
+{
+ int ret = 0;
+ u16 prev_band = 0;
+ u32 prev_bottom_of_band = 0;
+
+ debug("Si4709_dev_band_set called");
+
+ prev_band = Si4709_dev.settings.band;
+ prev_bottom_of_band = Si4709_dev.settings.bottom_of_band;
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_band_set called when DS is invalid");
+ ret = -1;
+ } else {
+ switch (band) {
+ case BAND_87500_108000_kHz:
+ si47xx_set_property(FM_SEEK_BAND_BOTTOM, 8750);
+ si47xx_set_property(FM_SEEK_BAND_TOP, 10800);
+ Si4709_dev.settings.band = BAND_87500_108000_kHz;
+ Si4709_dev.settings.bottom_of_band = FREQ_87500_kHz;
+ break;
+ case BAND_76000_108000_kHz:
+ si47xx_set_property(FM_SEEK_BAND_BOTTOM, 7600);
+ si47xx_set_property(FM_SEEK_BAND_TOP, 10800);
+ Si4709_dev.settings.band = BAND_76000_108000_kHz;
+ Si4709_dev.settings.bottom_of_band = FREQ_76000_kHz;
+ break;
+ case BAND_76000_90000_kHz:
+ si47xx_set_property(FM_SEEK_BAND_BOTTOM, 7600);
+ si47xx_set_property(FM_SEEK_BAND_TOP, 9000);
+ Si4709_dev.settings.band = BAND_76000_90000_kHz;
+ Si4709_dev.settings.bottom_of_band = FREQ_76000_kHz;
+ break;
+ default:
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+int Si4709_dev_ch_spacing_set(int ch_spacing)
+{
+ int ret = 0;
+ u16 prev_ch_spacing = 0;
+
+ debug("Si4709_dev_ch_spacing_set called");
+
+ mutex_lock(&(Si4709_dev.lock));
+ prev_ch_spacing = Si4709_dev.settings.channel_spacing;
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_ch_spacing_set called "
+ "when DS is invalid");
+ ret = -1;
+ } else {
+ switch (ch_spacing) {
+ case CHAN_SPACING_200_kHz:
+ si47xx_set_property(FM_SEEK_FREQ_SPACING, 20);
+ Si4709_dev.settings.channel_spacing =
+ CHAN_SPACING_200_kHz;
+ break;
+
+ case CHAN_SPACING_100_kHz:
+ si47xx_set_property(FM_SEEK_FREQ_SPACING, 10);
+ Si4709_dev.settings.channel_spacing =
+ CHAN_SPACING_100_kHz;
+ break;
+
+ case CHAN_SPACING_50_kHz:
+ si47xx_set_property(FM_SEEK_FREQ_SPACING, 5);
+ Si4709_dev.settings.channel_spacing =
+ CHAN_SPACING_50_kHz;
+ break;
+
+ default:
+ ret = -1;
+ }
+
+ if (ret == 0) {
+ if (ret < 0) {
+ debug("Si4709_dev_ch_spacing_set "
+ "i2c_write 1 failed");
+ Si4709_dev.settings.channel_spacing =
+ prev_ch_spacing;
+ }
+ }
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+int Si4709_dev_chan_select(u32 frequency)
+{
+ int ret = 0;
+
+ debug("Si4709_dev_chan_select called");
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_chan_select called when DS is invalid");
+ ret = -1;
+ } else {
+ Si4709_dev.state.seek_state = RADIO_SEEK_ON;
+
+ ret = tune_freq(frequency);
+ debug("Si4709_dev_chan_select called1");
+ Si4709_dev.state.seek_state = RADIO_SEEK_OFF;
+ }
+ return ret;
+}
+
+int Si4709_dev_chan_get(u32 *frequency)
+{
+ int ret = 0;
+
+ debug("Si4709_dev_chan_get called");
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_chan_get called when DS is invalid");
+ ret = -1;
+ } else {
+ if (ret < 0)
+ debug("Si4709_dev_chan_get i2c_read failed");
+ else {
+ fmTuneStatus(0, 0);
+ *frequency = Freq;
+ }
+ }
+ mutex_unlock(&(Si4709_dev.lock));
+ return ret;
+}
+
+int Si4709_dev_seek_full(u32 *frequency)
+{
+ int ret = 0;
+
+ debug("Si4709_dev_seek_full called\n");
+ mutex_lock(&(Si4709_dev.lock));
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_seek_full called when DS is invalid");
+ ret = -1;
+ } else {
+ Si4709_dev.state.seek_state = RADIO_SEEK_ON;
+ ret = seek(frequency, 1, 0);
+ Si4709_dev.state.seek_state = RADIO_SEEK_OFF;
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+int Si4709_dev_seek_up(u32 *frequency)
+{
+ int ret = 0;
+
+ debug("Si4709_dev_seek_up called\n");
+ mutex_lock(&(Si4709_dev.lock));
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_seek_up called when DS is invalid");
+ ret = -1;
+ } else {
+ Si4709_dev.state.seek_state = RADIO_SEEK_ON;
+ ret = seek(frequency, 1, 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\n");
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_seek_down called when DS is invalid");
+ ret = -1;
+ } else {
+ Si4709_dev.state.seek_state = RADIO_SEEK_ON;
+
+ ret = seek(frequency, 0, 1);
+
+ Si4709_dev.state.seek_state = RADIO_SEEK_OFF;
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+int Si4709_dev_RSSI_seek_th_set(u8 seek_th)
+{
+ int ret = 0;
+
+ debug("Si4709_dev_RSSI_seek_th_set called");
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_RSSI_seek_th_set called "
+ "when DS is invalid");
+ ret = -1;
+ } else {
+ si47xx_set_property(FM_SEEK_TUNE_RSSI_THRESHOLD, seek_th);
+ Si4709_dev.settings.curr_rssi_th = seek_th;
+ if (ret < 0)
+ debug("Si4709_dev_RSSI_seek_th_set i2c_write 1 failed");
+ }
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+int Si4709_dev_seek_SNR_th_set(u8 seek_SNR)
+{
+ int ret = 0;
+
+ debug("Si4709_dev_seek_SNR_th_set called");
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_seek_SNR_th_set called "
+ "when DS is invalid");
+ ret = -1;
+ } else {
+ si47xx_set_property(FM_SEEK_TUNE_SNR_THRESHOLD, seek_SNR);
+ Si4709_dev.settings.curr_snr = seek_SNR;
+
+ if (ret < 0)
+ debug("Si4709_dev_seek_SNR_th_set i2c_write 1 failed");
+ }
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+int Si4709_dev_seek_FM_ID_th_set(u8 seek_FM_ID_th)
+{
+ int ret = 0;
+
+ debug("Si4709_dev_seek_FM_ID_th_set called");
+
+ 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) {
+ debug("Si4709_dev_cur_RSSI_get called when DS is invalid");
+ ret = -1;
+ } else {
+ fmRsqStatus(0);
+ if (ret < 0) {
+ debug("Si4709_dev_cur_RSSI_get i2c_read 1 failed");
+ } else {
+ cur_RSSI->curr_rssi = RSSI;
+ 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");
+#if 0 /*To Do*/
+ mutex_lock(&(Si4709_dev.lock));
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_device_id called when DS is invalid");
+ ret = -1;
+ } else {
+ ret = i2c_read(DEVICE_ID);
+ if (ret < 0) {
+ debug("Si4709_dev_device_id i2c_read failed");
+ } else {
+ dev_id->part_number =
+ DEVICE_ID_PART_NUMBER(Si4709_dev.
+ registers[DEVICE_ID]);
+ dev_id->manufact_number =
+ DEVICE_ID_MANUFACT_NUMBER(Si4709_dev.
+ registers[DEVICE_ID]);
+ }
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+#endif
+ return ret;
+}
+
+int Si4709_dev_chip_id(struct chip_id *chp_id)
+{
+ int ret = 0;
+
+ debug("Si4709_dev_chip_id called");
+#if 0 /*To Do*/
+ mutex_lock(&(Si4709_dev.lock));
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_chip_id called when DS is invalid");
+ ret = -1;
+ } else {
+ ret = i2c_read(CHIP_ID);
+ if (ret < 0) {
+ debug("Si4709_dev_chip_id i2c_read failed");
+ } else {
+ chp_id->chip_version =
+ CHIP_ID_CHIP_VERSION(
+ Si4709_dev.registers[CHIP_ID]);
+ chp_id->device =
+ CHIP_ID_DEVICE(Si4709_dev.registers[CHIP_ID]);
+ chp_id->firmware_version =
+ CHIP_ID_FIRMWARE_VERSION(Si4709_dev.
+ registers[CHIP_ID]);
+ }
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+#endif
+ return ret;
+}
+
+int Si4709_dev_sys_config2(struct sys_config2 *sys_conf2)
+{
+ int ret = 0;
+
+ debug("Si4709_sys_config2 called\n");
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_sys_config2 called when DS is invalid");
+ ret = -1;
+ } else {
+ if (ret < 0) {
+ debug("Si4709_sys_config2 i2c_read failed");
+ } else {
+ sys_conf2->rssi_th = Si4709_dev.settings.curr_rssi_th;
+ sys_conf2->fm_band = Si4709_dev.settings.band;
+ sys_conf2->fm_chan_spac =
+ Si4709_dev.settings.channel_spacing;
+ sys_conf2->fm_vol = 0;
+ }
+ }
+
+ 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\n");
+ mutex_lock(&(Si4709_dev.lock));
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_sys_config3 called when DS is invalid");
+ mutex_unlock(&(Si4709_dev.lock));
+ return -1;
+ }
+ if (ret < 0) {
+ debug("Si4709_sys_config3 i2c_read failed");
+ } else {
+ sys_conf3->smmute = 0;
+ sys_conf3->smutea = 0;
+ sys_conf3->volext = 0;
+ sys_conf3->sksnr = Si4709_dev.settings.curr_snr;
+ sys_conf3->skcnt = 0;
+ }
+ 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) {
+ debug("Si4709_dev_status_rssi called when DS is invalid");
+ mutex_unlock(&(Si4709_dev.lock));
+ return -1;
+ }
+ fmRsqStatus(0);
+ if (ret < 0) {
+ debug("Si4709_sys_config3 i2c_read failed");
+ } else {
+ debug("Si4709_dev_status_rssi %d\n", RSSI);
+ status->rssi = RSSI;
+ }
+
+ 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) {
+ debug("Si4709_dev_sys_config2_set called when DS is invalid");
+ ret = -1;
+ } else {
+ si47xx_set_property(FM_SEEK_TUNE_RSSI_THRESHOLD,
+ sys_conf2->rssi_th);
+ Si4709_dev_band_set(sys_conf2->fm_band);
+ si47xx_set_property(FM_SEEK_FREQ_SPACING,
+ sys_conf2->fm_chan_spac);
+ Si4709_dev.settings.curr_rssi_th = sys_conf2->rssi_th;
+ Si4709_dev.settings.band = sys_conf2->fm_band;
+ Si4709_dev.settings.channel_spacing = sys_conf2->fm_chan_spac;
+
+ if (ret < 0) {
+ debug("Si4709_dev_sys_config2_set i2c_write 1 failed");
+ } else
+ debug(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));
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_sys_config3_set called "
+ "when DS is invalid");
+ ret = -1;
+ } else {
+ si47xx_set_property(FM_SEEK_TUNE_SNR_THRESHOLD,
+ sys_conf3->sksnr);
+ Si4709_dev.settings.curr_snr = sys_conf3->sksnr;
+ if (ret < 0) {
+ debug("Si4709_dev_sys_config3_set i2c_write 1 failed");
+ Si4709_dev.registers[SYSCONFIG3] = register_bak;
+ }
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+int Si4709_dev_power_config(struct power_config *pow_conf)
+{
+ int ret = 0;
+
+ debug("Si4709_dev_power_config called");
+
+ return ret;
+}
+
+/* VNVS:END */
+
+/* VNVS:START 18-NOV'09 */
+/* Reading AFCRL Bit */
+int Si4709_dev_AFCRL_get(u8 *afc)
+{
+ int ret = 0;
+
+ debug("Si4709_dev_AFCRL_get called");
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_AFCRL_get called when DS is invalid");
+ ret = -1;
+ } else {
+ fmRsqStatus(0);
+ if (ret < 0)
+ debug("Si4709_dev_AFCRL_get i2c_read failed");
+ *afc = AFCRL;
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+/* Setting DE
+ emphasis time constant 50us(Europe,Japan,Australia) or 75us(USA)
+ */
+int Si4709_dev_DE_set(u8 de_tc)
+{
+ u16 sysconfig1 = 0;
+ int ret = 0;
+
+ debug("Si4709_dev_DE_set called");
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ sysconfig1 = Si4709_dev.registers[SYSCONFIG1];
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_DE_set called when DS is invalid");
+ ret = -1;
+ } else {
+ switch (de_tc) {
+ case DE_TIME_CONSTANT_50:
+ si47xx_set_property(FM_DEEMPHASIS, FM_DEEMPH_50US);
+ break;
+
+ case DE_TIME_CONSTANT_75:
+ si47xx_set_property(FM_DEEMPHASIS, FM_DEEMPH_75US);
+ break;
+
+ default:
+ ret = -1;
+ }
+
+ if (0 == ret) {
+ if (ret < 0)
+ debug("Si4709_dev_DE_set i2c_write failed");
+ }
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+/*Resetting the RDS Data Buffer*/
+int Si4709_dev_reset_rds_data()
+{
+ int ret = 0;
+
+ debug_rds("Si4709_dev_reset_rds_data called");
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_reset_rds_data called when DS is invalid");
+ ret = -1;
+ } else {
+ RDS_Buffer_Index_write = 0;
+ RDS_Buffer_Index_read = 0;
+ RDS_Data_Lost = 0;
+ RDS_Data_Available = 0;
+ memset(RDS_Block_Data_buffer, 0, RDS_BUFFER_LENGTH * 8);
+ memset(RDS_Block_Error_buffer, 0, RDS_BUFFER_LENGTH * 4);
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+/*VNVS:END*/
+
+int Si4709_dev_VOLEXT_ENB(void)
+{
+ int ret = 0;
+
+ debug("Si4709_dev_VOLEXT_ENB called");
+
+ return ret;
+}
+
+int Si4709_dev_VOLEXT_DISB(void)
+{
+ int ret = 0;
+
+ debug("Si4709_dev_VOLEXT_DISB called");
+
+ 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));
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_volume_set called when DS is invalid");
+ ret = -1;
+ } else {
+ si47xx_set_property(RX_VOLUME, rx_vol[volume] & RX_VOLUME_MASK);
+
+ if (ret < 0) {
+ debug("Si4709_dev_volume_set i2c_write failed");
+ Si4709_dev.registers[SYSCONFIG2] = sysconfig2;
+ }
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+int Si4709_dev_volume_get(u8 *volume)
+{
+ int ret = 0;
+
+ debug("Si4709_dev_volume_get called");
+#if 0 /*To Do*/
+ mutex_lock(&(Si4709_dev.lock));
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_volume_get called when DS is invalid");
+ ret = -1;
+ } else
+ *volume =
+ SYSCONFIG2_GET_VOLUME(Si4709_dev.registers[SYSCONFIG2]);
+
+ mutex_unlock(&(Si4709_dev.lock));
+#endif
+ return ret;
+}
+
+/*
+VNVS:START 19-AUG'10 : Adding DSMUTE ON/OFF feature.
+The Soft Mute feature is available to attenuate the audio
+outputs and minimize audible noise in very weak signal conditions.
+ */
+int Si4709_dev_DSMUTE_ON(void)
+{
+ int ret = 0;
+ u16 powercfg = 0;
+
+ debug("Si4709_dev_DSMUTE_ON called");
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ powercfg = Si4709_dev.registers[POWERCFG];
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_DSMUTE_ON called when DS is invalid");
+ ret = -1;
+ } else {
+ si47xx_set_property(FM_SOFT_MUTE_RATE, 64);
+ si47xx_set_property(FM_SOFT_MUTE_MAX_ATTENUATION, 0);
+ si47xx_set_property(FM_SOFT_MUTE_SNR_THRESHOLD, 4);
+ if (ret < 0)
+ error("Si4709_dev_DSMUTE_ON i2c_write failed");
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+int Si4709_dev_DSMUTE_OFF(void)
+{
+ int ret = 0;
+ u16 powercfg = 0;
+
+ debug("Si4709_dev_DSMUTE_OFF called");
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ powercfg = Si4709_dev.registers[POWERCFG];
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_DSMUTE_OFF called when DS is invalid");
+ ret = -1;
+ } else {
+ si47xx_set_property(FM_SOFT_MUTE_RATE, 64);
+ si47xx_set_property(FM_SOFT_MUTE_MAX_ATTENUATION, 16);
+ si47xx_set_property(FM_SOFT_MUTE_SNR_THRESHOLD, 4);
+ if (ret < 0)
+ error("Si4709_dev_DSMUTE_OFF i2c_write failed");
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+/*VNVS:END*/
+
+int Si4709_dev_MUTE_ON(void)
+{
+ int ret = 0;
+ u16 powercfg = 0;
+
+ debug("Si4709_dev_MUTE_ON called");
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ powercfg = Si4709_dev.registers[POWERCFG];
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_MUTE_ON called when DS is invalid");
+ ret = -1;
+ } else {
+ si47xx_set_property(RX_HARD_MUTE,
+ RX_HARD_MUTE_RMUTE_MASK |
+ RX_HARD_MUTE_LMUTE_MASK);
+ if (ret < 0)
+ debug("Si4709_dev_MUTE_ON i2c_write failed");
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+int Si4709_dev_MUTE_OFF(void)
+{
+ int ret = 0;
+ u16 powercfg = 0;
+
+ debug("Si4709_dev_MUTE_OFF called");
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ powercfg = Si4709_dev.registers[POWERCFG];
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_MUTE_OFF called when DS is invalid");
+ ret = -1;
+ } else {
+ si47xx_set_property(RX_HARD_MUTE, 0);
+ if (ret < 0)
+ debug("Si4709_dev_MUTE_OFF i2c_write failed");
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+int Si4709_dev_MONO_SET(void)
+{
+ int ret = 0;
+ u16 powercfg = 0;
+
+ debug("Si4709_dev_MONO_SET called");
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ powercfg = Si4709_dev.registers[POWERCFG];
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_MONO_SET called when DS is invalid");
+ ret = -1;
+ } else {
+ si47xx_set_property(FM_BLEND_MONO_THRESHOLD, 127);
+ si47xx_set_property(FM_BLEND_STEREO_THRESHOLD, 127);
+ if (ret < 0)
+ debug("Si4709_dev_MONO_SET i2c_write failed");
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+int Si4709_dev_STEREO_SET(void)
+{
+ int ret = 0;
+ u16 powercfg = 0;
+
+ debug("Si4709_dev_STEREO_SET called");
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ powercfg = Si4709_dev.registers[POWERCFG];
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_STEREO_SET called when DS is invalid");
+ ret = -1;
+ } else {
+ si47xx_set_property(FM_BLEND_MONO_THRESHOLD, 30);
+ si47xx_set_property(FM_BLEND_STEREO_THRESHOLD, 49);
+ if (ret < 0)
+ debug("Si4709_dev_STEREO_SET i2c_write failed");
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+int Si4709_dev_RDS_ENABLE(void)
+{
+ int ret = 0;
+
+ debug("Si4709_dev_RDS_ENABLE called");
+
+ mutex_lock(&(Si4709_dev.lock));
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_RDS_ENABLE called when DS is invalid");
+ ret = -1;
+ } else {
+#ifdef RDS_INTERRUPT_ON_ALWAYS
+ si47xx_set_property(GPO_IEN, GPO_IEN_STCIEN_MASK |
+ GPO_IEN_STCREP_MASK | GPO_IEN_RDSIEN_MASK |
+ GPO_IEN_RDSREP_MASK);
+#endif
+ si47xx_set_property(FM_RDS_INTERRUPT_SOURCE,
+ FM_RDS_INTERRUPT_SOURCE_RECV_MASK);
+ si47xx_set_property(FM_RDS_CONFIG, FM_RDS_CONFIG_RDSEN_MASK |
+ (3 << FM_RDS_CONFIG_BLETHA_SHFT) |
+ (3 << FM_RDS_CONFIG_BLETHB_SHFT) |
+ (3 << FM_RDS_CONFIG_BLETHC_SHFT) |
+ (3 << FM_RDS_CONFIG_BLETHD_SHFT));
+ if (ret < 0)
+ debug("Si4709_dev_RDS_ENABLE i2c_write failed");
+#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)
+{
+ int ret = 0;
+
+ debug("Si4709_dev_RDS_DISABLE called");
+
+ mutex_lock(&(Si4709_dev.lock));
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_RDS_DISABLE called when DS is invalid");
+ ret = -1;
+ } else {
+ si47xx_set_property(FM_RDS_CONFIG, 0);
+
+ if (ret < 0)
+ debug("Si4709_dev_RDS_DISABLE i2c_write failed");
+#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) {
+ debug("Si4709_dev_rstate_get called when DS is invalid");
+ ret = -1;
+ } else {
+ dev_state->power_state = Si4709_dev.state.power_state;
+ dev_state->seek_state = Si4709_dev.state.seek_state;
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+/* VNVS:START 7-JUNE'10 Function call for work-queue "Si4709_wq" */
+#ifdef RDS_INTERRUPT_ON_ALWAYS
+void Si4709_work_func(struct work_struct *work)
+{
+ int i = 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);
+ fmRdsStatus(1, 0);
+ /* RDSR bit and RDS Block data, so reading the RDS registers */
+ do {
+ /* Writing into RDS_Block_Data_buffer */
+ i = 0;
+ RDS_Block_Data_buffer[i++ + 4 * RDS_Buffer_Index_write] =
+ BlockA;
+ RDS_Block_Data_buffer[i++ + 4 * RDS_Buffer_Index_write] =
+ BlockB;
+ RDS_Block_Data_buffer[i++ + 4 * RDS_Buffer_Index_write] =
+ BlockC;
+ RDS_Block_Data_buffer[i++ + 4 * RDS_Buffer_Index_write] =
+ BlockD;
+
+ /*Writing into RDS_Block_Error_buffer */
+ i = 0;
+
+ RDS_Block_Error_buffer[i++ + 4 * RDS_Buffer_Index_write] =
+ BleA;
+ RDS_Block_Error_buffer[i++ + 4 * RDS_Buffer_Index_write] =
+ BleB;
+ RDS_Block_Error_buffer[i++ + 4 * RDS_Buffer_Index_write] =
+ BleC;
+ RDS_Block_Error_buffer[i++ + 4 * RDS_Buffer_Index_write] =
+ BleD;
+ fmRdsStatus(1, 0);
+ } while (RdsFifoUsed != 0);
+
+#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;
+
+ debug_rds("Si4709_dev_RDS_data_get called");
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ 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) {
+ debug_rds("No_New_RDS_Data_is_available");
+ if (ret < 0)
+ error("Si4709_dev_RDS_data_get i2c_read 1 failed");
+ else {
+ fmTuneStatus(0, 0);
+ data->curr_channel = Freq;
+ data->curr_rssi = RSSI;
+ debug_rds("curr_channel: %u, curr_rssi:%u",
+ data->curr_channel,
+ (u32) data->curr_rssi);
+ }
+ mutex_unlock(&(Si4709_dev.lock));
+ return -1;
+ }
+ if (ret < 0)
+ error("Si4709_dev_RDS_data_get i2c_read 2 failed");
+ else {
+ fmTuneStatus(0, 0);
+ data->curr_channel = Freq;
+ data->curr_rssi = RSSI;
+ 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
+#if 0 /*To Do*/
+ SYSCONFIG1_BITSET_RDSIEN_HIGH(&Si4709_dev.registers[SYSCONFIG1]);
+
+ ret = i2c_write(SYSCONFIG1);
+ if (ret < 0) {
+ debug("Si4709_dev_RDS_data_get i2c_write 1 failed");
+ Si4709_dev.registers[SYSCONFIG1] = sysconfig1;
+ } else {
+ ret = i2c_read(SYSCONFIG1);
+ if (ret < 0)
+ debug("Si4709_dev_RDS_data_get i2c_read 1 failed");
+
+ debug("sysconfig1: 0x%x", Si4709_dev.registers[SYSCONFIG1]);
+
+ sysconfig1 = Si4709_dev.registers[SYSCONFIG1];
+
+ Si4709_dev_wait_flag = RDS_WAITING;
+
+ wait_RDS();
+
+ ret = i2c_read(STATUSRSSI);
+ if (ret < 0)
+ debug("Si4709_dev_RDS_data_get i2c_read 2 failed");
+
+ debug("statusrssi: 0x%x", Si4709_dev.registers[STATUSRSSI]);
+
+ SYSCONFIG1_BITSET_RDSIEN_LOW(&Si4709_dev.registers[SYSCONFIG1]);
+
+ ret = i2c_write(SYSCONFIG1);
+ if (ret < 0) {
+ debug("Si4709_dev_RDS_data_get i2c_write 2 failed");
+ Si4709_dev.registers[SYSCONFIG1] = sysconfig1;
+ } else if (Si4709_dev_wait_flag == WAIT_OVER) {
+ Si4709_dev_wait_flag = NO_WAIT;
+
+ ret = i2c_read(RDSD);
+ if (ret < 0)
+ debug("Si4709_dev_RDS_data_get "
+ "i2c_read 3 failed");
+ else {
+ data->rdsa = Si4709_dev.registers[RDSA];
+ data->rdsb = Si4709_dev.registers[RDSB];
+ data->rdsc = Si4709_dev.registers[RDSC];
+ data->rdsd = Si4709_dev.registers[RDSD];
+
+ get_cur_chan_freq(&(data->curr_channel),
+ Si4709_dev.registers[READCHAN]);
+ debug("curr_channel: %u", data->curr_channel);
+ data->curr_rssi =
+ STATUSRSSI_RSSI_SIGNAL_STRENGTH
+ (Si4709_dev.registers[STATUSRSSI]);
+ debug("curr_rssi:%u", (u32)data->curr_rssi);
+ data->blera =
+ STATUSRSSI_RDS_BLOCK_A_ERRORS
+ (Si4709_dev.registers[STATUSRSSI]);
+ data->blerb =
+ READCHAN_BLOCK_B_ERRORS(Si4709_dev.
+ registers[READCHAN]);
+ data->blerc =
+ READCHAN_BLOCK_C_ERRORS(Si4709_dev.
+ registers[READCHAN]);
+ data->blerd =
+ READCHAN_BLOCK_D_ERRORS(Si4709_dev.
+ registers[READCHAN]);
+ }
+ } else {
+ debug("Si4709_dev_RDS_data_get failure "
+ "no interrupt or timeout");
+ Si4709_dev_wait_flag = NO_WAIT;
+ mutex_unlock(&(Si4709_dev.lock));
+ return -1;
+ }
+ }
+#endif
+#endif
+
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+int Si4709_dev_RDS_timeout_set(u32 time_out)
+{
+ int ret = 0;
+ u32 jiffy_count = 0;
+
+ debug("Si4709_dev_RDS_timeout_set called");
+ /****convert time_out(in milliseconds) into jiffies*****/
+
+ jiffy_count = msecs_to_jiffies(time_out);
+
+ debug("jiffy_count%d", jiffy_count);
+
+ mutex_lock(&(Si4709_dev.lock));
+
+ if (Si4709_dev.valid == eFALSE) {
+ debug("Si4709_dev_RDS_timeout_set called when DS is invalid");
+ ret = -1;
+ } else {
+ Si4709_dev.settings.timeout_RDS = jiffy_count;
+ }
+
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+/**************************************************************/
+static int powerup(void)
+{
+ int ret = 0;
+ u16 powercfg = Si4709_dev.registers[POWERCFG];
+
+#if defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_M0_CTC)
+ gpio_set_value(Si4709_dev_sw, GPIO_LEVEL_HIGH);
+#endif
+
+ gpio_set_value(GPIO_FM_RST, GPIO_LEVEL_LOW);
+ usleep_range(5, 10);
+ s3c_gpio_cfgpin(Si4709_dev_int, S3C_GPIO_OUTPUT);
+ s3c_gpio_setpull(Si4709_dev_int, S3C_GPIO_PULL_DOWN);
+ gpio_set_value(Si4709_dev_int, GPIO_LEVEL_LOW);
+ usleep_range(10, 15);
+ gpio_set_value(GPIO_FM_RST, GPIO_LEVEL_HIGH);
+ usleep_range(5, 10);
+ s3c_gpio_cfgpin(Si4709_dev_int, S3C_GPIO_SFN(0xF));
+ s3c_gpio_setpull(Si4709_dev_int, S3C_GPIO_PULL_UP);
+ usleep_range(10, 15);
+
+ cmd[0] = POWER_UP;
+ cmd[1] = POWER_UP_IN_GPO2OEN;
+ cmd[1] |= POWER_UP_IN_FUNC_FMRX;
+ cmd[2] = POWER_UP_IN_OPMODE_RX_ANALOG;
+ ret = si47xx_command(3, cmd, 8, rsp);
+
+ if (ret < 0) {
+ debug("powerup->i2c_write 1 failed");
+ Si4709_dev.registers[POWERCFG] = powercfg;
+ } else {
+ /* Si4709/09 datasheet: Table 7 */
+ msleep(110);
+ Si4709_dev.state.power_state = RADIO_ON;
+ }
+ return ret;
+}
+
+static int powerdown(void)
+{
+ int ret = 0;
+
+ if (!(RADIO_POWERDOWN == Si4709_dev.state.power_state)) {
+ cmd[0] = POWER_DOWN;
+ ret = si47xx_command(1, cmd, 1, rsp);
+ msleep(110);
+
+ if (ret < 0)
+ debug("powerdown->i2c_write failed");
+ else
+ Si4709_dev.state.power_state = RADIO_POWERDOWN;
+
+ gpio_set_value(GPIO_FM_RST, GPIO_LEVEL_LOW);
+ } else
+ debug("Device already Powered-OFF\n");
+
+#if defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_M0_CTC)
+ gpio_set_value(Si4709_dev_sw, GPIO_LEVEL_LOW);
+#endif
+
+ return ret;
+}
+
+static int seek(u32 *frequency, int up, int mode)
+{
+ int ret = 0;
+ u8 get_int;
+
+ if (ret < 0) {
+ debug("seek i2c_write 1 failed");
+ } else {
+ Si4709_dev_wait_flag = SEEK_WAITING;
+ fmSeekStart(up, mode); /* mode 0 is full scan */
+ wait();
+ do {
+ get_int = getIntStatus();
+ } while (!(get_int & STCINT));
+
+ if (Si4709_dev_wait_flag == SEEK_CANCEL) {
+ fmTuneStatus(1, 0);
+ if (ret < 0) {
+ debug("seek i2c_write 2 failed");
+ }
+ if (ret < 0)
+ debug("seek i2c_read 1 failed");
+ else
+ *frequency = Freq;
+
+ *frequency = 0;
+ }
+
+ Si4709_dev_wait_flag = NO_WAIT;
+
+ fmTuneStatus(0, 1);
+ if (BLTF != 1)
+ *frequency = Freq;
+
+ else {
+ if (Valid)
+ *frequency = Freq;
+ else
+ *frequency = 0;
+ }
+ }
+ return ret;
+}
+
+static int tune_freq(u32 frequency)
+{
+ int ret = 0;
+
+ u16 channel = Si4709_dev.registers[CHANNEL];
+ mutex_lock(&(Si4709_dev.lock));
+
+ channel = freq_to_channel(frequency);
+ if (ret < 0) {
+ debug("tune_freq i2c_write 1 failed");
+ Si4709_dev.registers[CHANNEL] = channel;
+ } else {
+ Si4709_dev_wait_flag = TUNE_WAITING;
+ fmTuneFreq(frequency);
+ wait();
+ Si4709_dev_wait_flag = NO_WAIT;
+ debug("Si4709_dev_wait_flag = TUNE_WAITING\n");
+
+ if (!(getIntStatus() & STCINT)) {
+ printk(KERN_INFO "%s tune is failed!\n", __func__);
+ fmTuneStatus(1, 1);
+ mutex_unlock(&(Si4709_dev.lock));
+ return -1;
+ }
+
+ fmTuneStatus(0, 1);
+
+ debug("Si4709 tune_freq fmTuneStatus %x\n", rsp[0]);
+
+ }
+ mutex_unlock(&(Si4709_dev.lock));
+
+ return ret;
+}
+
+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;
+}
+
+/* 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
+
+/*-----------------------------------------------------------------------------
+ Helper function that sends the GET_INT_STATUS command to the part
+
+ Returns:
+ The status byte from the part.
+-----------------------------------------------------------------------------*/
+u8 getIntStatus(void)
+{
+ cmd[0] = GET_INT_STATUS;
+ si47xx_command(1, cmd, 1, rsp);
+
+ debug("Si4709 getIntStatus return %x\n", rsp[0]);
+ return rsp[0];
+}
+
+/*-----------------------------------------------------------------------------
+ Helper function that sends the FM_TUNE_FREQ command to the part
+
+ Inputs:
+ frequency in 10kHz steps
+-----------------------------------------------------------------------------*/
+static void fmTuneFreq(u16 frequency)
+{
+ cmd[0] = FM_TUNE_FREQ;
+ cmd[1] = 0;
+ cmd[2] = (u8)(frequency >> 8);
+ cmd[3] = (u8)(frequency & 0x00FF);
+ cmd[4] = (u8)0;
+ si47xx_command(5, cmd, 1, rsp);
+}
+
+/*-----------------------------------------------------------------------------
+ Helper function that sends the FM_TUNE_STATUS command to the part
+
+ Inputs:
+ cancel: If non-zero the current seek will be cancelled.
+ intack: If non-zero the interrupt for STCINT will be cleared.
+
+Outputs: These are global variables and are set by this method
+STC: The seek/tune is complete
+BLTF: The seek reached the band limit or original start frequency
+AFCRL: The AFC is railed if this is non-zero
+Valid: The station is valid if this is non-zero
+Freq: The current frequency
+RSSI: The RSSI level read at tune.
+ASNR: The audio SNR level read at tune.
+AntCap: The current level of the tuning capacitor.
+-----------------------------------------------------------------------------*/
+
+static void fmTuneStatus(u8 cancel, u8 intack)
+{
+ cmd[0] = FM_TUNE_STATUS;
+ cmd[1] = 0;
+ if (cancel)
+ cmd[1] |= FM_TUNE_STATUS_IN_CANCEL;
+ if (intack)
+ cmd[1] |= FM_TUNE_STATUS_IN_INTACK;
+
+ si47xx_command(2, cmd, 8, rsp);
+
+ STC = !!(rsp[0] & STCINT);
+ BLTF = !!(rsp[1] & FM_TUNE_STATUS_OUT_BTLF);
+ AFCRL = !!(rsp[1] & FM_TUNE_STATUS_OUT_AFCRL);
+ Valid = !!(rsp[1] & FM_TUNE_STATUS_OUT_VALID);
+ Freq = ((u16)rsp[2] << 8) | (u16)rsp[3];
+ RSSI = rsp[4];
+ ASNR = rsp[5];
+ AntCap = rsp[7];
+}
+
+/*-----------------------------------------------------------------------------
+ Helper function that sends the FM_RDS_STATUS command to the part
+
+ Inputs:
+ intack: If non-zero the interrupt for STCINT will be cleared.
+ mtfifo: If non-zero the fifo will be cleared.
+
+Outputs:
+Status: Contains bits about the status returned from the part.
+RdsInts: Contains bits about the interrupts that have fired
+related to RDS.
+RdsSync: If non-zero the RDS is currently synced.
+GrpLost: If non-zero some RDS groups were lost.
+RdsFifoUsed: The amount of groups currently remaining
+in the RDS fifo.
+BlockA: Block A group data from the oldest FIFO entry.
+BlockB: Block B group data from the oldest FIFO entry.
+BlockC: Block C group data from the oldest FIFO entry.
+BlockD: Block D group data from the oldest FIFO entry.
+BleA: Block A corrected error information.
+BleB: Block B corrected error information.
+BleC: Block C corrected error information.
+BleD: Block D corrected error information.
+-----------------------------------------------------------------------------*/
+void fmRdsStatus(u8 intack, u8 mtfifo)
+{
+ cmd[0] = FM_RDS_STATUS;
+ cmd[1] = 0;
+ if (intack)
+ cmd[1] |= FM_RDS_STATUS_IN_INTACK;
+ if (mtfifo)
+ cmd[1] |= FM_RDS_STATUS_IN_MTFIFO;
+
+ si47xx_command(2, cmd, 13, rsp);
+
+ Status = rsp[0];
+ RdsInts = rsp[1];
+ RdsSync = !!(rsp[2] & FM_RDS_STATUS_OUT_SYNC);
+ GrpLost = !!(rsp[2] & FM_RDS_STATUS_OUT_GRPLOST);
+ RdsFifoUsed = rsp[3];
+ BlockA = ((u16)rsp[4] << 8) | (u16)rsp[5];
+ BlockB = ((u16)rsp[6] << 8) | (u16)rsp[7];
+ BlockC = ((u16)rsp[8] << 8) | (u16)rsp[9];
+ BlockD = ((u16)rsp[10] << 8) | (u16)rsp[11];
+ BleA = (rsp[12] & FM_RDS_STATUS_OUT_BLEA) >>
+ FM_RDS_STATUS_OUT_BLEA_SHFT;
+ BleB = (rsp[12] & FM_RDS_STATUS_OUT_BLEB) >>
+ FM_RDS_STATUS_OUT_BLEB_SHFT;
+ BleC = (rsp[12] & FM_RDS_STATUS_OUT_BLEC) >>
+ FM_RDS_STATUS_OUT_BLEC_SHFT;
+ BleD = (rsp[12] & FM_RDS_STATUS_OUT_BLED) >>
+ FM_RDS_STATUS_OUT_BLED_SHFT;
+}
+
+
+/*-----------------------------------------------------------------------------
+ Helper function that sends the FM_RSQ_STATUS command to the part
+
+ Inputs:
+ intack: If non-zero the interrupt for STCINT will be cleared.
+
+Outputs:
+Status: Contains bits about the status returned from the part.
+RsqInts: Contains bits about the interrupts that have fired related to RSQ.
+SMUTE: The soft mute function is currently enabled
+AFCRL: The AFC is railed if this is non-zero
+Valid: The station is valid if this is non-zero
+Pilot: A pilot tone is currently present
+Blend: Percentage of blend for stereo. (100 = full stereo)
+RSSI: The RSSI level read at tune.
+ASNR: The audio SNR level read at tune.
+FreqOff: The frequency offset in kHz of the current station from the tuned
+frequency.
+-----------------------------------------------------------------------------*/
+static void fmRsqStatus(u8 intack)
+{
+ cmd[0] = FM_RSQ_STATUS;
+ cmd[1] = 0;
+ if (intack)
+ cmd[1] |= FM_RSQ_STATUS_IN_INTACK;
+
+ si47xx_command(2, cmd, 8, rsp);
+
+ Status = rsp[0];
+ RsqInts = rsp[1];
+ SMUTE = !!(rsp[2] & FM_RSQ_STATUS_OUT_SMUTE);
+ AFCRL = !!(rsp[2] & FM_RSQ_STATUS_OUT_AFCRL);
+ Valid = !!(rsp[2] & FM_RSQ_STATUS_OUT_VALID);
+ Pilot = !!(rsp[3] & FM_RSQ_STATUS_OUT_PILOT);
+ Blend = rsp[3] & FM_RSQ_STATUS_OUT_STBLEND;
+ RSSI = rsp[4];
+ ASNR = rsp[5];
+ FreqOff = rsp[7];
+}
+
+
+/*-----------------------------------------------------------------------------
+ Helper function that sends the FM_SEEK_START command to the part
+
+Inputs:
+seekUp: If non-zero seek will increment otherwise decrement
+wrap: If non-zero seek will wrap around band limits when hitting the end
+of the band limit.
+-----------------------------------------------------------------------------*/
+static void fmSeekStart(u8 seekUp, u8 wrap)
+{
+ cmd[0] = FM_SEEK_START;
+ cmd[1] = 0;
+ if (seekUp)
+ cmd[1] |= FM_SEEK_START_IN_SEEKUP;
+ if (wrap)
+ cmd[1] |= FM_SEEK_START_IN_WRAP;
+
+ si47xx_command(2, cmd, 1, rsp);
+}
+
+
+/*-----------------------------------------------------------------------------
+ Set the passed property number to the passed value.
+
+ Inputs:
+ propNumber: The number identifying the property to set
+ propValue: The value of the property.
+-----------------------------------------------------------------------------*/
+void si47xx_set_property(u16 propNumber, u16 propValue)
+{
+ cmd[0] = SET_PROPERTY;
+ cmd[1] = 0;
+ cmd[2] = (u8)(propNumber >> 8);
+ cmd[3] = (u8)(propNumber & 0x00FF);
+ cmd[4] = (u8)(propValue >> 8);
+ cmd[5] = (u8)(propValue & 0x00FF);
+
+ si47xx_command(6, cmd, 0, NULL);
+}
+
+/*-----------------------------------------------------------------------------
+ This command returns the status
+-----------------------------------------------------------------------------*/
+u8 si47xx_readStatus(void)
+{
+ u8 status;
+ i2c_read(1, &status);
+
+ return status;
+}
+
+
+/*-----------------------------------------------------------------------------
+ Command that will wait for CTS before returning
+-----------------------------------------------------------------------------*/
+void si47xx_waitForCTS(void)
+{
+ u16 i = 1000;
+ u8 rStatus = 0;
+
+ do {
+ rStatus = si47xx_readStatus();
+ usleep_range(5, 10);
+ } while (--i && !(rStatus & CTS));
+}
+
+/*-----------------------------------------------------------------------------
+ Sends a command to the part and returns the reply bytes
+-----------------------------------------------------------------------------*/
+int si47xx_command(u8 cmd_size, u8 *cmd, u8 reply_size, u8 *reply)
+{
+ int ret = 0;
+ ret = i2c_write(cmd_size, cmd);
+ si47xx_waitForCTS();
+
+ if (reply_size)
+ i2c_read(reply_size, reply);
+
+ if (ret < 0)
+ printk(KERN_INFO "%s i2c_write failed %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int i2c_write(u8 number_bytes, u8 *data_out)
+{
+ int ret = 0;
+
+ ret = i2c_master_send((struct i2c_client *)(Si4709_dev.client),
+ (const char *)data_out, number_bytes);
+ if (ret == number_bytes)
+ ret = 0;
+ else
+ ret = -1;
+
+ return ret;
+}
+
+static int i2c_read(u8 number_bytes, u8 *data_in)
+{
+ int ret = 0;
+
+ ret = i2c_master_recv((struct i2c_client *)(Si4709_dev.client), data_in,
+ number_bytes);
+ if (ret < 0)
+ printk(KERN_INFO "%s i2c_read failed %d\n", __func__, ret);
+
+ return ret;
+}
diff --git a/drivers/samsung/fm_si4709/Si4705_main.c b/drivers/samsung/fm_si4709/Si4705_main.c
new file mode 100644
index 0000000..aaccd5f
--- /dev/null
+++ b/drivers/samsung/fm_si4709/Si4705_main.c
@@ -0,0 +1,864 @@
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <linux/irq.h>
+#include <asm/irq.h>
+#include <linux/io.h>
+#include <linux/wait.h>
+#include <linux/stat.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+
+#include <plat/gpio-cfg.h>
+#include <mach/gpio.h>
+
+#include "Si4709_i2c_drv.h"
+#include "Si4709_dev.h"
+#include "Si4709_ioctl.h"
+#include "Si4709_common.h"
+
+/*******************************************************/
+
+/*static functions*/
+
+/*file operatons*/
+static int Si4709_open(struct inode *, struct file *);
+static int Si4709_release(struct inode *, struct file *);
+static long Si4709_ioctl(struct file *, unsigned int, unsigned long);
+
+/*ISR*/
+static irqreturn_t Si4709_isr(int irq, void *unused);
+/* static void __iomem *gpio_mask_mem; */
+/**********************************************************/
+
+static const struct file_operations Si4709_fops = {
+ .owner = THIS_MODULE,
+ .open = Si4709_open,
+ .unlocked_ioctl = Si4709_ioctl,
+ .release = Si4709_release,
+};
+
+static struct miscdevice Si4709_misc_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "fmradio",
+ .fops = &Si4709_fops,
+};
+
+/*VNVS:START 13-OCT'09----
+dummy struct which is used as a cookie for FM Radio interrupt */
+struct fm_radio {
+ int i;
+ int j;
+};
+
+struct fm_radio fm_radio_1;
+/*VNVS:END*/
+
+wait_queue_head_t Si4709_waitq;
+
+unsigned int Si4709_int;
+unsigned int Si4709_irq;
+
+/***************************************************************/
+
+static int Si4709_open(struct inode *inode, struct file *filp)
+{
+ debug("Si4709_open called\n");
+
+ return nonseekable_open(inode, filp);
+}
+
+static int Si4709_release(struct inode *inode, struct file *filp)
+{
+ debug("Si4709_release called\n\n");
+
+ return 0;
+}
+
+static long Si4709_ioctl(struct file *filp, unsigned int ioctl_cmd,
+ unsigned long arg)
+{
+ long ret = 0;
+ void __user *argp = (void __user *)arg;
+
+ debug("Si4709 ioctl 0x%x", ioctl_cmd);
+
+ if (_IOC_TYPE(ioctl_cmd) != Si4709_IOC_MAGIC) {
+ debug("Inappropriate ioctl 1 0x%x", ioctl_cmd);
+ return -ENOTTY;
+ }
+
+ if (_IOC_NR(ioctl_cmd) > Si4709_IOC_NR_MAX) {
+ debug("Inappropriate ioctl 2 0x%x", ioctl_cmd);
+ return -ENOTTY;
+ }
+
+
+ switch (ioctl_cmd) {
+ case Si4709_IOC_POWERUP:
+ debug("Si4709_IOC_POWERUP called\n\n");
+
+ ret = (long)Si4709_dev_powerup();
+ if (ret < 0)
+ debug("Si4709_IOC_POWERUP failed\n");
+ break;
+
+ case Si4709_IOC_POWERDOWN:
+ debug("Si4709_IOC_POWERDOWN called\n");
+
+ ret = (long)Si4709_dev_powerdown();
+ if (ret < 0)
+ debug("Si4709_IOC_POWERDOWN failed\n");
+ break;
+
+ case Si4709_IOC_BAND_SET:
+ {
+ int band;
+ debug("Si4709_IOC_BAND_SET called\n\n");
+
+ if (copy_from_user((void *)&band, argp, sizeof(int)))
+ ret = -EFAULT;
+ else {
+ ret = (long)Si4709_dev_band_set(band);
+ if (ret < 0)
+ debug("Si4709_IOC_BAND_SET failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_CHAN_SPACING_SET:
+ {
+ int ch_spacing;
+ debug("Si4709_IOC_CHAN_SPACING_SET called\n");
+
+ if (copy_from_user
+ ((void *)&ch_spacing, argp, sizeof(int)))
+ ret = -EFAULT;
+ else {
+ ret = (long)Si4709_dev_ch_spacing_set(ch_spacing);
+ if (ret < 0)
+ debug("Si4709_IOC_CHAN_SPACING_SET "
+ "failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_CHAN_SELECT:
+ {
+ u32 frequency;
+ debug("Si4709_IOC_CHAN_SELECT called\n");
+
+ if (copy_from_user
+ ((void *)&frequency, argp, sizeof(u32)))
+ ret = -EFAULT;
+ else {
+ ret = (long)Si4709_dev_chan_select(frequency);
+ if (ret < 0)
+ debug("Si4709_IOC_CHAN_SELECT "
+ "failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_CHAN_GET:
+ {
+ u32 frequency = 0;
+ debug("Si4709_IOC_CHAN_GET called\n");
+
+ ret = (long)Si4709_dev_chan_get(&frequency);
+ if (ret < 0)
+ debug("Si4709_IOC_CHAN_GET failed\n");
+ else if (copy_to_user
+ (argp, (void *)&frequency, sizeof(u32)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_SEEK_FULL:
+ {
+ u32 frequency = 0;
+ debug("Si4709_IOC_SEEK_FULL called\n");
+
+ ret = (long)Si4709_dev_seek_full(&frequency);
+ if (ret < 0)
+ debug("Si4709_IOC_SEEK_FULL failed\n");
+ else if (copy_to_user
+ (argp, (void *)&frequency, sizeof(u32)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_SEEK_UP:
+ {
+ u32 frequency = 0;
+ debug("Si4709_IOC_SEEK_UP called\n");
+
+ ret = (long)Si4709_dev_seek_up(&frequency);
+ if (ret < 0)
+ debug("Si4709_IOC_SEEK_UP failed\n");
+ else if (copy_to_user
+ (argp, (void *)&frequency, sizeof(u32)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_SEEK_DOWN:
+ {
+ u32 frequency = 0;
+ debug("Si4709_IOC_SEEK_DOWN called\n");
+
+ ret = (long)Si4709_dev_seek_down(&frequency);
+ if (ret < 0)
+ debug("Si4709_IOC_SEEK_DOWN failed\n");
+ else if (copy_to_user
+ (argp, (void *)&frequency, sizeof(u32)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_RSSI_SEEK_TH_SET:
+ {
+ u8 RSSI_seek_th;
+ debug("Si4709_IOC_RSSI_SEEK_TH_SET called\n");
+
+ if (copy_from_user
+ ((void *)&RSSI_seek_th, argp, sizeof(u8)))
+ ret = -EFAULT;
+ else {
+ ret = (long)Si4709_dev_RSSI_seek_th_set(RSSI_seek_th);
+ if (ret < 0)
+ debug("Si4709_IOC_RSSI_SEEK_TH_SET "
+ "failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_SEEK_SNR_SET:
+ {
+ u8 seek_SNR_th;
+ debug("Si4709_IOC_SEEK_SNR_SET called\n");
+
+ if (copy_from_user
+ ((void *)&seek_SNR_th, argp, sizeof(u8)))
+ ret = -EFAULT;
+ else {
+ ret = (long)Si4709_dev_seek_SNR_th_set(seek_SNR_th);
+ if (ret < 0)
+ debug("Si4709_IOC_SEEK_SNR_SET "
+ "failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_SEEK_CNT_SET:
+ {
+ u8 seek_FM_ID_th;
+ debug("Si4709_IOC_SEEK_CNT_SET called\n");
+
+ if (copy_from_user
+ ((void *)&seek_FM_ID_th, argp, sizeof(u8)))
+ ret = -EFAULT;
+ else {
+ ret =
+ (long)Si4709_dev_seek_FM_ID_th_set(seek_FM_ID_th);
+ if (ret < 0)
+ debug("Si4709_IOC_SEEK_CNT_SET "
+ "failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_CUR_RSSI_GET:
+ {
+ struct rssi_snr_t data;
+ debug("Si4709_IOC_CUR_RSSI_GET called\n");
+
+ ret = (long)Si4709_dev_cur_RSSI_get(&data);
+ if (ret < 0)
+ debug("Si4709_IOC_CUR_RSSI_GET failed\n");
+ else if (copy_to_user(argp, (void *)&data,
+ sizeof(data)))
+ ret = -EFAULT;
+
+ debug("curr_rssi:%d\ncurr_rssi_th:%d\ncurr_snr:%d\n",
+ data.curr_rssi, data.curr_rssi_th, data.curr_snr);
+ }
+ break;
+
+ case Si4709_IOC_VOLEXT_ENB:
+ debug("Si4709_IOC_VOLEXT_ENB called\n");
+
+ ret = (long)Si4709_dev_VOLEXT_ENB();
+ if (ret < 0)
+ debug("Si4709_IOC_VOLEXT_ENB failed\n");
+ break;
+
+ case Si4709_IOC_VOLEXT_DISB:
+ debug("Si4709_IOC_VOLEXT_DISB called\n");
+
+ ret = (long)Si4709_dev_VOLEXT_DISB();
+ if (ret < 0)
+ debug("Si4709_IOC_VOLEXT_DISB failed\n");
+ break;
+
+ case Si4709_IOC_VOLUME_SET:
+ {
+ u8 volume;
+ if (copy_from_user((void *)&volume, argp, sizeof(u8)))
+ ret = -EFAULT;
+ else {
+ debug("Si4709_IOC_VOLUME_SET called "
+ "vol %d\n", volume);
+ ret = (long)Si4709_dev_volume_set(volume);
+ if (ret < 0)
+ debug("Si4709_IOC_VOLUME_SET failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_VOLUME_GET:
+ {
+ u8 volume;
+ debug("Si4709_IOC_VOLUME_GET called\n");
+
+ ret = (long)Si4709_dev_volume_get(&volume);
+ if (ret < 0)
+ debug("Si4709_IOC_VOLUME_GET failed\n");
+ else if (copy_to_user
+ (argp, (void *)&volume, sizeof(u8)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_DSMUTE_ON:
+ debug("Si4709_IOC_DSMUTE_ON called\n\n");
+
+ ret = (long)Si4709_dev_DSMUTE_ON();
+ if (ret < 0)
+ error("Si4709_IOC_DSMUTE_ON failed\n");
+ break;
+
+ case Si4709_IOC_DSMUTE_OFF:
+ debug("Si4709_IOC_DSMUTE_OFF called\n\n");
+
+ ret = (long)Si4709_dev_DSMUTE_OFF();
+ if (ret < 0)
+ error("Si4709_IOC_DSMUTE_OFF failed\n");
+ break;
+
+ case Si4709_IOC_MUTE_ON:
+ debug("Si4709_IOC_MUTE_ON called\n");
+
+ ret = (long)Si4709_dev_MUTE_ON();
+ if (ret < 0)
+ debug("Si4709_IOC_MUTE_ON failed\n");
+ break;
+
+ case Si4709_IOC_MUTE_OFF:
+ debug("Si4709_IOC_MUTE_OFF called\n");
+
+ ret = (long)Si4709_dev_MUTE_OFF();
+ if (ret < 0)
+ debug("Si4709_IOC_MUTE_OFF failed\n");
+ break;
+
+ case Si4709_IOC_MONO_SET:
+ debug("Si4709_IOC_MONO_SET called\n");
+
+ ret = (long)Si4709_dev_MONO_SET();
+ if (ret < 0)
+ debug("Si4709_IOC_MONO_SET failed\n");
+ break;
+
+ case Si4709_IOC_STEREO_SET:
+ debug("Si4709_IOC_STEREO_SET called\n");
+
+ ret = (long)Si4709_dev_STEREO_SET();
+ if (ret < 0)
+ debug("Si4709_IOC_STEREO_SET failed\n");
+ break;
+
+ case Si4709_IOC_RSTATE_GET:
+ {
+ struct dev_state_t dev_state;
+
+ debug("Si4709_IOC_RSTATE_GET called\n");
+
+ ret = (long)Si4709_dev_rstate_get(&dev_state);
+ if (ret < 0)
+ debug("Si4709_IOC_RSTATE_GET failed\n");
+ else if (copy_to_user(argp, (void *)&dev_state,
+ sizeof(dev_state)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_RDS_DATA_GET:
+ {
+ struct radio_data_t data;
+ debug("Si4709_IOC_RDS_DATA_GET called\n");
+
+ ret = (long)Si4709_dev_RDS_data_get(&data);
+ if (ret < 0)
+ debug(" Si4709_IOC_RDS_DATA_GET failed\n");
+ else if (copy_to_user(argp, (void *)&data,
+ sizeof(data)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_RDS_ENABLE:
+ debug("Si4709_IOC_RDS_ENABLE called\n");
+
+ ret = (long)Si4709_dev_RDS_ENABLE();
+ if (ret < 0)
+ debug("Si4709_IOC_RDS_ENABLE failed\n");
+ break;
+
+ case Si4709_IOC_RDS_DISABLE:
+ debug("Si4709_IOC_RDS_DISABLE called\n");
+
+ ret = (long)Si4709_dev_RDS_DISABLE();
+ if (ret < 0)
+ debug("Si4709_IOC_RDS_DISABLE failed\n");
+ break;
+
+ case Si4709_IOC_RDS_TIMEOUT_SET:
+ {
+ u32 time_out;
+ debug("Si4709_IOC_RDS_TIMEOUT_SET called\n");
+
+ if (copy_from_user
+ ((void *)&time_out, argp, sizeof(u32)))
+ ret = -EFAULT;
+ else {
+ ret = (long)Si4709_dev_RDS_timeout_set(time_out);
+ if (ret < 0)
+ debug("Si4709_IOC_RDS_TIMEOUT_SET "
+ "failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_SEEK_CANCEL:
+ debug("Si4709_IOC_SEEK_CANCEL called\n");
+
+ if (Si4709_dev_wait_flag == SEEK_WAITING) {
+ Si4709_dev_wait_flag = SEEK_CANCEL;
+ wake_up_interruptible(&Si4709_waitq);
+ }
+ break;
+
+/*VNVS:START 13-OCT'09----
+Switch Case statements for calling functions which reads device-id,
+chip-id,power configuration, system configuration2 registers */
+ case Si4709_IOC_CHIP_ID_GET:
+ {
+ struct chip_id chp_id;
+ debug("Si4709_IOC_CHIP_ID called\n");
+
+ ret = (long)Si4709_dev_chip_id(&chp_id);
+ if (ret < 0)
+ debug("Si4709_IOC_CHIP_ID failed\n");
+ else if (copy_to_user(argp, (void *)&chp_id,
+ sizeof(chp_id)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_DEVICE_ID_GET:
+ {
+ struct device_id dev_id;
+ debug("Si4709_IOC_DEVICE_ID called\n");
+
+ ret = (long)Si4709_dev_device_id(&dev_id);
+ if (ret < 0)
+ debug("Si4709_IOC_DEVICE_ID failed\n");
+ else if (copy_to_user(argp, (void *)&dev_id,
+ sizeof(dev_id)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_SYS_CONFIG2_GET:
+ {
+ struct sys_config2 sys_conf2;
+ debug("Si4709_IOC_SYS_CONFIG2 called\n");
+
+ ret = (long)Si4709_dev_sys_config2(&sys_conf2);
+ if (ret < 0)
+ debug("Si4709_IOC_SYS_CONFIG2 failed\n");
+ else if (copy_to_user(argp, (void *)&sys_conf2,
+ sizeof(sys_conf2)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_SYS_CONFIG3_GET:
+ {
+ struct sys_config3 sys_conf3;
+ debug("Si4709_IOC_SYS_CONFIG3 called\n");
+
+ ret = (long)Si4709_dev_sys_config3(&sys_conf3);
+ if (ret < 0)
+ debug("Si4709_IOC_SYS_CONFIG3 failed\n");
+ else if (copy_to_user(argp, (void *)&sys_conf3,
+ sizeof(sys_conf3)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_POWER_CONFIG_GET:
+ {
+ struct power_config pow_conf;
+ debug("Si4709_IOC_POWER_CONFIG called\n");
+
+ ret = (long)Si4709_dev_power_config(&pow_conf);
+ if (ret < 0)
+ debug("Si4709_IOC_POWER_CONFIG failed\n");
+ else if (copy_to_user(argp, (void *)&pow_conf,
+ sizeof(pow_conf)))
+ ret = -EFAULT;
+ }
+ break;
+/*VNVS:END*/
+
+/*VNVS:START 18-NOV'09*/
+ /*Reading AFCRL Bit */
+ case Si4709_IOC_AFCRL_GET:
+ {
+ u8 afc;
+ debug("Si4709_IOC_AFCRL_GET called\n");
+
+ ret = (long)Si4709_dev_AFCRL_get(&afc);
+ if (ret < 0)
+ debug("Si4709_IOC_AFCRL_GET failed\n");
+ else if (copy_to_user(argp, (void *)&afc, sizeof(u8)))
+ ret = -EFAULT;
+ }
+ break;
+
+ /*Setting DE-emphasis Time Constant.
+ For DE=0,TC=50us(Europe,Japan,Australia)
+ and DE=1,TC=75us(USA) */
+ case Si4709_IOC_DE_SET:
+ {
+ u8 de_tc;
+ debug("Si4709_IOC_DE_SET called\n");
+
+ if (copy_from_user((void *)&de_tc, argp, sizeof(u8)))
+ ret = -EFAULT;
+ else {
+ ret = (long)Si4709_dev_DE_set(de_tc);
+ if (ret < 0)
+ debug("Si4709_IOC_DE_SET failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_STATUS_RSSI_GET:
+ {
+ struct status_rssi status;
+ debug("Si4709_IOC_STATUS_RSSI_GET called\n");
+
+ ret = (long)Si4709_dev_status_rssi(&status);
+ if (ret < 0)
+ debug("Si4709_IOC_STATUS_RSSI_GET failed\n");
+ else if (copy_to_user(argp, (void *)&status,
+ sizeof(status)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_SYS_CONFIG2_SET:
+ {
+ struct sys_config2 sys_conf2;
+ unsigned long n;
+ debug("Si4709_IOC_SYS_CONFIG2_SET called\n");
+
+ n = copy_from_user((void *)&sys_conf2, argp,
+ sizeof(sys_conf2));
+ if (n) {
+ debug("Si4709_IOC_SYS_CONFIG2_SET() : "
+ "copy_from_user() has error!! "
+ "Failed to read [%lu] byes!", n);
+ ret = -EFAULT;
+ } else {
+ ret = (long)Si4709_dev_sys_config2_set(&sys_conf2);
+ if (ret < 0)
+ debug("Si4709_IOC_SYS_CONFIG2_SET"
+ "failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_SYS_CONFIG3_SET:
+ {
+ struct sys_config3 sys_conf3;
+ unsigned long n;
+
+ debug("Si4709_IOC_SYS_CONFIG3_SET called\n");
+
+ n = copy_from_user((void *)&sys_conf3, argp,
+ sizeof(sys_conf3));
+ if (n) {
+ debug("Si4709_IOC_SYS_CONFIG3_SET() : "
+ "copy_from_user() has error!! "
+ "Failed to read [%lu] byes!", n);
+ ret = -EFAULT;
+ } else {
+ ret = (long)Si4709_dev_sys_config3_set(&sys_conf3);
+ if (ret < 0)
+ debug("Si4709_IOC_SYS_CONFIG3_SET "
+ "failed\n");
+ }
+ }
+ break;
+
+ /*Resetting the RDS Data Buffer */
+ case Si4709_IOC_RESET_RDS_DATA:
+ {
+ debug("Si4709_IOC_RESET_RDS_DATA called\n");
+
+ ret = (long)Si4709_dev_reset_rds_data();
+ if (ret < 0)
+ error("Si4709_IOC_RESET_RDS_DATA failed\n");
+ }
+ break;
+/*VNVS:END*/
+ default:
+ debug(" ioctl default\n");
+ ret = -ENOTTY;
+ break;
+ }
+
+ return ret;
+}
+
+static irqreturn_t Si4709_isr(int irq, void *unused)
+{
+ debug("Si4709_isr: FM device called IRQ: %d\n", irq);
+#ifdef RDS_INTERRUPT_ON_ALWAYS
+ if ((Si4709_dev_wait_flag == SEEK_WAITING) ||
+ (Si4709_dev_wait_flag == TUNE_WAITING)) {
+ debug("Si4709_isr: FM Seek/Tune Interrupt "
+ "called IRQ %d\n", irq);
+ Si4709_dev_wait_flag = WAIT_OVER;
+ wake_up_interruptible(&Si4709_waitq);
+ } else if (Si4709_RDS_flag == RDS_WAITING) { /* RDS Interrupt */
+ debug_rds("Si4709_isr: FM RDS Interrupt "
+ "called IRQ %d", irq);
+
+ debug_rds("RDS_Groups_Available_till_now b/w "
+ "Power ON/OFF : %d",
+ RDS_Groups_Available_till_now);
+
+ if (!work_pending(&Si4709_work))
+ queue_work(Si4709_wq, &Si4709_work);
+ }
+#else
+ if ((Si4709_dev_wait_flag == SEEK_WAITING) ||
+ (Si4709_dev_wait_flag == TUNE_WAITING) ||
+ (Si4709_dev_wait_flag == RDS_WAITING)) {
+ Si4709_dev_wait_flag = WAIT_OVER;
+ wake_up_interruptible(&Si4709_waitq);
+ }
+#endif
+ return IRQ_HANDLED;
+}
+
+/************************************************************/
+
+void debug_ioctls(void)
+{
+ debug("------------------------------------------------\n");
+
+ debug("Si4709_IOC_POWERUP 0x%x", Si4709_IOC_POWERUP);
+
+ debug("Si4709_IOC_POWERDOWN 0x%x", Si4709_IOC_POWERDOWN);
+
+ debug("Si4709_IOC_BAND_SET 0x%x", Si4709_IOC_BAND_SET);
+
+ debug("Si4709_IOC_CHAN_SPACING_SET 0x%x", Si4709_IOC_CHAN_SPACING_SET);
+
+ debug("Si4709_IOC_CHAN_SELECT 0x%x", Si4709_IOC_CHAN_SELECT);
+
+ debug("Si4709_IOC_CHAN_GET 0x%x", Si4709_IOC_CHAN_GET);
+
+ debug("Si4709_IOC_SEEK_UP 0x%x", Si4709_IOC_SEEK_UP);
+
+ debug("Si4709_IOC_SEEK_DOWN 0x%x", Si4709_IOC_SEEK_DOWN);
+
+ /*VNVS:28OCT'09---- Si4709_IOC_SEEK_AUTO is disabled as of now */
+ /* debug("Si4709_IOC_SEEK_AUTO 0x%x", Si4709_IOC_SEEK_AUTO); */
+
+ debug("Si4709_IOC_RSSI_SEEK_TH_SET 0x%x", Si4709_IOC_RSSI_SEEK_TH_SET);
+
+ debug("Si4709_IOC_SEEK_SNR_SET 0x%x", Si4709_IOC_SEEK_SNR_SET);
+
+ debug("Si4709_IOC_SEEK_CNT_SET 0x%x", Si4709_IOC_SEEK_CNT_SET);
+
+ debug("Si4709_IOC_CUR_RSSI_GET 0x%x", Si4709_IOC_CUR_RSSI_GET);
+
+ debug("Si4709_IOC_VOLEXT_ENB 0x%x", Si4709_IOC_VOLEXT_ENB);
+
+ debug("Si4709_IOC_VOLEXT_DISB 0x%x", Si4709_IOC_VOLEXT_DISB);
+
+ debug("Si4709_IOC_VOLUME_SET 0x%x", Si4709_IOC_VOLUME_SET);
+
+ debug("Si4709_IOC_VOLUME_GET 0x%x", Si4709_IOC_VOLUME_GET);
+
+ debug("Si4709_IOC_MUTE_ON 0x%x", Si4709_IOC_MUTE_ON);
+
+ debug("Si4709_IOC_MUTE_OFF 0x%x", Si4709_IOC_MUTE_OFF);
+
+ debug("Si4709_IOC_MONO_SET 0x%x", Si4709_IOC_MONO_SET);
+
+ debug("Si4709_IOC_STEREO_SET 0x%x", Si4709_IOC_STEREO_SET);
+
+ debug("Si4709_IOC_RSTATE_GET 0x%x", Si4709_IOC_RSTATE_GET);
+
+ debug("Si4709_IOC_RDS_DATA_GET 0x%x", Si4709_IOC_RDS_DATA_GET);
+
+ debug("Si4709_IOC_RDS_ENABLE 0x%x", Si4709_IOC_RDS_ENABLE);
+
+ debug("Si4709_IOC_RDS_DISABLE 0x%x", Si4709_IOC_RDS_DISABLE);
+
+ debug("Si4709_IOC_RDS_TIMEOUT_SET 0x%x", Si4709_IOC_RDS_TIMEOUT_SET);
+
+ debug("Si4709_IOC_DEVICE_ID_GET 0x%x", Si4709_IOC_DEVICE_ID_GET);
+
+ debug("Si4709_IOC_CHIP_ID_GET 0x%x", Si4709_IOC_CHIP_ID_GET);
+
+ debug("Si4709_IOC_SYS_CONFIG2_GET 0x%x", Si4709_IOC_SYS_CONFIG2_GET);
+
+ debug("Si4709_IOC_POWER_CONFIG_GET 0x%x", Si4709_IOC_POWER_CONFIG_GET);
+
+ debug("Si4709_IOC_AFCRL_GET 0x%x", Si4709_IOC_AFCRL_GET);
+
+ debug("Si4709_IOC_DE_SET 0x%x", Si4709_IOC_DE_SET);
+
+ debug("Si4709_IOC_DSMUTE_ON 0x%x", Si4709_IOC_DSMUTE_ON);
+
+ debug("Si4709_IOC_DSMUTE_OFF 0x%x", Si4709_IOC_DSMUTE_OFF);
+
+ debug("Si4709_IOC_RESET_RDS_DATA 0x%x", Si4709_IOC_RESET_RDS_DATA);
+
+ debug("------------------------------------------------\n");
+}
+
+int __init Si4709_driver_init(void)
+{
+ int ret = 0;
+
+ debug("Si4709_driver_init called\n");
+
+ /*Initialize the Si4709 dev mutex */
+ Si4709_dev_mutex_init();
+
+ /*misc device registration */
+ ret = misc_register(&Si4709_misc_device);
+ if (ret < 0) {
+ error("Si4709_driver_init misc_register failed\n");
+ return ret;
+ }
+
+#if defined(CONFIG_MACH_M0)
+ if (system_rev >= 15)
+ Si4709_int = GPIO_FM_INT_REV15;
+ else
+#endif
+ Si4709_int = GPIO_FM_INT;
+
+ Si4709_irq = gpio_to_irq(Si4709_int);
+
+ irq_set_irq_type(Si4709_irq, IRQ_TYPE_EDGE_FALLING);
+ /*KGVS: Configuring the GPIO_FM_INT in mach-jupiter.c */
+ ret = request_irq(Si4709_irq, Si4709_isr,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "Si4709", NULL);
+ if (ret) {
+ error("Si4709_driver_init request_irq "
+ "failed %d", Si4709_int);
+ goto MISC_DREG;
+ } else
+ debug("Si4709_driver_init request_irq "
+ "success %d", Si4709_int);
+
+ if (gpio_is_valid(GPIO_FM_RST)) {
+ if (gpio_request(GPIO_FM_RST, "GPC1"))
+ debug(KERN_ERR "Failed to request "
+ "FM_RESET!\n\n");
+ gpio_direction_output(GPIO_FM_RST, GPIO_LEVEL_LOW);
+ }
+
+#if defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_M0_CTC)
+ if (gpio_is_valid(GPIO_FM_MIC_SW)) {
+ if (gpio_request(GPIO_FM_MIC_SW, "GPL0"))
+ debug(KERN_ERR "Failed to request "
+ "FM_MIC_SW!\n\n");
+ gpio_direction_output(GPIO_FM_RST, GPIO_LEVEL_LOW);
+ }
+#endif
+
+ /*VNVS: 13-OCT'09----
+ Initially Pulling the interrupt pin HIGH
+ as the FM Radio device gives 5ms low pulse*/
+ s3c_gpio_setpull(Si4709_int, S3C_GPIO_PULL_UP);
+ /****Resetting the device****/
+ gpio_set_value(GPIO_FM_RST, GPIO_LEVEL_LOW);
+ s3c_gpio_cfgpin(Si4709_int, S3C_GPIO_OUTPUT);
+ s3c_gpio_setpull(Si4709_int, S3C_GPIO_PULL_DOWN);
+ gpio_set_value(GPIO_FM_RST, GPIO_LEVEL_HIGH);
+ usleep_range(10, 15);
+ s3c_gpio_cfgpin(Si4709_int, S3C_GPIO_SFN(0xF));
+ s3c_gpio_setpull(Si4709_int, S3C_GPIO_PULL_UP);
+
+ gpio_free(FM_RESET);
+
+ /*Add the i2c driver */
+ ret = Si4709_i2c_drv_init();
+ if (ret < 0)
+ goto MISC_IRQ_DREG;
+
+ init_waitqueue_head(&Si4709_waitq);
+
+ debug("Si4709_driver_init successful\n");
+
+ return ret;
+
+MISC_IRQ_DREG:
+ free_irq(Si4709_irq, NULL);
+MISC_DREG:
+ misc_deregister(&Si4709_misc_device);
+
+ return ret;
+}
+
+void __exit Si4709_driver_exit(void)
+{
+ debug("Si4709_driver_exit called\n");
+
+#if defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_M0_CTC)
+ gpio_free(GPIO_FM_MIC_SW);
+#endif
+
+ /*Delete the i2c driver */
+ Si4709_i2c_drv_exit();
+ free_irq(Si4709_irq, NULL);
+
+ /*misc device deregistration */
+ misc_deregister(&Si4709_misc_device);
+}
+
+module_init(Si4709_driver_init);
+module_exit(Si4709_driver_exit);
+MODULE_AUTHOR("Varun Mahajan <m.varun@samsung.com>");
+MODULE_DESCRIPTION("Si4709 FM tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/samsung/fm_si4709/Si4709_common.h b/drivers/samsung/fm_si4709/Si4709_common.h
new file mode 100644
index 0000000..b35f5b8
--- /dev/null
+++ b/drivers/samsung/fm_si4709/Si4709_common.h
@@ -0,0 +1,49 @@
+#ifndef _COMMON_H
+#define _COMMON_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <mach/gpio.h>
+
+/* #define Si4709_DEBUG */
+
+#define error(fmt, arg...) printk(KERN_CRIT fmt "\n", ##arg)
+
+#ifdef Si4709_DEBUG
+#define debug(fmt, arg...) printk(KERN_CRIT "--------" fmt "\n", ##arg)
+#else
+#define debug(fmt, arg...)
+#endif
+
+#define FM_RESET GPIO_FM_RST
+#if defined(CONFIG_MACH_Q1_CMCC_BD)
+#define FM_PORT "GPX13"
+#else
+#define FM_PORT "GPB"
+#endif
+
+#define FM_IRQ_INT gpio_to_irq(GPIO_FM_INT) /* GPB1(EXT_INT3[1]) */
+
+/* VNVS:28-OCT'09 : For testing FM tune and seek operation status */
+#define TEST_FM
+
+/* VNVS:7-JUNE'10 : RDS Interrupt ON Always */
+/* (Enabling interrupt when RDS is enabled) */
+#define RDS_INTERRUPT_ON_ALWAYS
+
+/* VNVS:18-JUN'10 : For testing RDS */
+/* Enable only for debugging RDS */
+/* #define RDS_TESTING */
+#ifdef RDS_TESTING
+#define debug_rds(fmt, arg...) printk(KERN_CRIT "--------" fmt "\n", ##arg)
+#define GROUP_TYPE_2A (2 * 2 + 0)
+#define GROUP_TYPE_2B (2 * 2 + 1)
+#else
+#define debug_rds(fmt, arg...)
+#endif
+
+#define YES 1
+#define NO 0
+
+#endif
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
diff --git a/drivers/samsung/fm_si4709/Si4709_dev.h b/drivers/samsung/fm_si4709/Si4709_dev.h
new file mode 100644
index 0000000..8b8371f
--- /dev/null
+++ b/drivers/samsung/fm_si4709/Si4709_dev.h
@@ -0,0 +1,231 @@
+#ifndef _Si4709_DEV_H
+#define _Si4709_DEV_H
+
+#include <linux/i2c.h>
+
+#include "Si4709_regs.h"
+#include "Si4709_common.h"
+
+#define NUM_SEEK_PRESETS 20
+
+#define WAIT_OVER 0
+#define SEEK_WAITING 1
+#define NO_WAIT 2
+#define TUNE_WAITING 4
+#define RDS_WAITING 5
+#define SEEK_CANCEL 6
+
+/*dev settings*/
+/*band*/
+#define BAND_87500_108000_kHz 1
+#define BAND_76000_108000_kHz 2
+#define BAND_76000_90000_kHz 3
+
+/*channel spacing*/
+#define CHAN_SPACING_200_kHz 20 /*US*/
+#define CHAN_SPACING_100_kHz 10 /*Europe,Japan */
+#define CHAN_SPACING_50_kHz 5
+/*DE-emphasis Time Constant*/
+#define DE_TIME_CONSTANT_50 1 /*Europe,Japan,Australia */
+#define DE_TIME_CONSTANT_75 0 /*US*/
+struct dev_state_t {
+ int power_state;
+ int seek_state;
+};
+
+struct rssi_snr_t {
+ u8 curr_rssi;
+ u8 curr_rssi_th;
+ u8 curr_snr;
+};
+
+struct device_id {
+ u8 part_number;
+ u16 manufact_number;
+};
+
+struct chip_id {
+ u8 chip_version;
+ u8 device;
+ u8 firmware_version;
+};
+
+struct sys_config2 {
+ u16 rssi_th;
+ u8 fm_band;
+ u8 fm_chan_spac;
+ u8 fm_vol;
+};
+
+struct sys_config3 {
+ u8 smmute;
+ u8 smutea;
+ u8 volext;
+ u8 sksnr;
+ u8 skcnt;
+};
+
+struct status_rssi {
+ u8 rdsr;
+ u8 stc;
+ u8 sfbl;
+ u8 afcrl;
+ u8 rdss;
+ u8 blera;
+ u8 st;
+ u16 rssi;
+};
+
+struct power_config {
+ u16 dsmute:1;
+ u16 dmute:1;
+ u16 mono:1;
+ u16 rds_mode:1;
+ u16 sk_mode:1;
+ u16 seek_up:1;
+ u16 seek:1;
+ u16 power_disable:1;
+ u16 power_enable:1;
+};
+
+struct radio_data_t {
+ u16 rdsa;
+ u16 rdsb;
+ u16 rdsc;
+ u16 rdsd;
+ u8 curr_rssi;
+ u32 curr_channel;
+ u8 blera;
+ u8 blerb;
+ u8 blerc;
+ u8 blerd;
+};
+
+struct channel_into_t {
+ u32 frequency;
+ u8 rsssi_val;
+};
+
+struct dev_settings_t {
+ u16 band;
+ u32 bottom_of_band;
+ u16 channel_spacing;
+ u32 timeout_RDS; /****For storing the jiffy value****/
+ u32 seek_preset[NUM_SEEK_PRESETS];
+ u8 curr_snr;
+ u8 curr_rssi_th;
+};
+
+struct Si4709_device_t {
+ /*Any function which
+ - views/modifies the fields of this structure
+ - does i2c communication
+ should lock the mutex before doing so.
+ Recursive locking should not be done.
+ In this file all the exported functions will take care
+ of this. The static functions will not deal with the
+ mutex */
+ struct mutex lock;
+
+ struct i2c_client const *client;
+
+ struct dev_state_t state;
+
+ struct dev_settings_t settings;
+
+ struct channel_into_t rssi_freq[50];
+
+ u16 registers[NUM_OF_REGISTERS];
+
+ /* This field will be checked by all the functions
+ exported by this file (except the init function),
+ to validate the the fields of this structure.
+ if eTRUE: the fileds are valid
+ if eFALSE: do not trust the values of the fields
+ of this structure */
+ unsigned short valid;
+
+ /*will be true is the client ans state fields are correct */
+ unsigned short valid_client_state;
+};
+
+extern int Si4709_dev_wait_flag;
+
+#ifdef RDS_INTERRUPT_ON_ALWAYS
+extern int Si4709_RDS_flag;
+extern int RDS_Data_Available;
+extern int RDS_Data_Lost;
+extern int RDS_Groups_Available_till_now;
+extern struct workqueue_struct *Si4709_wq;
+extern struct work_struct Si4709_work;
+#endif
+
+/* Function prototypes */
+
+/*extern functions*/
+/**********************************************/
+/* All the exported functions which view or modify the device
+ state/data, do i2c com will have to lock the mutex before
+ doing so
+*/
+/**********************************************/
+
+extern int Si4709_dev_init(struct i2c_client *);
+extern int Si4709_dev_exit(void);
+
+extern void Si4709_dev_mutex_init(void);
+
+extern int Si4709_dev_suspend(void);
+extern int Si4709_dev_resume(void);
+
+extern int Si4709_dev_powerup(void);
+extern int Si4709_dev_powerdown(void);
+
+extern int Si4709_dev_band_set(int);
+extern int Si4709_dev_ch_spacing_set(int);
+
+extern int Si4709_dev_chan_select(u32);
+extern int Si4709_dev_chan_get(u32 *);
+
+extern int Si4709_dev_seek_full(u32 *);
+extern int Si4709_dev_seek_up(u32 *);
+extern int Si4709_dev_seek_down(u32 *);
+extern int Si4709_dev_seek_auto(u32 *);
+
+extern int Si4709_dev_RSSI_seek_th_set(u8);
+extern int Si4709_dev_seek_SNR_th_set(u8);
+extern int Si4709_dev_seek_FM_ID_th_set(u8);
+extern int Si4709_dev_cur_RSSI_get(struct rssi_snr_t *);
+extern int Si4709_dev_VOLEXT_ENB(void);
+extern int Si4709_dev_VOLEXT_DISB(void);
+extern int Si4709_dev_volume_set(u8);
+extern int Si4709_dev_volume_get(u8 *);
+extern int Si4709_dev_DSMUTE_ON(void);
+extern int Si4709_dev_DSMUTE_OFF(void);
+extern int Si4709_dev_MUTE_ON(void);
+extern int Si4709_dev_MUTE_OFF(void);
+extern int Si4709_dev_MONO_SET(void);
+extern int Si4709_dev_STEREO_SET(void);
+extern int Si4709_dev_rstate_get(struct dev_state_t *);
+extern int Si4709_dev_RDS_data_get(struct radio_data_t *);
+extern int Si4709_dev_RDS_ENABLE(void);
+extern int Si4709_dev_RDS_DISABLE(void);
+extern int Si4709_dev_RDS_timeout_set(u32);
+extern int Si4709_dev_device_id(struct device_id *);
+extern int Si4709_dev_chip_id(struct chip_id *);
+extern int Si4709_dev_sys_config2(struct sys_config2 *);
+extern int Si4709_dev_sys_config3(struct sys_config3 *);
+extern int Si4709_dev_power_config(struct power_config *);
+extern int Si4709_dev_AFCRL_get(u8 *);
+extern int Si4709_dev_DE_set(u8);
+extern int Si4709_dev_status_rssi(struct status_rssi *status);
+extern int Si4709_dev_sys_config2_set(struct sys_config2 *sys_conf2);
+extern int Si4709_dev_sys_config3_set(struct sys_config3 *sys_conf3);
+extern int Si4709_dev_reset_rds_data(void);
+
+/***********************************************/
+
+#ifdef RDS_INTERRUPT_ON_ALWAYS
+extern void Si4709_work_func(struct work_struct *);
+#endif
+#endif
diff --git a/drivers/samsung/fm_si4709/Si4709_i2c_drv.c b/drivers/samsung/fm_si4709/Si4709_i2c_drv.c
new file mode 100644
index 0000000..4f92197
--- /dev/null
+++ b/drivers/samsung/fm_si4709/Si4709_i2c_drv.c
@@ -0,0 +1,192 @@
+
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+
+#include "Si4709_dev.h"
+#include "Si4709_common.h"
+#include "Si4709_i2c_drv.h"
+
+/*static functions*/
+static int Si4709_probe(struct i2c_client *);
+static int Si4709_remove(struct i2c_client *);
+static int Si4709_suspend(struct i2c_client *, pm_message_t mesg);
+static int Si4709_resume(struct i2c_client *);
+
+static struct i2c_client *Si4709_i2c_client;
+
+struct si4709_data {
+ struct i2c_client *client;
+};
+
+/*I2C Setting*/
+
+static struct i2c_driver Si4709_i2c_driver;
+
+#if 0
+static unsigned short Si4709_normal_i2c[] = { I2C_CLIENT_END };
+static unsigned short Si4709_ignore[] = { I2C_CLIENT_END };
+
+static unsigned short Si4709_i2c_probe[] = {
+ 8, SI4709_I2C_ADDRESS >> 1, I2C_CLIENT_END
+};
+
+static struct i2c_client_address_data Si4709_addr_data = {
+ .normal_i2c = Si4709_normal_i2c,
+ .ignore = Si4709_ignore,
+ .probe = Si4709_i2c_probe,
+};
+#endif
+
+static const struct i2c_device_id si4709_id[] = {
+ {"Si4709", 0},
+ {}
+};
+
+static int Si4709_probe(struct i2c_client *client)
+{
+ int ret = 0;
+
+ debug("Si4709 i2c driver Si4709_probe called");
+
+ if (strcmp(client->name, "Si4709") != 0) {
+ ret = -1;
+ error("Si4709_probe: device not supported");
+ } else {
+ ret = Si4709_dev_init(client);
+ if (ret < 0)
+ error("Si4709_dev_init failed");
+ }
+
+ return ret;
+}
+
+static int Si4709_remove(struct i2c_client *client)
+{
+ int ret = 0;
+
+ debug("Si4709 i2c driver Si4709_remove called");
+
+ if (strcmp(client->name, "Si4709") != 0) {
+ ret = -1;
+ error("Si4709_remove: device not supported");
+ } else {
+ ret = Si4709_dev_exit();
+ if (ret < 0)
+ error("Si4709_dev_exit failed");
+ }
+
+ return ret;
+}
+
+static int si4709_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int err = 0;
+ struct si4709_data *si4709_dev;
+
+ debug("----- %s %d\n", __func__, __LINE__);
+
+ si4709_dev = kzalloc(sizeof(struct si4709_data), GFP_KERNEL);
+
+ if (!si4709_dev) {
+ err = -ENOMEM;
+ return err;
+ }
+
+ Si4709_i2c_client = client;
+ i2c_set_clientdata(client, si4709_dev);
+
+ if (Si4709_i2c_client == NULL) {
+ error("Si4709 i2c_client is NULL");
+ return -ENODEV;
+ }
+
+ Si4709_probe(Si4709_i2c_client);
+
+ return 0;
+}
+
+static int __exit si4709_i2c_remove(struct i2c_client *client)
+{
+ struct si4709_data *si4709_dev = i2c_get_clientdata(client);
+
+ debug("----- %s %d\n", __func__, __LINE__);
+
+ Si4709_remove(Si4709_i2c_client);
+ kfree(si4709_dev);
+ kfree(client);
+ si4709_dev = NULL;
+ Si4709_i2c_client = NULL;
+
+ return 0;
+}
+
+MODULE_DEVICE_TABLE(i2c, si4709_id);
+
+static struct i2c_driver Si4709_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "Si4709",
+ },
+ .id_table = si4709_id,
+ .probe = si4709_i2c_probe,
+ .remove = __devexit_p(si4709_i2c_remove),
+ .suspend = Si4709_suspend,
+ .resume = Si4709_resume,
+};
+
+static int Si4709_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ int ret = 0;
+
+ debug("Si4709 i2c driver Si4709_suspend called");
+
+ if (strcmp(client->name, "Si4709") != 0) {
+ ret = -1;
+ error("Si4709_suspend: device not supported");
+ } else {
+ ret = Si4709_dev_suspend();
+ if (ret < 0)
+ error("Si4709_dev_disable failed");
+ }
+
+ return 0;
+}
+
+static int Si4709_resume(struct i2c_client *client)
+{
+ int ret = 0;
+
+ /* debug("Si4709 i2c driver Si4709_resume called"); */
+
+ if (strcmp(client->name, "Si4709") != 0) {
+ ret = -1;
+ error("Si4709_resume: device not supported");
+ } else {
+ ret = Si4709_dev_resume();
+ if (ret < 0)
+ error("Si4709_dev_enable failed");
+ }
+
+ return 0;
+}
+
+int Si4709_i2c_drv_init(void)
+{
+ int ret = 0;
+
+ debug("Si4709 i2c driver Si4709_i2c_driver_init called");
+
+ ret = i2c_add_driver(&Si4709_i2c_driver);
+ if (ret < 0)
+ error("Si4709 i2c_add_driver failed");
+
+ return ret;
+}
+
+void Si4709_i2c_drv_exit(void)
+{
+ debug("Si4709 i2c driver Si4709_i2c_driver_exit called");
+
+ i2c_del_driver(&Si4709_i2c_driver);
+}
diff --git a/drivers/samsung/fm_si4709/Si4709_i2c_drv.h b/drivers/samsung/fm_si4709/Si4709_i2c_drv.h
new file mode 100644
index 0000000..e734af4
--- /dev/null
+++ b/drivers/samsung/fm_si4709/Si4709_i2c_drv.h
@@ -0,0 +1,8 @@
+#ifndef _Si4709_I2C_DRV_H
+#define _Si4709_I2C_DRV_H
+
+/*extern functions*/
+extern int Si4709_i2c_drv_init(void);
+extern void Si4709_i2c_drv_exit(void);
+
+#endif
diff --git a/drivers/samsung/fm_si4709/Si4709_ioctl.h b/drivers/samsung/fm_si4709/Si4709_ioctl.h
new file mode 100644
index 0000000..e9fba9f
--- /dev/null
+++ b/drivers/samsung/fm_si4709/Si4709_ioctl.h
@@ -0,0 +1,121 @@
+#ifndef _Si4709_IOCTL_H
+#define _Si4709_IOCTL_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#include "Si4709_dev.h"
+
+/*****************IOCTLS******************/
+/*magic no*/
+#define Si4709_IOC_MAGIC 0xFA
+/*max seq no*/
+#define Si4709_IOC_NR_MAX 40
+
+/*commands*/
+
+#define Si4709_IOC_POWERUP _IO(Si4709_IOC_MAGIC, 0)
+
+#define Si4709_IOC_POWERDOWN _IO(Si4709_IOC_MAGIC, 1)
+
+#define Si4709_IOC_BAND_SET _IOW(Si4709_IOC_MAGIC, 2, int)
+
+#define Si4709_IOC_CHAN_SPACING_SET _IOW(Si4709_IOC_MAGIC, 3, int)
+
+#define Si4709_IOC_CHAN_SELECT _IOW(Si4709_IOC_MAGIC, 4, u32)
+
+#define Si4709_IOC_CHAN_GET _IOR(Si4709_IOC_MAGIC, 5, u32)
+
+#define Si4709_IOC_SEEK_UP _IOR(Si4709_IOC_MAGIC, 6, u32)
+
+#define Si4709_IOC_SEEK_DOWN _IOR(Si4709_IOC_MAGIC, 7, u32)
+
+/*VNVS:28OCT'09---- Si4709_IOC_SEEK_AUTO is disabled as of now*/
+/* #define Si4709_IOC_SEEK_AUTO _IOR(Si4709_IOC_MAGIC, 8, u32) */
+
+#define Si4709_IOC_RSSI_SEEK_TH_SET _IOW(Si4709_IOC_MAGIC, 9, u8)
+
+#define Si4709_IOC_SEEK_SNR_SET _IOW(Si4709_IOC_MAGIC, 10, u8)
+
+#define Si4709_IOC_SEEK_CNT_SET _IOW(Si4709_IOC_MAGIC, 11, u8)
+
+#define Si4709_IOC_CUR_RSSI_GET \
+_IOR(Si4709_IOC_MAGIC, 12, struct rssi_snr_t)
+
+#define Si4709_IOC_VOLEXT_ENB _IO(Si4709_IOC_MAGIC, 13)
+
+#define Si4709_IOC_VOLEXT_DISB _IO(Si4709_IOC_MAGIC, 14)
+
+#define Si4709_IOC_VOLUME_SET _IOW(Si4709_IOC_MAGIC, 15, u8)
+
+#define Si4709_IOC_VOLUME_GET _IOR(Si4709_IOC_MAGIC, 16, u8)
+
+#define Si4709_IOC_MUTE_ON _IO(Si4709_IOC_MAGIC, 17)
+
+#define Si4709_IOC_MUTE_OFF _IO(Si4709_IOC_MAGIC, 18)
+
+#define Si4709_IOC_MONO_SET _IO(Si4709_IOC_MAGIC, 19)
+
+#define Si4709_IOC_STEREO_SET _IO(Si4709_IOC_MAGIC, 20)
+
+#define Si4709_IOC_RSTATE_GET \
+_IOR(Si4709_IOC_MAGIC, 21, struct dev_state_t)
+
+#define Si4709_IOC_RDS_DATA_GET \
+_IOR(Si4709_IOC_MAGIC, 22, struct radio_data_t)
+
+#define Si4709_IOC_RDS_ENABLE _IO(Si4709_IOC_MAGIC, 23)
+
+#define Si4709_IOC_RDS_DISABLE _IO(Si4709_IOC_MAGIC, 24)
+
+#define Si4709_IOC_RDS_TIMEOUT_SET _IOW(Si4709_IOC_MAGIC, 25, u32)
+
+#define Si4709_IOC_SEEK_CANCEL _IO(Si4709_IOC_MAGIC, 26)
+
+/*VNVS:START 13-OCT'09 :
+ Added IOCTLs for reading the device-id,chip-id,power configuration,
+ system configuration2 registers*/
+#define Si4709_IOC_DEVICE_ID_GET \
+_IOR(Si4709_IOC_MAGIC, 27, struct device_id)
+
+#define Si4709_IOC_CHIP_ID_GET \
+_IOR(Si4709_IOC_MAGIC, 28, struct chip_id)
+
+#define Si4709_IOC_SYS_CONFIG2_GET \
+_IOR(Si4709_IOC_MAGIC, 29, struct sys_config2)
+
+#define Si4709_IOC_POWER_CONFIG_GET \
+_IOR(Si4709_IOC_MAGIC, 30, struct power_config)
+
+/* For reading AFCRL bit, to check for a valid channel */
+#define Si4709_IOC_AFCRL_GET _IOR(Si4709_IOC_MAGIC, 31, u8)
+
+/* Setting DE-emphasis Time Constant.
+For DE=0,TC=50us(Europe,Japan,Australia) and DE=1,TC=75us(USA) */
+#define Si4709_IOC_DE_SET _IOW(Si4709_IOC_MAGIC, 32, u8)
+/*VNVS:END*/
+
+#define Si4709_IOC_SYS_CONFIG3_GET \
+_IOR(Si4709_IOC_MAGIC, 33, struct sys_config3)
+
+#define Si4709_IOC_STATUS_RSSI_GET \
+_IOR(Si4709_IOC_MAGIC, 34, struct status_rssi)
+
+#define Si4709_IOC_SYS_CONFIG2_SET \
+_IOW(Si4709_IOC_MAGIC, 35, struct sys_config2)
+
+#define Si4709_IOC_SYS_CONFIG3_SET \
+_IOW(Si4709_IOC_MAGIC, 36, struct sys_config3)
+
+#define Si4709_IOC_DSMUTE_ON _IO(Si4709_IOC_MAGIC, 37)
+
+#define Si4709_IOC_DSMUTE_OFF _IO(Si4709_IOC_MAGIC, 38)
+
+#define Si4709_IOC_RESET_RDS_DATA _IO(Si4709_IOC_MAGIC, 39)
+
+#define Si4709_IOC_SEEK_FULL _IOR(Si4709_IOC_MAGIC, 40, u32)
+
+
+/*****************************************/
+
+#endif
diff --git a/drivers/samsung/fm_si4709/Si4709_main.c b/drivers/samsung/fm_si4709/Si4709_main.c
new file mode 100644
index 0000000..5531c12
--- /dev/null
+++ b/drivers/samsung/fm_si4709/Si4709_main.c
@@ -0,0 +1,844 @@
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <linux/irq.h>
+#include <asm/irq.h>
+#include <linux/io.h>
+#include <linux/wait.h>
+#include <linux/stat.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+
+#include <plat/gpio-cfg.h>
+#include <mach/gpio.h>
+
+#include "Si4709_i2c_drv.h"
+#include "Si4709_dev.h"
+#include "Si4709_ioctl.h"
+#include "Si4709_common.h"
+
+/*******************************************************/
+
+/*static functions*/
+
+/*file operatons*/
+static int Si4709_open(struct inode *, struct file *);
+static int Si4709_release(struct inode *, struct file *);
+static long Si4709_ioctl(struct file *, unsigned int, unsigned long);
+
+/*ISR*/
+static irqreturn_t Si4709_isr(int irq, void *unused);
+/* static void __iomem *gpio_mask_mem; */
+/**********************************************************/
+
+static const struct file_operations Si4709_fops = {
+ .owner = THIS_MODULE,
+ .open = Si4709_open,
+ .unlocked_ioctl = Si4709_ioctl,
+ .release = Si4709_release,
+};
+
+static struct miscdevice Si4709_misc_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "fmradio",
+ .fops = &Si4709_fops,
+};
+
+/*VNVS:START 13-OCT'09----
+dummy struct which is used as a cookie for FM Radio interrupt */
+struct fm_radio {
+ int i;
+ int j;
+};
+
+struct fm_radio fm_radio_1;
+/*VNVS:END*/
+
+wait_queue_head_t Si4709_waitq;
+
+unsigned int Si4709_int;
+unsigned int Si4709_irq;
+
+/***************************************************************/
+
+static int Si4709_open(struct inode *inode, struct file *filp)
+{
+ debug("Si4709_open called\n");
+
+ return nonseekable_open(inode, filp);
+}
+
+static int Si4709_release(struct inode *inode, struct file *filp)
+{
+ debug("Si4709_release called\n\n");
+
+ return 0;
+}
+
+static long Si4709_ioctl(struct file *filp, unsigned int ioctl_cmd,
+ unsigned long arg)
+{
+ long ret = 0;
+ void __user *argp = (void __user *)arg;
+
+ debug("Si4709 ioctl 0x%x", ioctl_cmd);
+
+ if (_IOC_TYPE(ioctl_cmd) != Si4709_IOC_MAGIC) {
+ error("Inappropriate ioctl 1 0x%x", ioctl_cmd);
+ return -ENOTTY;
+ }
+
+ if (_IOC_NR(ioctl_cmd) > Si4709_IOC_NR_MAX) {
+ error("Inappropriate ioctl 2 0x%x", ioctl_cmd);
+ return -ENOTTY;
+ }
+
+
+ switch (ioctl_cmd) {
+ case Si4709_IOC_POWERUP:
+ debug("Si4709_IOC_POWERUP called\n\n");
+
+ ret = (long)Si4709_dev_powerup();
+ if (ret < 0)
+ error("Si4709_IOC_POWERUP failed\n");
+ break;
+
+ case Si4709_IOC_POWERDOWN:
+ debug("Si4709_IOC_POWERDOWN called\n");
+
+ ret = (long)Si4709_dev_powerdown();
+ if (ret < 0)
+ error("Si4709_IOC_POWERDOWN failed\n");
+ break;
+
+ case Si4709_IOC_BAND_SET:
+ {
+ int band;
+ debug("Si4709_IOC_BAND_SET called\n\n");
+
+ if (copy_from_user((void *)&band, argp, sizeof(int)))
+ ret = -EFAULT;
+ else {
+ ret = (long)Si4709_dev_band_set(band);
+ if (ret < 0)
+ error("Si4709_IOC_BAND_SET failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_CHAN_SPACING_SET:
+ {
+ int ch_spacing;
+ debug("Si4709_IOC_CHAN_SPACING_SET called\n");
+
+ if (copy_from_user
+ ((void *)&ch_spacing, argp, sizeof(int)))
+ ret = -EFAULT;
+ else {
+ ret = (long)Si4709_dev_ch_spacing_set(ch_spacing);
+ if (ret < 0)
+ error("Si4709_IOC_CHAN_SPACING_SET "
+ "failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_CHAN_SELECT:
+ {
+ u32 frequency;
+ debug("Si4709_IOC_CHAN_SELECT called\n");
+
+ if (copy_from_user
+ ((void *)&frequency, argp, sizeof(u32)))
+ ret = -EFAULT;
+ else {
+ ret = (long)Si4709_dev_chan_select(frequency);
+ if (ret < 0)
+ error("Si4709_IOC_CHAN_SELECT "
+ "failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_CHAN_GET:
+ {
+ u32 frequency = 0;
+ debug("Si4709_IOC_CHAN_GET called\n");
+
+ ret = (long)Si4709_dev_chan_get(&frequency);
+ if (ret < 0)
+ error("Si4709_IOC_CHAN_GET failed\n");
+ else if (copy_to_user
+ (argp, (void *)&frequency, sizeof(u32)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_SEEK_UP:
+ {
+ u32 frequency = 0;
+ debug("Si4709_IOC_SEEK_UP called\n");
+
+ ret = (long)Si4709_dev_seek_up(&frequency);
+ if (ret < 0)
+ error("Si4709_IOC_SEEK_UP failed\n");
+ else if (copy_to_user
+ (argp, (void *)&frequency, sizeof(u32)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_SEEK_DOWN:
+ {
+ u32 frequency = 0;
+ debug("Si4709_IOC_SEEK_DOWN called\n");
+
+ ret = (long)Si4709_dev_seek_down(&frequency);
+ if (ret < 0)
+ error("Si4709_IOC_SEEK_DOWN failed\n");
+ else if (copy_to_user
+ (argp, (void *)&frequency, sizeof(u32)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_RSSI_SEEK_TH_SET:
+ {
+ u8 RSSI_seek_th;
+ debug("Si4709_IOC_RSSI_SEEK_TH_SET called\n");
+
+ if (copy_from_user
+ ((void *)&RSSI_seek_th, argp, sizeof(u8)))
+ ret = -EFAULT;
+ else {
+ ret = (long)Si4709_dev_RSSI_seek_th_set(RSSI_seek_th);
+ if (ret < 0)
+ error("Si4709_IOC_RSSI_SEEK_TH_SET "
+ "failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_SEEK_SNR_SET:
+ {
+ u8 seek_SNR_th;
+ debug("Si4709_IOC_SEEK_SNR_SET called\n");
+
+ if (copy_from_user
+ ((void *)&seek_SNR_th, argp, sizeof(u8)))
+ ret = -EFAULT;
+ else {
+ ret = (long)Si4709_dev_seek_SNR_th_set(seek_SNR_th);
+ if (ret < 0)
+ error("Si4709_IOC_SEEK_SNR_SET "
+ "failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_SEEK_CNT_SET:
+ {
+ u8 seek_FM_ID_th;
+ debug("Si4709_IOC_SEEK_CNT_SET called\n");
+
+ if (copy_from_user
+ ((void *)&seek_FM_ID_th, argp, sizeof(u8)))
+ ret = -EFAULT;
+ else {
+ ret =
+ (long)Si4709_dev_seek_FM_ID_th_set(seek_FM_ID_th);
+ if (ret < 0)
+ error("Si4709_IOC_SEEK_CNT_SET "
+ "failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_CUR_RSSI_GET:
+ {
+ struct rssi_snr_t data;
+ debug("Si4709_IOC_CUR_RSSI_GET called\n");
+
+ ret = (long)Si4709_dev_cur_RSSI_get(&data);
+ if (ret < 0)
+ error("Si4709_IOC_CUR_RSSI_GET failed\n");
+ else if (copy_to_user(argp, (void *)&data,
+ sizeof(data)))
+ ret = -EFAULT;
+
+ debug("curr_rssi:%d\ncurr_rssi_th:%d\ncurr_snr:%d\n",
+ data.curr_rssi, data.curr_rssi_th, data.curr_snr);
+ }
+ break;
+
+ case Si4709_IOC_VOLEXT_ENB:
+ debug("Si4709_IOC_VOLEXT_ENB called\n");
+
+ ret = (long)Si4709_dev_VOLEXT_ENB();
+ if (ret < 0)
+ error("Si4709_IOC_VOLEXT_ENB failed\n");
+ break;
+
+ case Si4709_IOC_VOLEXT_DISB:
+ debug("Si4709_IOC_VOLEXT_DISB called\n");
+
+ ret = (long)Si4709_dev_VOLEXT_DISB();
+ if (ret < 0)
+ error("Si4709_IOC_VOLEXT_DISB failed\n");
+ break;
+
+ case Si4709_IOC_VOLUME_SET:
+ {
+ u8 volume;
+ if (copy_from_user((void *)&volume, argp, sizeof(u8)))
+ ret = -EFAULT;
+ else {
+ debug("Si4709_IOC_VOLUME_SET called "
+ "vol %d\n", volume);
+ ret = (long)Si4709_dev_volume_set(volume);
+ if (ret < 0)
+ error("Si4709_IOC_VOLUME_SET failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_VOLUME_GET:
+ {
+ u8 volume;
+ debug("Si4709_IOC_VOLUME_GET called\n");
+
+ ret = (long)Si4709_dev_volume_get(&volume);
+ if (ret < 0)
+ error("Si4709_IOC_VOLUME_GET failed\n");
+ else if (copy_to_user
+ (argp, (void *)&volume, sizeof(u8)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_DSMUTE_ON:
+ debug("Si4709_IOC_DSMUTE_ON called\n\n");
+
+ ret = (long)Si4709_dev_DSMUTE_ON();
+ if (ret < 0)
+ error("Si4709_IOC_DSMUTE_ON failed\n");
+ break;
+
+ case Si4709_IOC_DSMUTE_OFF:
+ debug("Si4709_IOC_DSMUTE_OFF called\n\n");
+
+ ret = (long)Si4709_dev_DSMUTE_OFF();
+ if (ret < 0)
+ error("Si4709_IOC_DSMUTE_OFF failed\n");
+ break;
+
+ case Si4709_IOC_MUTE_ON:
+ debug("Si4709_IOC_MUTE_ON called\n");
+
+ ret = (long)Si4709_dev_MUTE_ON();
+ if (ret < 0)
+ error("Si4709_IOC_MUTE_ON failed\n");
+ break;
+
+ case Si4709_IOC_MUTE_OFF:
+ debug("Si4709_IOC_MUTE_OFF called\n");
+
+ ret = (long)Si4709_dev_MUTE_OFF();
+ if (ret < 0)
+ error("Si4709_IOC_MUTE_OFF failed\n");
+ break;
+
+ case Si4709_IOC_MONO_SET:
+ debug("Si4709_IOC_MONO_SET called\n");
+
+ ret = (long)Si4709_dev_MONO_SET();
+ if (ret < 0)
+ error("Si4709_IOC_MONO_SET failed\n");
+ break;
+
+ case Si4709_IOC_STEREO_SET:
+ debug("Si4709_IOC_STEREO_SET called\n");
+
+ ret = (long)Si4709_dev_STEREO_SET();
+ if (ret < 0)
+ error("Si4709_IOC_STEREO_SET failed\n");
+ break;
+
+ case Si4709_IOC_RSTATE_GET:
+ {
+ struct dev_state_t dev_state;
+
+ debug("Si4709_IOC_RSTATE_GET called\n");
+
+ ret = (long)Si4709_dev_rstate_get(&dev_state);
+ if (ret < 0)
+ error("Si4709_IOC_RSTATE_GET failed\n");
+ else if (copy_to_user(argp, (void *)&dev_state,
+ sizeof(dev_state)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_RDS_DATA_GET:
+ {
+ struct radio_data_t data;
+ debug("Si4709_IOC_RDS_DATA_GET called\n");
+
+ ret = (long)Si4709_dev_RDS_data_get(&data);
+ if (ret < 0)
+ error("Si4709_IOC_RDS_DATA_GET failed\n");
+ else if (copy_to_user(argp, (void *)&data,
+ sizeof(data)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_RDS_ENABLE:
+ debug("Si4709_IOC_RDS_ENABLE called\n");
+
+ ret = (long)Si4709_dev_RDS_ENABLE();
+ if (ret < 0)
+ error("Si4709_IOC_RDS_ENABLE failed\n");
+ break;
+
+ case Si4709_IOC_RDS_DISABLE:
+ debug("Si4709_IOC_RDS_DISABLE called\n");
+
+ ret = (long)Si4709_dev_RDS_DISABLE();
+ if (ret < 0)
+ error("Si4709_IOC_RDS_DISABLE failed\n");
+ break;
+
+ case Si4709_IOC_RDS_TIMEOUT_SET:
+ {
+ u32 time_out;
+ debug("Si4709_IOC_RDS_TIMEOUT_SET called\n");
+
+ if (copy_from_user
+ ((void *)&time_out, argp, sizeof(u32)))
+ ret = -EFAULT;
+ else {
+ ret = (long)Si4709_dev_RDS_timeout_set(time_out);
+ if (ret < 0)
+ error("Si4709_IOC_RDS_TIMEOUT_SET "
+ "failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_SEEK_CANCEL:
+ debug("Si4709_IOC_SEEK_CANCEL called\n");
+
+ if (Si4709_dev_wait_flag == SEEK_WAITING) {
+ Si4709_dev_wait_flag = SEEK_CANCEL;
+ wake_up_interruptible(&Si4709_waitq);
+ }
+ break;
+
+/*VNVS:START 13-OCT'09----
+Switch Case statements for calling functions which reads device-id,
+chip-id,power configuration, system configuration2 registers */
+ case Si4709_IOC_CHIP_ID_GET:
+ {
+ struct chip_id chp_id;
+ debug("Si4709_IOC_CHIP_ID called\n");
+
+ ret = (long)Si4709_dev_chip_id(&chp_id);
+ if (ret < 0)
+ error("Si4709_IOC_CHIP_ID failed\n");
+ else if (copy_to_user(argp, (void *)&chp_id,
+ sizeof(chp_id)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_DEVICE_ID_GET:
+ {
+ struct device_id dev_id;
+ debug("Si4709_IOC_DEVICE_ID called\n");
+
+ ret = (long)Si4709_dev_device_id(&dev_id);
+ if (ret < 0)
+ error("Si4709_IOC_DEVICE_ID failed\n");
+ else if (copy_to_user(argp, (void *)&dev_id,
+ sizeof(dev_id)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_SYS_CONFIG2_GET:
+ {
+ struct sys_config2 sys_conf2;
+ debug("Si4709_IOC_SYS_CONFIG2 called\n");
+
+ ret = (long)Si4709_dev_sys_config2(&sys_conf2);
+ if (ret < 0)
+ error("Si4709_IOC_SYS_CONFIG2 failed\n");
+ else if (copy_to_user(argp, (void *)&sys_conf2,
+ sizeof(sys_conf2)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_SYS_CONFIG3_GET:
+ {
+ struct sys_config3 sys_conf3;
+ debug("Si4709_IOC_SYS_CONFIG3 called\n");
+
+ ret = (long)Si4709_dev_sys_config3(&sys_conf3);
+ if (ret < 0)
+ error("Si4709_IOC_SYS_CONFIG3 failed\n");
+ else if (copy_to_user(argp, (void *)&sys_conf3,
+ sizeof(sys_conf3)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_POWER_CONFIG_GET:
+ {
+ struct power_config pow_conf;
+ debug("Si4709_IOC_POWER_CONFIG called\n");
+
+ ret = (long)Si4709_dev_power_config(&pow_conf);
+ if (ret < 0)
+ error("Si4709_IOC_POWER_CONFIG failed\n");
+ else if (copy_to_user(argp, (void *)&pow_conf,
+ sizeof(pow_conf)))
+ ret = -EFAULT;
+ }
+ break;
+/*VNVS:END*/
+
+/*VNVS:START 18-NOV'09*/
+ /*Reading AFCRL Bit */
+ case Si4709_IOC_AFCRL_GET:
+ {
+ u8 afc;
+ debug("Si4709_IOC_AFCRL_GET called\n");
+
+ ret = (long)Si4709_dev_AFCRL_get(&afc);
+ if (ret < 0)
+ error("Si4709_IOC_AFCRL_GET failed\n");
+ else if (copy_to_user(argp, (void *)&afc, sizeof(u8)))
+ ret = -EFAULT;
+ }
+ break;
+
+ /*Setting DE-emphasis Time Constant.
+ For DE=0,TC=50us(Europe,Japan,Australia)
+ and DE=1,TC=75us(USA) */
+ case Si4709_IOC_DE_SET:
+ {
+ u8 de_tc;
+ debug("Si4709_IOC_DE_SET called\n");
+
+ if (copy_from_user((void *)&de_tc, argp, sizeof(u8)))
+ ret = -EFAULT;
+ else {
+ ret = (long)Si4709_dev_DE_set(de_tc);
+ if (ret < 0)
+ error("Si4709_IOC_DE_SET failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_STATUS_RSSI_GET:
+ {
+ struct status_rssi status;
+ debug("Si4709_IOC_STATUS_RSSI_GET called\n");
+
+ ret = (long)Si4709_dev_status_rssi(&status);
+ if (ret < 0)
+ error("Si4709_IOC_STATUS_RSSI_GET failed\n");
+ else if (copy_to_user(argp, (void *)&status,
+ sizeof(status)))
+ ret = -EFAULT;
+ }
+ break;
+
+ case Si4709_IOC_SYS_CONFIG2_SET:
+ {
+ struct sys_config2 sys_conf2;
+ unsigned long n;
+ debug("Si4709_IOC_SYS_CONFIG2_SET called\n");
+
+ n = copy_from_user((void *)&sys_conf2, argp,
+ sizeof(sys_conf2));
+ if (n) {
+ debug("Si4709_IOC_SYS_CONFIG2_SET() : "
+ "copy_from_user() has error!! "
+ "Failed to read [%lu] byes!", n);
+ ret = -EFAULT;
+ } else {
+ ret = (long)Si4709_dev_sys_config2_set(&sys_conf2);
+ if (ret < 0)
+ error("Si4709_IOC_SYS_CONFIG2_SET"
+ "failed\n");
+ }
+ }
+ break;
+
+ case Si4709_IOC_SYS_CONFIG3_SET:
+ {
+ struct sys_config3 sys_conf3;
+ unsigned long n;
+
+ debug("Si4709_IOC_SYS_CONFIG3_SET called\n");
+
+ n = copy_from_user((void *)&sys_conf3, argp,
+ sizeof(sys_conf3));
+ if (n < 0) {
+ error("Si4709_IOC_SYS_CONFIG3_SET() : "
+ "copy_from_user() has error!! "
+ "Failed to read [%lu] byes!", n);
+ ret = -EFAULT;
+ } else {
+ ret = (long)Si4709_dev_sys_config3_set(&sys_conf3);
+ if (ret < 0)
+ error("Si4709_IOC_SYS_CONFIG3_SET "
+ "failed\n");
+ }
+ }
+ break;
+
+ /*Resetting the RDS Data Buffer */
+ case Si4709_IOC_RESET_RDS_DATA:
+ {
+ debug("Si4709_IOC_RESET_RDS_DATA called\n");
+
+ ret = (long)Si4709_dev_reset_rds_data();
+ if (ret < 0)
+ error("Si4709_IOC_RESET_RDS_DATA failed\n");
+ }
+ break;
+/*VNVS:END*/
+
+ default:
+ error(" ioctl default\n");
+ ret = -ENOTTY;
+ break;
+ }
+
+ return ret;
+}
+
+static irqreturn_t Si4709_isr(int irq, void *unused)
+{
+ debug("Si4709_isr: FM device called IRQ: %d", irq);
+#ifdef RDS_INTERRUPT_ON_ALWAYS
+ if ((Si4709_dev_wait_flag == SEEK_WAITING) ||
+ (Si4709_dev_wait_flag == TUNE_WAITING)) {
+ debug("Si4709_isr: FM Seek/Tune Interrupt "
+ "called IRQ %d\n", irq);
+ Si4709_dev_wait_flag = WAIT_OVER;
+ wake_up_interruptible(&Si4709_waitq);
+ } else if (Si4709_RDS_flag == RDS_WAITING) { /* RDS Interrupt */
+ debug_rds("Si4709_isr: FM RDS Interrupt "
+ "called IRQ %d", irq);
+ RDS_Data_Available++;
+ RDS_Groups_Available_till_now++;
+
+ debug_rds("RDS_Groups_Available_till_now b/w "
+ "Power ON/OFF : %d",
+ RDS_Groups_Available_till_now);
+
+ if (RDS_Data_Available > 1)
+ RDS_Data_Lost++;
+
+ if (!work_pending(&Si4709_work))
+ queue_work(Si4709_wq, &Si4709_work);
+ }
+#else
+ if ((Si4709_dev_wait_flag == SEEK_WAITING) ||
+ (Si4709_dev_wait_flag == TUNE_WAITING) ||
+ (Si4709_dev_wait_flag == RDS_WAITING)) {
+ Si4709_dev_wait_flag = WAIT_OVER;
+ wake_up_interruptible(&Si4709_waitq);
+ }
+#endif
+ return IRQ_HANDLED;
+}
+
+/************************************************************/
+
+void debug_ioctls(void)
+{
+ debug("------------------------------------------------\n");
+
+ debug("Si4709_IOC_POWERUP 0x%x", Si4709_IOC_POWERUP);
+
+ debug("Si4709_IOC_POWERDOWN 0x%x", Si4709_IOC_POWERDOWN);
+
+ debug("Si4709_IOC_BAND_SET 0x%x", Si4709_IOC_BAND_SET);
+
+ debug("Si4709_IOC_CHAN_SPACING_SET 0x%x", Si4709_IOC_CHAN_SPACING_SET);
+
+ debug("Si4709_IOC_CHAN_SELECT 0x%x", Si4709_IOC_CHAN_SELECT);
+
+ debug("Si4709_IOC_CHAN_GET 0x%x", Si4709_IOC_CHAN_GET);
+
+ debug("Si4709_IOC_SEEK_UP 0x%x", Si4709_IOC_SEEK_UP);
+
+ debug("Si4709_IOC_SEEK_DOWN 0x%x", Si4709_IOC_SEEK_DOWN);
+
+ /*VNVS:28OCT'09---- Si4709_IOC_SEEK_AUTO is disabled as of now */
+ /* debug("Si4709_IOC_SEEK_AUTO 0x%x", Si4709_IOC_SEEK_AUTO); */
+
+ debug("Si4709_IOC_RSSI_SEEK_TH_SET 0x%x", Si4709_IOC_RSSI_SEEK_TH_SET);
+
+ debug("Si4709_IOC_SEEK_SNR_SET 0x%x", Si4709_IOC_SEEK_SNR_SET);
+
+ debug("Si4709_IOC_SEEK_CNT_SET 0x%x", Si4709_IOC_SEEK_CNT_SET);
+
+ debug("Si4709_IOC_CUR_RSSI_GET 0x%x", Si4709_IOC_CUR_RSSI_GET);
+
+ debug("Si4709_IOC_VOLEXT_ENB 0x%x", Si4709_IOC_VOLEXT_ENB);
+
+ debug("Si4709_IOC_VOLEXT_DISB 0x%x", Si4709_IOC_VOLEXT_DISB);
+
+ debug("Si4709_IOC_VOLUME_SET 0x%x", Si4709_IOC_VOLUME_SET);
+
+ debug("Si4709_IOC_VOLUME_GET 0x%x", Si4709_IOC_VOLUME_GET);
+
+ debug("Si4709_IOC_MUTE_ON 0x%x", Si4709_IOC_MUTE_ON);
+
+ debug("Si4709_IOC_MUTE_OFF 0x%x", Si4709_IOC_MUTE_OFF);
+
+ debug("Si4709_IOC_MONO_SET 0x%x", Si4709_IOC_MONO_SET);
+
+ debug("Si4709_IOC_STEREO_SET 0x%x", Si4709_IOC_STEREO_SET);
+
+ debug("Si4709_IOC_RSTATE_GET 0x%x", Si4709_IOC_RSTATE_GET);
+
+ debug("Si4709_IOC_RDS_DATA_GET 0x%x", Si4709_IOC_RDS_DATA_GET);
+
+ debug("Si4709_IOC_RDS_ENABLE 0x%x", Si4709_IOC_RDS_ENABLE);
+
+ debug("Si4709_IOC_RDS_DISABLE 0x%x", Si4709_IOC_RDS_DISABLE);
+
+ debug("Si4709_IOC_RDS_TIMEOUT_SET 0x%x", Si4709_IOC_RDS_TIMEOUT_SET);
+
+ debug("Si4709_IOC_DEVICE_ID_GET 0x%x", Si4709_IOC_DEVICE_ID_GET);
+
+ debug("Si4709_IOC_CHIP_ID_GET 0x%x", Si4709_IOC_CHIP_ID_GET);
+
+ debug("Si4709_IOC_SYS_CONFIG2_GET 0x%x", Si4709_IOC_SYS_CONFIG2_GET);
+
+ debug("Si4709_IOC_POWER_CONFIG_GET 0x%x", Si4709_IOC_POWER_CONFIG_GET);
+
+ debug("Si4709_IOC_AFCRL_GET 0x%x", Si4709_IOC_AFCRL_GET);
+
+ debug("Si4709_IOC_DE_SET 0x%x", Si4709_IOC_DE_SET);
+
+ debug("Si4709_IOC_DSMUTE_ON 0x%x", Si4709_IOC_DSMUTE_ON);
+
+ debug("Si4709_IOC_DSMUTE_OFF 0x%x", Si4709_IOC_DSMUTE_OFF);
+
+ debug("Si4709_IOC_RESET_RDS_DATA 0x%x", Si4709_IOC_RESET_RDS_DATA);
+
+ debug("------------------------------------------------\n");
+}
+
+int __init Si4709_driver_init(void)
+{
+ int ret = 0;
+
+ debug("Si4709_driver_init called\n");
+
+ /*Initialize the Si4709 dev mutex */
+ Si4709_dev_mutex_init();
+
+ /*misc device registration */
+ ret = misc_register(&Si4709_misc_device);
+ if (ret < 0) {
+ error("Si4709_driver_init misc_register failed\n");
+ return ret;
+ }
+
+ if (system_rev >= 0x7) {
+ Si4709_int = GPIO_FM_INT_REV07;
+ Si4709_irq = gpio_to_irq(GPIO_FM_INT_REV07);
+ } else {
+ Si4709_int = GPIO_FM_INT;
+ Si4709_irq = gpio_to_irq(GPIO_FM_INT);
+ }
+
+ s3c_gpio_cfgpin(Si4709_int, S3C_GPIO_SFN(0xF));
+ s3c_gpio_setpull(Si4709_int, S3C_GPIO_PULL_NONE);
+
+ irq_set_irq_type(Si4709_irq, IRQ_TYPE_EDGE_FALLING);
+
+ /*KGVS: Configuring the GPIO_FM_INT in mach-jupiter.c */
+ ret = request_irq(Si4709_irq, Si4709_isr, IRQF_DISABLED,
+ "Si4709", NULL);
+ if (ret) {
+ error("Si4709_driver_init request_irq "
+ "failed %d", Si4709_int);
+ goto MISC_DREG;
+ } else
+ debug("Si4709_driver_init request_irq "
+ "success %d", Si4709_int);
+
+ if (gpio_is_valid(FM_RESET)) {
+ if (gpio_request(FM_RESET, FM_PORT))
+ debug(KERN_ERR "Failed to request "
+ "FM_RESET!\n");
+ gpio_direction_output(FM_RESET, GPIO_LEVEL_LOW);
+ }
+
+ /*VNVS: 13-OCT'09----
+ Initially Pulling the interrupt pin HIGH
+ as the FM Radio device gives 5ms low pulse*/
+ s3c_gpio_setpull(Si4709_int, S3C_GPIO_PULL_UP);
+
+ /****Resetting the device****/
+ gpio_set_value(FM_RESET, GPIO_LEVEL_LOW);
+ gpio_set_value(FM_RESET, GPIO_LEVEL_HIGH);
+ /*VNVS: 13-OCT'09---- Freeing the FM_RESET pin */
+
+ gpio_free(FM_RESET);
+
+ /*Add the i2c driver */
+ ret = Si4709_i2c_drv_init();
+ if (ret < 0)
+ goto MISC_IRQ_DREG;
+
+ init_waitqueue_head(&Si4709_waitq);
+
+ debug("Si4709_driver_init successful\n");
+
+ return ret;
+
+MISC_IRQ_DREG:
+ free_irq(Si4709_irq, NULL);
+MISC_DREG:
+ misc_deregister(&Si4709_misc_device);
+
+ return ret;
+}
+
+void __exit Si4709_driver_exit(void)
+{
+ debug("Si4709_driver_exit called\n");
+
+ /*Delete the i2c driver */
+ Si4709_i2c_drv_exit();
+ free_irq(Si4709_irq, NULL);
+
+ /*misc device deregistration */
+ misc_deregister(&Si4709_misc_device);
+}
+
+module_init(Si4709_driver_init);
+module_exit(Si4709_driver_exit);
+MODULE_AUTHOR("Varun Mahajan <m.varun@samsung.com>");
+MODULE_DESCRIPTION("Si4709 FM tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/samsung/fm_si4709/Si4709_main.h b/drivers/samsung/fm_si4709/Si4709_main.h
new file mode 100644
index 0000000..61d8872
--- /dev/null
+++ b/drivers/samsung/fm_si4709/Si4709_main.h
@@ -0,0 +1,8 @@
+#ifndef _Si4709_MAIN_H
+#define _Si4709_MAIN_H
+
+#include <linux/wait.h>
+
+extern wait_queue_head_t Si4709_waitq;
+
+#endif
diff --git a/drivers/samsung/fm_si4709/Si4709_regs.h b/drivers/samsung/fm_si4709/Si4709_regs.h
new file mode 100644
index 0000000..aa77651
--- /dev/null
+++ b/drivers/samsung/fm_si4709/Si4709_regs.h
@@ -0,0 +1,799 @@
+#ifndef _Si4709_REGS_H
+#define _Si4709_REGS_H
+
+#define NUM_OF_REGISTERS 0x10
+
+/*Si4709 registers*/
+#define DEVICE_ID 0x00
+#define CHIP_ID 0x01
+#define POWERCFG 0x02
+#define CHANNEL 0x03
+#define SYSCONFIG1 0x04
+#define SYSCONFIG2 0x05
+#define SYSCONFIG3 0x06
+#define TEST1 0x07
+#define TEST2 0x08
+#define BOOTCONFIG 0x09
+#define STATUSRSSI 0x0A
+#define READCHAN 0x0B
+#define RDSA 0x0C
+#define RDSB 0x0D
+#define RDSC 0x0E
+#define RDSD 0x0F
+
+/***********POWERCFG************/
+#define POWERCFG_DSMUTE 0x8000
+#define POWERCFG_DMUTE 0x4000
+#define POWERCFG_MONO 0x2000
+#define POWERCFG_RDSM 0x0800
+#define POWERCFG_SKMODE 0x0400
+#define POWERCFG_SEEKUP 0x0200
+#define POWERCFG_SEEK 0x0100
+#define POWERCFG_DISABLE 0x0040
+#define POWERCFG_ENABLE 0x0001
+/************************************/
+
+/***********CHANNEL************/
+#define CHANNEL_TUNE 0x8000
+/************************************/
+
+/***********SYSCONFIG1************/
+#define SYSCONFIG1_RDSIEN 0x8000
+#define SYSCONFIG1_STCIEN 0x4000
+#define SYSCONFIG1_RDS 0x1000
+#define SYSCONFIG1_DE 0x0800
+#define SYSCONFIG1_AGCD 0x0400
+#define SYSCONFIG1_BLNDADJ1 0x0080
+#define SYSCONFIG1_BLNDADJ0 0x0040
+#define SYSCONFIG1_GPO1 0x0008
+#define SYSCONFIG1_GPO0 0x0004
+/************************************/
+
+/***********SYSCONFIG2************/
+#define SYSCONFIG2_BAND1 0x0080
+#define SYSCONFIG2_BAND0 0x0040
+#define SYSCONFIG2_SPACE1 0x0020
+#define SYSCONFIG2_SPACE0 0x0010
+#define SYSCONFIG2_VOLUME3 0x0008
+#define SYSCONFIG2_VOLUME2 0x0004
+#define SYSCONFIG2_VOLUME1 0x0002
+#define SYSCONFIG2_VOLUME0 0x0001
+/************************************/
+
+/***********SYSCONFIG3************/
+#define SYSCONFIG3_SMUTER1 0x8000
+#define SYSCONFIG3_SMUTER0 0x4000
+#define SYSCONFIG3_SMUTEA1 0x2000
+#define SYSCONFIG3_SMUTEA0 0x1000
+#define SYSCONFIG3_VOLEXT 0x0100
+#define SYSCONFIG3_SKSNR3 0x0080
+#define SYSCONFIG3_SKSNR2 0x0040
+#define SYSCONFIG3_SKSNR1 0x0020
+#define SYSCONFIG3_SKSNR0 0x0010
+#define SYSCONFIG3_SKCNT3 0x0008
+#define SYSCONFIG3_SKCNT2 0x0004
+#define SYSCONFIG3_SKCNT1 0x0002
+#define SYSCONFIG3_SKCNT0 0x0001
+/************************************/
+
+/***********TEST1************/
+#define TEST1_AHIZEN 0x4000
+/************************************/
+
+/***********STATUSRSSI************/
+#define STATUSRSSI_RDSR 0x8000
+#define STATUSRSSI_STC 0x4000
+#define STATUSRSSI_SF_BL 0x2000
+#define STATUSRSSI_AFCRL 0x1000
+#define STATUSRSSI_RDSS 0x0800
+#define STATUSRSSI_BLERA1 0x0400
+#define STATUSRSSI_BLERA0 0x0200
+#define STATUSRSSI_ST 0x0100
+/************************************/
+
+/***********READCHAN************/
+#define READCHAN_BLERB1 0x8000
+#define READCHAN_BLERB0 0x4000
+#define READCHAN_BLERC1 0x2000
+#define READCHAN_BLERC0 0x1000
+#define READCHAN_BLERD1 0x0800
+#define READCHAN_BLERD0 0x0400
+
+#define READCHAN_CHAN_MASK 0x03FF
+/************************************/
+
+/*************************************************************/
+static inline void switch_on_bits(u16 *data, u16 bits_on)
+{
+ *data |= bits_on;
+}
+
+static inline void switch_off_bits(u16 *data, u16 bits_off)
+{
+ u16 aux = 0xFFFF;
+ aux ^= bits_off;
+ *data &= aux;
+}
+
+#define BIT_ON 1
+#define BIT_OFF 0
+
+static inline int check_bit(u16 data, u16 bit)
+{
+ return data & bit ? BIT_ON : BIT_OFF;
+}
+
+/**************************************************************/
+
+/********************************************************************/
+static inline void POWERCFG_BITSET_ENABLE_HIGH(u16 *data)
+{
+ switch_on_bits(data, (POWERCFG_ENABLE));
+}
+
+static inline void POWERCFG_BITSET_DISABLE_HIGH(u16 *data)
+{
+ switch_on_bits(data, (POWERCFG_DISABLE));
+}
+
+static inline void POWERCFG_BITSET_DISABLE_LOW(u16 *data)
+{
+ switch_off_bits(data, (POWERCFG_DISABLE));
+}
+
+static inline void POWERCFG_BITSET_DMUTE_HIGH(u16 *data)
+{
+ switch_on_bits(data, (POWERCFG_DMUTE));
+}
+
+static inline void POWERCFG_BITSET_DMUTE_LOW(u16 *data)
+{
+ switch_off_bits(data, (POWERCFG_DMUTE));
+}
+
+static inline void POWERCFG_BITSET_DSMUTE_HIGH(u16 *data)
+{
+ switch_on_bits(data, (POWERCFG_DSMUTE));
+}
+
+static inline void POWERCFG_BITSET_DSMUTE_LOW(u16 *data)
+{
+ switch_off_bits(data, (POWERCFG_DSMUTE));
+}
+
+static inline void POWERCFG_BITSET_MONO_HIGH(u16 *data)
+{
+ switch_on_bits(data, (POWERCFG_MONO));
+}
+
+static inline void POWERCFG_BITSET_MONO_LOW(u16 *data)
+{
+ switch_off_bits(data, (POWERCFG_MONO));
+}
+
+static inline void POWERCFG_BITSET_RDSM_HIGH(u16 *data)
+{
+ switch_on_bits(data, (POWERCFG_RDSM));
+}
+
+static inline void POWERCFG_BITSET_RDSM_LOW(u16 *data)
+{
+ switch_off_bits(data, (POWERCFG_RDSM));
+}
+
+static inline void POWERCFG_BITSET_SKMODE_HIGH(u16 *data)
+{
+ switch_on_bits(data, (POWERCFG_SKMODE));
+}
+
+static inline void POWERCFG_BITSET_SKMODE_LOW(u16 *data)
+{
+ switch_off_bits(data, (POWERCFG_SKMODE));
+}
+
+static inline void POWERCFG_BITSET_SEEKUP_HIGH(u16 *data)
+{
+ switch_on_bits(data, (POWERCFG_SEEKUP));
+}
+
+static inline void POWERCFG_BITSET_SEEKUP_LOW(u16 *data)
+{
+ switch_off_bits(data, (POWERCFG_SEEKUP));
+}
+
+static inline void POWERCFG_BITSET_SEEK_HIGH(u16 *data)
+{
+ switch_on_bits(data, (POWERCFG_SEEK));
+}
+
+static inline void POWERCFG_BITSET_SEEK_LOW(u16 *data)
+{
+ switch_off_bits(data, (POWERCFG_SEEK));
+}
+
+static inline void POWERCFG_BITSET_RESERVED(u16 *data)
+{
+ *data &= 0xEF41;
+}
+
+/********************************************************************/
+
+static inline void CHANNEL_BITSET_TUNE_HIGH(u16 *data)
+{
+ switch_on_bits(data, (CHANNEL_TUNE));
+}
+
+static inline void CHANNEL_BITSET_TUNE_LOW(u16 *data)
+{
+ switch_off_bits(data, (CHANNEL_TUNE));
+}
+
+static inline void CHANNEL_BITSET_RESERVED(u16 *data)
+{
+ *data &= 0x83FF;
+}
+
+/********************************************************************/
+
+static inline void SYSCONFIG1_BITSET_RDSIEN_HIGH(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG1_RDSIEN));
+}
+
+static inline void SYSCONFIG1_BITSET_RDSIEN_LOW(u16 *data)
+{
+ switch_off_bits(data, (SYSCONFIG1_RDSIEN));
+}
+
+static inline void SYSCONFIG1_BITSET_STCIEN_HIGH(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG1_STCIEN));
+}
+
+static inline void SYSCONFIG1_BITSET_STCIEN_LOW(u16 *data)
+{
+ switch_off_bits(data, (SYSCONFIG1_STCIEN));
+}
+
+static inline void SYSCONFIG1_BITSET_RDS_HIGH(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG1_RDS));
+}
+
+static inline void SYSCONFIG1_BITSET_RDS_LOW(u16 *data)
+{
+ switch_off_bits(data, (SYSCONFIG1_RDS));
+}
+
+static inline void SYSCONFIG1_BITSET_DE_50(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG1_DE));
+}
+
+static inline void SYSCONFIG1_BITSET_DE_75(u16 *data)
+{
+ switch_off_bits(data, (SYSCONFIG1_DE));
+}
+
+static inline void SYSCONFIG1_BITSET_AGCD_HIGH(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG1_AGCD));
+}
+
+static inline void SYSCONFIG1_BITSET_AGCD_LOW(u16 *data)
+{
+ switch_off_bits(data, (SYSCONFIG1_AGCD));
+}
+
+static inline void SYSCONFIG1_BITSET_RSSI_DEF_31_49(u16 *data)
+{
+ switch_off_bits(data, (SYSCONFIG1_BLNDADJ1 | SYSCONFIG1_BLNDADJ0));
+}
+
+static inline void SYSCONFIG1_BITSET_RSSI_37_55(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG1_BLNDADJ0));
+ switch_off_bits(data, (SYSCONFIG1_BLNDADJ1));
+}
+
+static inline void SYSCONFIG1_BITSET_RSSI_19_37(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG1_BLNDADJ1));
+ switch_off_bits(data, (SYSCONFIG1_BLNDADJ0));
+}
+
+static inline void SYSCONFIG1_BITSET_RSSI_25_43(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG1_BLNDADJ1 | SYSCONFIG1_BLNDADJ0));
+}
+
+static inline void SYSCONFIG1_BITSET_GPIO_HIGH_IMP(u16 *data)
+{
+ switch_off_bits(data, (SYSCONFIG1_GPO1 | SYSCONFIG1_GPO0));
+}
+
+static inline void SYSCONFIG1_BITSET_GPIO_STC_RDS_INT(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG1_GPO0));
+ switch_off_bits(data, (SYSCONFIG1_GPO1));
+}
+
+static inline void SYSCONFIG1_BITSET_GPIO_LOW(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG1_GPO1));
+ switch_off_bits(data, (SYSCONFIG1_GPO0));
+}
+
+static inline void SYSCONFIG1_BITSET_GPIO_HIGH(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG1_GPO1 | SYSCONFIG1_GPO0));
+}
+
+static inline void SYSCONFIG1_BITSET_RESERVED(u16 *data)
+{
+ *data &= 0xDCCC;
+ *data |= 0x22;
+}
+
+/********************************************************************/
+
+/*US/EUROPE (Default)*/
+static inline void SYSCONFIG2_BITSET_BAND_87p5_108_MHz(u16 *data)
+{
+ switch_off_bits(data, (SYSCONFIG2_BAND1 | SYSCONFIG2_BAND0));
+}
+
+/*Japan wide band*/
+static inline void SYSCONFIG2_BITSET_BAND_76_108_MHz(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG2_BAND0));
+ switch_off_bits(data, (SYSCONFIG2_BAND1));
+}
+
+/*Japan*/
+static inline void SYSCONFIG2_BITSET_BAND_76_90_MHz(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG2_BAND1));
+ switch_off_bits(data, (SYSCONFIG2_BAND0));
+}
+
+/*US, Australia (Default)*/
+static inline void SYSCONFIG2_BITSET_SPACE_200_KHz(u16 *data)
+{
+ switch_off_bits(data, (SYSCONFIG2_SPACE1 | SYSCONFIG2_SPACE0));
+}
+
+/*Europe, Japan*/
+static inline void SYSCONFIG2_BITSET_SPACE_100_KHz(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG2_SPACE0));
+ switch_off_bits(data, (SYSCONFIG2_SPACE1));
+}
+
+static inline void SYSCONFIG2_BITSET_SPACE_50_KHz(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG2_SPACE1));
+ switch_off_bits(data, (SYSCONFIG2_SPACE0));
+}
+
+static inline void SYSCONFIG2_BITSET_VOLUME(u16 *data, u8 volume)
+{
+ *data &= 0xFFF0;
+ *data |= (volume & 0x0F);
+}
+
+static inline void SYSCONFIG2_BITSET_SEEKTH(u16 *data, u8 seek_th)
+{
+ *data &= 0x00FF;
+ *data |= ((seek_th << 8) & 0xFF00);
+}
+
+static inline u8 SYSCONFIG2_GET_VOLUME(u16 data)
+{
+ return (u8) (data & 0x000F);
+}
+
+/********************************************************************/
+
+static inline void SYSCONFIG3_BITSET_SMUTER_FASTEST(u16 *data)
+{
+ switch_off_bits(data, (SYSCONFIG3_SMUTER1 | SYSCONFIG3_SMUTER0));
+}
+
+static inline void SYSCONFIG3_BITSET_SMUTER_FAST(u16 *data)
+{
+ switch_off_bits(data, (SYSCONFIG3_SMUTER1));
+ switch_on_bits(data, (SYSCONFIG3_SMUTER0));
+}
+
+static inline void SYSCONFIG3_BITSET_SMUTER_SLOW(u16 *data)
+{
+ switch_off_bits(data, (SYSCONFIG3_SMUTER0));
+ switch_on_bits(data, (SYSCONFIG3_SMUTER1));
+}
+
+static inline void SYSCONFIG3_BITSET_SMUTER_SLOWEST(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG3_SMUTER1 | SYSCONFIG3_SMUTER0));
+}
+
+static inline void SYSCONFIG3_BITSET_SMUTEA_16_dB(u16 *data)
+{
+ switch_off_bits(data, (SYSCONFIG3_SMUTEA1 | SYSCONFIG3_SMUTEA0));
+}
+
+static inline void SYSCONFIG3_BITSET_SMUTEA_14dB(u16 *data)
+{
+ switch_off_bits(data, (SYSCONFIG3_SMUTEA1));
+ switch_on_bits(data, (SYSCONFIG3_SMUTEA0));
+}
+
+static inline void SYSCONFIG3_BITSET_SMUTEA_12dB(u16 *data)
+{
+ switch_off_bits(data, (SYSCONFIG3_SMUTEA0));
+ switch_on_bits(data, (SYSCONFIG3_SMUTEA1));
+}
+
+static inline void SYSCONFIG3_BITSET_SMUTEA_10dB(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG3_SMUTEA1 | SYSCONFIG3_SMUTEA0));
+}
+
+static inline void SYSCONFIG3_BITSET_VOLEXT_DISB(u16 *data)
+{
+ switch_off_bits(data, (SYSCONFIG3_VOLEXT));
+}
+
+static inline void SYSCONFIG3_BITSET_VOLEXT_ENB(u16 *data)
+{
+ switch_on_bits(data, (SYSCONFIG3_VOLEXT));
+}
+
+static inline void SYSCONFIG3_BITSET_SKSNR(u16 *data, u8 seeksnr)
+{
+ *data &= 0xFF0F;
+ *data |= ((seeksnr << 4) & 0xF0);
+}
+
+static inline void SYSCONFIG3_BITSET_SKCNT(u16 *data, u8 seekcnt)
+{
+ *data &= 0xFFF0;
+ *data |= ((seekcnt) & 0x0F);
+}
+
+static inline void SYSCONFIG3_BITSET_RESERVED(u16 *data)
+{
+ *data &= 0xF1FF;
+}
+
+/********************************************************************/
+
+static inline void TEST1_BITSET_AHIZEN_HIGH(u16 *data)
+{
+ switch_on_bits(data, (TEST1_AHIZEN));
+}
+
+static inline void TEST1_BITSET_AHIZEN_LOW(u16 *data)
+{
+ switch_off_bits(data, (TEST1_AHIZEN));
+}
+
+static inline void TEST1_BITSET_RESERVED(u16 *data)
+{
+ *data &= 0x7FFF;
+}
+
+/********************************************************************/
+
+#define NEW_RDS_GROUP_READY 1
+#define NO_RDS_GROUP_READY 0
+
+#define COMPLETE 1
+#define CLEAR 0
+
+#define SEEK_SUCCESSFUL 1
+#define SEEK_FAILURE_BAND_LMT_RCHD 0
+
+#define AFC_RAILED 1
+#define AFC_NOT_RAILED 0
+
+#define RDS_DECODER_SYNCHRONIZED 1
+#define RDS_DECODER_NOT_SYNCHRONIZED 0
+
+#define STEREO 1
+#define MONO 0
+
+#define ERRORS_0 0
+#define ERRORS_1_2 1
+#define ERRORS_3_5 2
+#define ERRORS_NO_CORREC_POSSIBLE_6_p 3
+
+static inline int STATUSRSSI_RDS_READY_STATUS(u16 data)
+{
+ if (check_bit(data, STATUSRSSI_RDSR) == BIT_ON)
+ return NEW_RDS_GROUP_READY;
+ else
+ return NO_RDS_GROUP_READY;
+}
+
+static inline int STATUSRSSI_SEEK_TUNE_STATUS(u16 data)
+{
+ if (check_bit(data, STATUSRSSI_STC) == BIT_ON)
+ return COMPLETE;
+ else
+ return CLEAR;
+}
+
+static inline int STATUSRSSI_SF_BL_STATUS(u16 data)
+{
+ if (check_bit(data, STATUSRSSI_SF_BL) == BIT_ON)
+ return SEEK_FAILURE_BAND_LMT_RCHD;
+ else
+ return SEEK_SUCCESSFUL;
+}
+
+static inline int STATUSRSSI_AFC_RAIL_STATUS(u16 data)
+{
+ if (check_bit(data, STATUSRSSI_AFCRL) == BIT_ON)
+ return AFC_RAILED;
+ else
+ return AFC_NOT_RAILED;
+}
+
+static inline int STATUSRSSI_RDS_SYNC_STATUS(u16 data)
+{
+ if (check_bit(data, STATUSRSSI_RDSS) == BIT_ON)
+ return RDS_DECODER_SYNCHRONIZED;
+ else
+ return RDS_DECODER_NOT_SYNCHRONIZED;
+}
+
+static inline int STATUSRSSI_RDS_BLOCK_A_ERRORS(u16 data)
+{
+ int ret = 0;
+ int bits_status = 0;
+
+ ret = check_bit(data, STATUSRSSI_BLERA1);
+
+ if (ret == BIT_ON)
+ bits_status = 0x02;
+ else
+ bits_status = 0x00;
+
+ ret = check_bit(data, STATUSRSSI_BLERA0);
+
+ if (ret == BIT_ON)
+ bits_status |= 0x01;
+
+ return bits_status;
+}
+
+static inline int STATUSRSSI_STEREO_STATUS(u16 data)
+{
+ if (check_bit(data, STATUSRSSI_RDSS) == BIT_ON)
+ return STEREO;
+ else
+ return MONO;
+}
+
+static inline u8 STATUSRSSI_RSSI_SIGNAL_STRENGTH(u16 data)
+{
+ return (u8) (0x00FF & data);
+}
+
+static inline u8 DEVICE_ID_PART_NUMBER(u16 data)
+{
+ data = data >> 12;
+ return (u8) (0x000F & data);
+}
+
+static inline u16 DEVICE_ID_MANUFACT_NUMBER(u16 data)
+{
+ return (u16) (0x0FFF & data);
+}
+
+static inline u8 CHIP_ID_CHIP_VERSION(u16 data)
+{
+ data = data >> 10;
+ return (u8) (0x003F & data);
+}
+
+static inline u8 CHIP_ID_DEVICE(u16 data)
+{
+ data = data >> 6;
+ return (u8) (0x000F & data);
+}
+
+static inline u8 CHIP_ID_FIRMWARE_VERSION(u16 data)
+{
+ return (u8) (0x003F & data);
+}
+
+static inline u8 SYS_CONFIG2_RSSI_TH(u16 data)
+{
+ data = data >> 8;
+ return (u8) (0x00FF & data);
+}
+
+static inline u8 SYS_CONFIG2_FM_BAND(u16 data)
+{
+ data = data >> 6;
+ return (u8) (0x0003 & data);
+}
+
+static inline u8 SYS_CONFIG2_FM_CHAN_SPAC(u16 data)
+{
+ data = data >> 4;
+ return (u8) (0x0003 & data);
+}
+
+static inline u8 SYS_CONFIG2_FM_VOL(u16 data)
+{
+ return (u8) (0x000F & data);
+}
+
+/*POWER_CONFIG_STATUS*/
+
+#define SOFTMUTE_ENABLE 0
+#define SOFTMUTE_DISABLE 1
+
+#define MUTE_ENABLE 0
+#define MUTE_DISABLE 1
+
+#define STEREO_SELECT 0
+#define MONO_SELECT 1
+
+#define RDS_MODE_STANDARD 0
+#define RDS_MODE_VERBOSE 1
+
+#define SEEK_MODE_CONT_SEEK 0
+#define SEEK_MODE_STOP_SEEK 1
+
+#define SEEK_DOWN 0
+#define SEEK_UP 1
+
+#define SEEK_DISABLE 0
+#define SEEK_ABLE 1
+
+static inline int POWER_CONFIG_SOFTMUTE_STATUS(u16 data)
+{
+ if (check_bit(data, POWERCFG_DSMUTE) == BIT_ON)
+ return SOFTMUTE_DISABLE;
+ else
+ return SOFTMUTE_ENABLE;
+}
+
+static inline int POWER_CONFIG_MUTE_STATUS(u16 data)
+{
+ if (check_bit(data, POWERCFG_DMUTE) == BIT_ON)
+ return MUTE_DISABLE;
+ else
+ return MUTE_ENABLE;
+}
+
+static inline int POWER_CONFIG_MONO_STATUS(u16 data)
+{
+ if (check_bit(data, POWERCFG_MONO) == BIT_ON)
+ return MONO_SELECT;
+ else
+ return STEREO_SELECT;
+}
+
+static inline int POWER_CONFIG_RDS_MODE_STATUS(u16 data)
+{
+ if (check_bit(data, POWERCFG_RDSM) == BIT_ON)
+ return RDS_MODE_VERBOSE;
+ else
+ return RDS_MODE_STANDARD;
+}
+
+static inline int POWER_CONFIG_SKMODE_STATUS(u16 data)
+{
+ if (check_bit(data, POWERCFG_SKMODE) == BIT_ON)
+ return SEEK_MODE_STOP_SEEK;
+ else
+ return SEEK_MODE_CONT_SEEK;
+}
+
+static inline int POWER_CONFIG_SEEKUP_STATUS(u16 data)
+{
+ if (check_bit(data, POWERCFG_SEEKUP) == BIT_ON)
+ return SEEK_UP;
+ else
+ return SEEK_DOWN;
+}
+
+static inline int POWER_CONFIG_SEEK_STATUS(u16 data)
+{
+ if (check_bit(data, POWERCFG_SEEK) == BIT_ON)
+ return SEEK_ABLE;
+ else
+ return SEEK_DISABLE;
+}
+
+static inline int POWER_CONFIG_DISABLE_STATUS(u16 data)
+{
+ if (check_bit(data, POWERCFG_DISABLE) == BIT_ON)
+ return 1;
+ else
+ return 0;
+}
+
+static inline int POWER_CONFIG_ENABLE_STATUS(u16 data)
+{
+ if (check_bit(data, POWERCFG_ENABLE) == BIT_ON)
+ return 1;
+ else
+ return 0;
+}
+
+/********************************************************************/
+
+static inline int READCHAN_BLOCK_B_ERRORS(u16 data)
+{
+ int ret = 0;
+ int bits_status = 0;
+
+ ret = check_bit(data, READCHAN_BLERB1);
+
+ if (ret == BIT_ON)
+ bits_status = 0x02;
+ else
+ bits_status = 0x00;
+
+ ret = check_bit(data, READCHAN_BLERB0);
+
+ if (ret == BIT_ON)
+ bits_status |= 0x01;
+
+ return bits_status;
+}
+
+static inline int READCHAN_BLOCK_C_ERRORS(u16 data)
+{
+ int ret = 0;
+ int bits_status = 0;
+
+ ret = check_bit(data, READCHAN_BLERC1);
+
+ if (ret == BIT_ON)
+ bits_status = 0x02;
+ else
+ bits_status = 0x00;
+
+ ret = check_bit(data, READCHAN_BLERC0);
+
+ if (ret == BIT_ON)
+ bits_status |= 0x01;
+
+ return bits_status;
+}
+
+static inline int READCHAN_BLOCK_D_ERRORS(u16 data)
+{
+ int ret = 0;
+ int bits_status = 0;
+
+ ret = check_bit(data, READCHAN_BLERD1);
+
+ if (ret == BIT_ON)
+ bits_status = 0x02;
+ else
+ bits_status = 0x00;
+
+ ret = check_bit(data, READCHAN_BLERD0);
+
+ if (ret == BIT_ON)
+ bits_status |= 0x01;
+
+ return bits_status;
+}
+
+static inline u16 READCHAN_GET_CHAN(u16 data)
+{
+ return data & READCHAN_CHAN_MASK;
+}
+
+/********************************************************************/
+
+#endif
diff --git a/drivers/samsung/fm_si4709/commanddefs.h b/drivers/samsung/fm_si4709/commanddefs.h
new file mode 100644
index 0000000..74ca6d2
--- /dev/null
+++ b/drivers/samsung/fm_si4709/commanddefs.h
@@ -0,0 +1,192 @@
+/* This file contains the command definitions for the Si47xx Parts. */
+#ifndef _COMMAND_DEFS_H_
+#define _COMMAND_DEFS_H_
+
+/*==================================================================
+General Commands
+==================================================================*/
+
+/* STATUS bits - Used by all methods */
+#define STCINT 0x01
+#define ASQINT 0x02
+#define RDSINT 0x04
+#define RSQINT 0x08
+#define ERR 0x40
+#define CTS 0x80
+
+/* POWER_UP */
+#define POWER_UP 0x01
+#define POWER_UP_IN_FUNC_FMRX 0x00
+#define POWER_UP_IN_FUNC_AMRX 0x01
+#define POWER_UP_IN_FUNC_FMTX 0x02
+#define POWER_UP_IN_FUNC_WBRX 0x03
+#define POWER_UP_IN_FUNC_QUERY 0x0F
+#define POWER_UP_IN_PATCH 0x20
+#define POWER_UP_IN_GPO2OEN 0x40
+#define POWER_UP_IN_CTSIEN 0x80
+#define POWER_UP_IN_OPMODE_RX_ANALOG 0x05
+#define POWER_UP_IN_OPMODE_TX_ANALOG 0x50
+
+/* GET_REV */
+#define GET_REV 0x10
+
+/* POWER_DOWN */
+#define POWER_DOWN 0x11
+
+/* SET_PROPERTY */
+#define SET_PROPERTY 0x12
+
+/* GET_PROPERTY */
+#define GET_PROPERTY 0x13
+
+/* GET_INT_STATUS */
+#define GET_INT_STATUS 0x14
+
+/*==================================================================
+ FM Receive Commands
+==================================================================*/
+
+/* FM_TUNE_FREQ */
+#define FM_TUNE_FREQ 0x20
+
+/* FM_SEEK_START */
+#define FM_SEEK_START 0x21
+#define FM_SEEK_START_IN_WRAP 0x04
+#define FM_SEEK_START_IN_SEEKUP 0x08
+
+/* FM_TUNE_STATUS */
+#define FM_TUNE_STATUS 0x22
+#define FM_TUNE_STATUS_IN_INTACK 0x01
+#define FM_TUNE_STATUS_IN_CANCEL 0x02
+#define FM_TUNE_STATUS_OUT_VALID 0x01
+#define FM_TUNE_STATUS_OUT_AFCRL 0x02
+#define FM_TUNE_STATUS_OUT_BTLF 0x80
+
+/* FM_RSQ_STATUS */
+#define FM_RSQ_STATUS 0x23
+#define FM_RSQ_STATUS_IN_INTACK 0x01
+#define FM_RSQ_STATUS_OUT_RSSILINT 0x01
+#define FM_RSQ_STATUS_OUT_RSSIHINT 0x02
+#define FM_RSQ_STATUS_OUT_ASNRLINT 0x04
+#define FM_RSQ_STATUS_OUT_ASNRHINT 0x08
+#define FM_RSQ_STATUS_OUT_BLENDINT 0x80
+#define FM_RSQ_STATUS_OUT_VALID 0x01
+#define FM_RSQ_STATUS_OUT_AFCRL 0x02
+#define FM_RSQ_STATUS_OUT_SMUTE 0x08
+#define FM_RSQ_STATUS_OUT_PILOT 0x80
+#define FM_RSQ_STATUS_OUT_STBLEND 0x7F
+
+/* FM_RDS_STATUS */
+#define FM_RDS_STATUS 0x24
+#define FM_RDS_STATUS_IN_INTACK 0x01
+#define FM_RDS_STATUS_IN_MTFIFO 0x02
+#define FM_RDS_STATUS_OUT_RECV 0x01
+#define FM_RDS_STATUS_OUT_SYNCLOST 0x02
+#define FM_RDS_STATUS_OUT_SYNCFOUND 0x04
+#define FM_RDS_STATUS_OUT_SYNC 0x01
+#define FM_RDS_STATUS_OUT_GRPLOST 0x04
+#define FM_RDS_STATUS_OUT_BLED 0x03
+#define FM_RDS_STATUS_OUT_BLEC 0x0C
+#define FM_RDS_STATUS_OUT_BLEB 0x30
+#define FM_RDS_STATUS_OUT_BLEA 0xC0
+#define FM_RDS_STATUS_OUT_BLED_SHFT 0
+#define FM_RDS_STATUS_OUT_BLEC_SHFT 2
+#define FM_RDS_STATUS_OUT_BLEB_SHFT 4
+#define FM_RDS_STATUS_OUT_BLEA_SHFT 6
+
+/*==================================================================
+ AM Receive Commands
+==================================================================*/
+
+/* AM_TUNE_FREQ */
+#define AM_TUNE_FREQ 0x40
+
+/* AM_SEEK_START */
+#define AM_SEEK_START 0x41
+#define AM_SEEK_START_IN_WRAP 0x04
+#define AM_SEEK_START_IN_SEEKUP 0x08
+
+/* AM_TUNE_STATUS */
+#define AM_TUNE_STATUS 0x42
+#define AM_TUNE_STATUS_IN_INTACK 0x01
+#define AM_TUNE_STATUS_IN_CANCEL 0x02
+#define AM_TUNE_STATUS_OUT_VALID 0x01
+#define AM_TUNE_STATUS_OUT_AFCRL 0x02
+#define AM_TUNE_STATUS_OUT_BTLF 0x80
+
+/* AM_RSQ_STATUS */
+#define AM_RSQ_STATUS 0x23
+#define AM_RSQ_STATUS_IN_INTACK 0x01
+#define AM_RSQ_STATUS_OUT_RSSILINT 0x01
+#define AM_RSQ_STATUS_OUT_RSSIHINT 0x02
+#define AM_RSQ_STATUS_OUT_ASNRLINT 0x04
+#define AM_RSQ_STATUS_OUT_ASNRHINT 0x08
+#define AM_RSQ_STATUS_OUT_VALID 0x01
+#define AM_RSQ_STATUS_OUT_AFCRL 0x02
+#define AM_RSQ_STATUS_OUT_SMUTE 0x08
+
+/*==================================================================
+ FM Transmit Commands
+==================================================================*/
+
+/* TX_TUNE_FREQ */
+#define TX_TUNE_FREQ 0x30
+
+/* TX_TUNE_POWER */
+#define TX_TUNE_POWER 0x31
+
+/* TX_TUNE_MEASURE */
+#define TX_TUNE_MEASURE 0x32
+
+/* TX_TUNE_STATUS */
+#define TX_TUNE_STATUS 0x33
+#define TX_TUNE_STATUS_IN_INTACK 0x01
+
+/* TX_ASQ_STATUS */
+#define TX_ASQ_STATUS 0x34
+#define TX_ASQ_STATUS_IN_INTACK 0x01
+#define TX_ASQ_STATUS_OUT_IALL 0x01
+#define TX_ASQ_STATUS_OUT_IALH 0x02
+#define TX_ASQ_STATUS_OUT_OVERMOD 0x04
+
+/* TX_RDS_BUFF */
+#define TX_RDS_BUFF 0x35
+#define TX_RDS_BUFF_IN_INTACK 0x01
+#define TX_RDS_BUFF_IN_MTBUFF 0x02
+#define TX_RDS_BUFF_IN_LDBUFF 0x04
+#define TX_RDS_BUFF_IN_FIFO 0x80
+
+/* TX_RDS_PS */
+#define TX_RDS_PS 0x36
+
+/*==================================================================
+ WB Receive Commands
+==================================================================*/
+
+/* WB_TUNE_FREQ */
+#define WB_TUNE_FREQ 0x50
+
+/* WB_TUNE_STATUS */
+#define WB_TUNE_STATUS 0x52
+#define WB_TUNE_STATUS_IN_INTACK 0x01
+#define WB_TUNE_STATUS_OUT_VALID 0x01
+#define WB_TUNE_STATUS_OUT_AFCRL 0x02
+
+/* WB_RSQ_STATUS */
+#define WB_RSQ_STATUS 0x53
+#define WB_RSQ_STATUS_IN_INTACK 0x01
+#define WB_RSQ_STATUS_OUT_RSSILINT 0x01
+#define WB_RSQ_STATUS_OUT_RSSIHINT 0x02
+#define WB_RSQ_STATUS_OUT_ASNRLINT 0x04
+#define WB_RSQ_STATUS_OUT_ASNRHINT 0x08
+#define WB_RSQ_STATUS_OUT_VALID 0x01
+#define WB_RSQ_STATUS_OUT_AFCRL 0x02
+
+/* WB_ASQ_STATUS */
+#define WB_ASQ_STATUS 0x55
+#define WB_ASQ_STATUS_IN_INTACK 0x01
+#define WB_ASQ_STATUS_OUT_ALERTONINT 0x01
+#define WB_ASQ_STATUS_OUT_ALERTOFFINT 0x02
+#define WB_ASQ_STATUS_OUT_ALERT 0x01
+
+#endif
diff --git a/drivers/samsung/fm_si4709/propertydefs.h b/drivers/samsung/fm_si4709/propertydefs.h
new file mode 100644
index 0000000..356e9f5
--- /dev/null
+++ b/drivers/samsung/fm_si4709/propertydefs.h
@@ -0,0 +1,578 @@
+/* This file contains the property definitions for the Si47xx Parts. */
+#ifndef _PROPERTY_DEFS_H_
+#define _PROPERTY_DEFS_H_
+
+/*==================================================================
+ General Properties
+==================================================================*/
+
+/* GPO_IEN */
+#define GPO_IEN 0x0001
+#define GPO_IEN_STCIEN_MASK 0x0001
+#define GPO_IEN_ASQIEN_MASK 0x0002
+#define GPO_IEN_RDSIEN_MASK 0x0004
+#define GPO_IEN_RSQIEN_MASK 0x0008
+#define GPO_IEN_ERRIEN_MASK 0x0040
+#define GPO_IEN_CTSIEN_MASK 0x0080
+#define GPO_IEN_STCREP_MASK 0x0100
+#define GPO_IEN_ASQREP_MASK 0x0200
+#define GPO_IEN_RDSREP_MASK 0x0400
+#define GPO_IEN_RSQREP_MASK 0x0800
+#define GPO_IEN_STCIEN_SHFT 0
+#define GPO_IEN_ASQIEN_SHFT 1
+#define GPO_IEN_RDSIEN_SHFT 2
+#define GPO_IEN_RSQIEN_SHFT 3
+#define GPO_IEN_ERRIEN_SHFT 6
+#define GPO_IEN_CTSIEN_SHFT 7
+#define GPO_IEN_STCREP_SHFT 8
+#define GPO_IEN_ASQREP_SHFT 9
+#define GPO_IEN_RDSREP_SHFT 10
+#define GPO_IEN_RSQREP_SHFT 11
+
+/* DIGITAL_INPUT_FORMAT */
+#define DIGITAL_INPUT_FORMAT 0x0101
+#define DIGITAL_INPUT_FORMAT_ISIZE_MASK 0x0003
+#define DIGITAL_INPUT_FORMAT_IMONO_MASK 0x0004
+#define DIGITAL_INPUT_FORMAT_IMODE_MASK 0x0078
+#define DIGITAL_INPUT_FORMAT_IFALL_MASK 0x0080
+#define DIGITAL_INPUT_FORMAT_ISIZE_SHFT 0
+#define DIGITAL_INPUT_FORMAT_IMONO_SHFT 2
+#define DIGITAL_INPUT_FORMAT_IMODE_SHFT 3
+#define DIGITAL_INPUT_FORMAT_IFALL_SHFT 7
+
+/* DIGITAL_INPUT_SAMPLE_RATE */
+#define DIGITAL_INPUT_SAMPLE_RATE 0x0103
+
+/* DIGITAL_OUTPUT_FORMAT */
+#define DIGITAL_OUTPUT_FORMAT 0x0102
+#define DIGITAL_OUTPUT_FORMAT_OSIZE_MASK 0x0003
+#define DIGITAL_OUTPUT_FORMAT_OMONO_MASK 0x0004
+#define DIGITAL_OUTPUT_FORMAT_OMODE_MASK 0x0078
+#define DIGITAL_OUTPUT_FORMAT_OFALL_MASK 0x0080
+#define DIGITAL_OUTPUT_FORMAT_OSIZE_SHFT 0
+#define DIGITAL_OUTPUT_FORMAT_OMONO_SHFT 2
+#define DIGITAL_OUTPUT_FORMAT_OMODE_SHFT 3
+#define DIGITAL_OUTPUT_FORMAT_OFALL_SHFT 7
+
+/* DIGITAL_OUTPUT_SAMPLE_RATE */
+#define DIGITAL_OUTPUT_SAMPLE_RATE 0x0104
+
+/* REFCLK_FREQ */
+#define REFCLK_FREQ 0x0201
+
+/* REFCLK_PRESCALE */
+#define REFCLK_PRESCALE 0x0202
+#define REFCLK_PRESCALE_MASK 0x0FFF
+#define REFCLK_PRESCALE_SHFT 0
+
+/*==================================================================
+ FM Receive Properties
+==================================================================*/
+
+/* FM_DEEMPHASIS */
+#define FM_DEEMPHASIS 0x1100
+#define FM_DEEMPHASIS_MASK 0x0003
+#define FM_DEEMPHASIS_SHFT 0
+
+/* FM_BLEND_STEREO_THRESHOLD */
+#define FM_BLEND_STEREO_THRESHOLD 0x1105
+#define FM_BLEND_STEREO_THRESHOLD_MASK 0x007F
+#define FM_BLEND_STEREO_THRESHOLD_SHFT 0
+
+/* FM_BLEND_MONO_THRESHOLD */
+#define FM_BLEND_MONO_THRESHOLD 0x1106
+#define FM_BLEND_MONO_THRESHOLD_MASK 0x007F
+#define FM_BLEND_MONO_THRESHOLD_SHFT 0
+
+
+/* FM_MAX_TUNE_ERROR */
+#define FM_MAX_TUNE_ERROR 0x1108
+#define FM_MAX_TUNE_ERROR_MASK 0x007F
+#define FM_MAX_TUNE_ERROR_SHFT 0
+
+/* FM_RSQ_INT_SOURCE */
+#define FM_RSQ_INT_SOURCE 0x1200
+#define FM_RSQ_INT_SOURCE_RSSILIEN_MASK 0x0001
+#define FM_RSQ_INT_SOURCE_RSSIHIEN_MASK 0x0002
+#define FM_RSQ_INT_SOURCE_ASNRLIEN_MASK 0x0004
+#define FM_RSQ_INT_SOURCE_ASNRHIEN_MASK 0x0008
+#define FM_RSQ_INT_SOURCE_BLENDIEN_MASK 0x0080
+#define FM_RSQ_INT_SOURCE_RSSILIEN_SHFT 0
+#define FM_RSQ_INT_SOURCE_RSSIHIEN_SHFT 1
+#define FM_RSQ_INT_SOURCE_ASNRLIEN_SHFT 2
+#define FM_RSQ_INT_SOURCE_ASNRHIEN_SHFT 3
+#define FM_RSQ_INT_SOURCE_BLENDIEN_SHFT 7
+
+/* FM_RSQ_SNR_HI_THRESHOLD */
+#define FM_RSQ_SNR_HI_THRESHOLD 0x1201
+#define FM_RSQ_SNR_HI_THRESHOLD_MASK 0x007F
+#define FM_RSQ_SNR_HI_THRESHOLD_SHFT 0
+
+/* FM_RSQ_SNR_LO_THRESHOLD */
+#define FM_RSQ_SNR_LO_THRESHOLD 0x1202
+#define FM_RSQ_SNR_LO_THRESHOLD_MASK 0x007F
+#define FM_RSQ_SNR_LO_THRESHOLD_SHFT 0
+
+/* FM_RSQ_RSSI_HI_THRESHOLD */
+#define FM_RSQ_RSSI_HI_THRESHOLD 0x1203
+#define FM_RSQ_RSSI_HI_THRESHOLD_MASK 0x007F
+#define FM_RSQ_RSSI_HI_THRESHOLD_SHFT 0
+
+/* FM_RSQ_RSSI_LO_THRESHOLD */
+#define FM_RSQ_RSSI_LO_THRESHOLD 0x1204
+#define FM_RSQ_RSSI_LO_THRESHOLD_MASK 0x007F
+#define FM_RSQ_RSSI_LO_THRESHOLD_SHFT 0
+
+/* FM_RSQ_BLEND_THRESHOLD */
+#define FM_RSQ_BLEND_THRESHOLD 0x1207
+#define FM_RSQ_BLEND_THRESHOLD_BLEND_MASK 0x007F
+#define FM_RSQ_BLEND_THRESHOLD_PILOT_MASK 0x0080
+#define FM_RSQ_BLEND_THRESHOLD_BLEND_SHFT 0
+#define FM_RSQ_BLEND_THRESHOLD_PILOT_SHFT 7
+
+/* FM_SOFT_MUTE_RATE */
+#define FM_SOFT_MUTE_RATE 0x1300
+#define FM_SOFT_MUTE_RATE_MASK 0x00FF
+#define FM_SOFT_MUTE_RATE_SHFT 0
+
+/* FM_SOFT_MUTE_MAX_ATTENUATION */
+#define FM_SOFT_MUTE_MAX_ATTENUATION 0x1302
+#define FM_SOFT_MUTE_MAX_ATTENUATION_MASK 0x001F
+#define FM_SOFT_MUTE_MAX_ATTENUATION_SHFT 0
+
+/* FM_SOFT_MUTE_SNR_THRESHOLD */
+#define FM_SOFT_MUTE_SNR_THRESHOLD 0x1303
+#define FM_SOFT_MUTE_SNR_THRESHOLD_MASK 0x000F
+#define FM_SOFT_MUTE_SNR_THRESHOLD_SHFT 0
+
+/* FM_SEEK_BAND_BOTTOM */
+#define FM_SEEK_BAND_BOTTOM 0x1400
+
+/* FM_SEEK_BAND_TOP */
+#define FM_SEEK_BAND_TOP 0x1401
+
+/* FM_SEEK_FREQ_SPACING */
+#define FM_SEEK_FREQ_SPACING 0x1402
+#define FM_SEEK_FREQ_SPACING_MASK 0x001F
+#define FM_SEEK_FREQ_SPACING_SHFT 0
+
+/* FM_SEEK_TUNE_SNR_THRESHOLD */
+#define FM_SEEK_TUNE_SNR_THRESHOLD 0x1403
+#define FM_SEEK_TUNE_SNR_THRESHOLD_MASK 0x007F
+#define FM_SEEK_TUNE_SNR_THRESHOLD_SHFT 0
+
+/* FM_SEEK_TUNE_RSSI_THRESHOLD */
+#define FM_SEEK_TUNE_RSSI_THRESHOLD 0x1404
+#define FM_SEEK_TUNE_RSSI_THRESHOLD_MASK 0x007F
+#define FM_SEEK_TUNE_RSSI_THRESHOLD_SHFT 0
+
+/* FM_RDS_INTERRUPT_SOURCE */
+#define FM_RDS_INTERRUPT_SOURCE 0x1500
+#define FM_RDS_INTERRUPT_SOURCE_RECV_MASK 0x0001
+#define FM_RDS_INTERRUPT_SOURCE_SYNCLOST_MASK 0x0002
+#define FM_RDS_INTERRUPT_SOURCE_SYNCFOUND_MASK 0x0004
+#define FM_RDS_INTERRUPT_SOURCE_RECV_SHFT 0
+#define FM_RDS_INTERRUPT_SOURCE_SYNCLOST_SHFT 1
+#define FM_RDS_INTERRUPT_SOURCE_SYNCFOUND_SHFT 2
+
+/* FM_RDS_INTERRUPT_FIFO_COUNT */
+#define FM_RDS_INTERRUPT_FIFO_COUNT 0x1501
+#define FM_RDS_INTERRUPT_FIFO_COUNT_MASK 0x00FF
+#define FM_RDS_INTERRUPT_FIFO_COUNT_SHFT 0
+
+/* FM_RDS_CONFIG */
+#define FM_RDS_CONFIG 0x1502
+#define FM_RDS_CONFIG_RDSEN_MASK 0x0001
+#define FM_RDS_CONFIG_BLETHD_MASK 0x0300
+#define FM_RDS_CONFIG_BLETHC_MASK 0x0C00
+#define FM_RDS_CONFIG_BLETHB_MASK 0x3000
+#define FM_RDS_CONFIG_BLETHA_MASK 0xC000
+#define FM_RDS_CONFIG_RDSEN_SHFT 0
+#define FM_RDS_CONFIG_BLETHD_SHFT 8
+#define FM_RDS_CONFIG_BLETHC_SHFT 10
+#define FM_RDS_CONFIG_BLETHB_SHFT 12
+#define FM_RDS_CONFIG_BLETHA_SHFT 14
+
+/*==================================================================
+ FM Transmit Properties
+==================================================================*/
+
+/* TX_COMPONENT_ENABLE */
+#define TX_COMPONENT_ENABLE 0x2100
+#define TX_COMPONENT_ENABLE_PILOT_MASK 0x0001
+#define TX_COMPONENT_ENABLE_LMR_MASK 0x0002
+#define TX_COMPONENT_ENABLE_RDS_MASK 0x0004
+#define TX_COMPONENT_ENABLE_PILOT_SHFT 0
+#define TX_COMPONENT_ENABLE_LMR_SHFT 1
+#define TX_COMPONENT_ENABLE_RDS_SHFT 2
+
+/* TX_AUDIO_DEVIATION */
+#define TX_AUDIO_DEVIATION 0x2101
+
+/* TX_PILOT_DEVIATION */
+#define TX_PILOT_DEVIATION 0x2102
+
+/* TX_RDS_DEVIATION */
+#define TX_RDS_DEVIATION 0x2103
+
+/* TX_LINE_INPUT_LEVEL */
+#define TX_LINE_INPUT_LEVEL 0x2104
+#define TX_LINE_INPUT_LEVEL_LILEVEL_MASK 0x03FF
+#define TX_LINE_INPUT_LEVEL_LIATTEN_MASK 0x3000
+#define TX_LINE_INPUT_LEVEL_LILEVEL_SHFT 0
+#define TX_LINE_INPUT_LEVEL_LIATTEN_SHFT 12
+
+/* TX_LINE_INPUT_MUTE */
+#define TX_LINE_INPUT_MUTE 0x2105
+#define TX_LINE_INPUT_MUTE_RIMUTE_MASK 0x0001
+#define TX_LINE_INPUT_MUTE_LIMUTE_MASK 0x0002
+#define TX_LINE_INPUT_MUTE_RIMUTE_SHFT 0
+#define TX_LINE_INPUT_MUTE_LIMUTE_SHFT 1
+
+/* TX_PREEMPHASIS */
+#define TX_PREEMPHASIS 0x2106
+#define TX_PREMPHASIS_MASK 0x0003
+#define TX_PREMPHASIS_SHFT 0
+
+/* TX_PILOT_FREQUENCY */
+#define TX_PILOT_FREQUENCY 0x2107
+
+/* TX_ACOMP_ENABLE */
+#define TX_ACOMP_ENABLE 0x2200
+#define TX_ACOMP_ENABLE_ACEN_MASK 0x0001
+#define TX_ACOMP_ENABLE_LIMITEN_MASK 0x0002
+#define TX_ACOMP_ENABLE_ACEN_SHFT 0
+#define TX_ACOMP_ENABLE_LIMITEN_SHFT 1
+
+/* TX_ACOMP_THRESHOLD */
+#define TX_ACOMP_THRESHOLD 0x2201
+
+/* TX_ACOMP_ATTACK_TIME */
+#define TX_ACOMP_ATTACK_TIME 0x2202
+#define TX_ACOMP_ATTACK_TIME_MASK 0x000F
+#define TX_ACOMP_ATTACK_TIME_SHFT 0
+
+/* TX_ACOMP_RELEASE_TIME */
+#define TX_ACOMP_RELEASE_TIME 0x2203
+#define TX_ACOMP_RELEASE_TIME_MASK 0x0007
+#define TX_ACOMP_RELEASE_TIME_SHFT 0
+
+/* TX_ACOMP_GAIN */
+#define TX_ACOMP_GAIN 0x2204
+#define TX_ACOMP_GAIN_MASK 0x003F
+#define TX_ACOMP_GAIN_SHFT 0
+
+/* TX_LIMITER_RELEASE_TIME */
+#define TX_LIMITER_RELEASE_TIME 0x2205
+
+/* TX_ASQ_INT_SELECT */
+#define TX_ASQ_INT_SELECT 0x2300
+#define TX_ASQ_INT_SELECT_IALLIEN_MASK 0x0001
+#define TX_ASQ_INT_SELECT_IALHIEN_MASK 0x0002
+#define TX_ASQ_INT_SELECT_OVERMODIEN_MASK 0x0004
+#define TX_ASQ_INT_SELECT_IALLIEN_SHFT 0
+#define TX_ASQ_INT_SELECT_IALHIEN_SHFT 1
+#define TX_ASQ_INT_SELECT_OVERMODIEN_SHFT 2
+
+/* TX_ASQ_LEVEL_LOW */
+#define TX_ASQ_LEVEL_LOW 0x2301
+#define TX_ASQ_LEVEL_LOW_MASK 0x00FF
+#define TX_ASQ_LEVEL_LOW_SHFT 0
+
+/* TX_ASQ_DURATION_LOW */
+#define TX_ASQ_DURATION_LOW 0x2302
+
+/* TX_ASQ_LEVEL_HIGH */
+#define TX_ASQ_LEVEL_HIGH 0x2303
+#define TX_ASQ_LEVEL_HIGH_MASK 0x00FF
+#define TX_ASQ_LEVEL_HIGH_SHFT 0
+
+/* TX_ASQ_DURATION_LOW */
+#define TX_ASQ_DURATION_HIGH 0x2304
+
+/* TX_RDS_INT_SOURCE */
+#define TX_RDS_INT_SOURCE 0x2C00
+#define TX_RDS_INT_SOURCE_FIFOMT_MASK 0x0001
+#define TX_RDS_INT_SOURCE_CBUFWRAP_MASK 0x0002
+#define TX_RDS_INT_SOURCE_FIFOXMIT_MASK 0x0004
+#define TX_RDS_INT_SOURCE_CBUFXMIT_MASK 0x0008
+#define TX_RDS_INT_SOURCE_PSXMIT_MASK 0x0010
+#define TX_RDS_INT_SOURCE_FIFOMT_SHFT 0
+#define TX_RDS_INT_SOURCE_CBUFWRAP_SHFT 1
+#define TX_RDS_INT_SOURCE_FIFOXMIT_SHFT 2
+#define TX_RDS_INT_SOURCE_CBUFXMIT_SHFT 3
+#define TX_RDS_INT_SOURCE_PSXMIT_SHFT 4
+
+/* TX_RDS_PI */
+#define TX_RDS_PI 0x2C01
+
+/* TX_RDS_PS_MIX */
+#define TX_RDS_PS_MIX 0x2C02
+#define TX_RDS_PS_MIX_MASK 0x0007
+#define TX_RDS_PS_MIX_SHFT 0
+
+/* TX_RDS_PS_MISC */
+#define TX_RDS_PS_MISC 0x2C03
+#define TX_RDS_PS_MISC_RDSMS_MASK 0x0008
+#define TX_RDS_PS_MISC_RDSTA_MASK 0x0010
+#define TX_RDS_PS_MISC_RDSPTY_MASK 0x03E0
+#define TX_RDS_PS_MISC_RDSTP_MASK 0x0400
+#define TX_RDS_PS_MISC_FORCEB_MASK 0x0800
+#define TX_RDS_PS_MISC_RDSD0_MASK 0x1000
+#define TX_RDS_PS_MISC_RDSD1_MASK 0x2000
+#define TX_RDS_PS_MISC_RDSD2_MASK 0x4000
+#define TX_RDS_PS_MISC_RDSD3_MASK 0x8000
+#define TX_RDS_PS_MISC_RDSMS_SHFT 3
+#define TX_RDS_PS_MISC_RDSTA_SHFT 4
+#define TX_RDS_PS_MISC_RDSPTY_SHFT 5
+#define TX_RDS_PS_MISC_RDSTP_SHFT 10
+#define TX_RDS_PS_MISC_FORCEB_SHFT 11
+#define TX_RDS_PS_MISC_RDSD0_SHFT 12
+#define TX_RDS_PS_MISC_RDSD1_SHFT 13
+#define TX_RDS_PS_MISC_RDSD2_SHFT 14
+#define TX_RDS_PS_MISC_RDSD3_SHFT 15
+
+/* TX_RDS_PS_REPEAT_COUNT */
+#define TX_RDS_PS_REPEAT_COUNT 0x2C04
+#define TX_RDS_PS_REPEAT_COUNT_MASK 0x00FF
+#define TX_RDS_PS_REPEAT_COUNT_SHFT 0
+
+/* TX_RDS_PS_MESSAGE_COUNT */
+#define TX_RDS_PS_MESSAGE_COUNT 0x2C05
+#define TX_RDS_PS_MESSAGE_COUNT_MASK 0x000F
+#define TX_RDS_PS_MESSAGE_COUNT_SHFT 0
+
+/* TX_RDS_PS_AF */
+#define TX_RDS_PS_AF 0x2C06
+
+/* TX_RDS_FIFO_SIZE */
+#define TX_RDS_FIFO_SIZE 0x2C07
+#define TX_RDS_FIFO_SIZE_MASK 0x00FF
+#define TX_RDS_FIFO_SIZE_SHFT 0
+
+
+/*==================================================================
+ AM Receive Properties
+==================================================================*/
+
+/* AM_DEEMPHASIS */
+#define AM_DEEMPHASIS 0x3100
+#define AM_DEEMPHASIS_MASK 0x0001
+#define AM_DEEMPHASIS_SHFT 0
+
+/* AM_CHANNEL_FILTER */
+#define AM_CHANNEL_FILTER 0x3102
+#define AM_CHANNEL_FILTER_MASK 0x0007
+#define AM_CHANNEL_FILTER_SHFT 0
+
+/* AM_RSQ_INT_SOURCE */
+#define AM_RSQ_INT_SOURCE 0x3200
+#define AM_RSQ_INT_SOURCE_RSSILIEN_MASK 0x0001
+#define AM_RSQ_INT_SOURCE_RSSIHIEN_MASK 0x0002
+#define AM_RSQ_INT_SOURCE_ASNRLIEN_MASK 0x0004
+#define AM_RSQ_INT_SOURCE_ASNRHIEN_MASK 0x0008
+#define AM_RSQ_INT_SOURCE_RSSILIEN_SHFT 0
+#define AM_RSQ_INT_SOURCE_RSSIHIEN_SHFT 1
+#define AM_RSQ_INT_SOURCE_ASNRLIEN_SHFT 2
+#define AM_RSQ_INT_SOURCE_ASNRHIEN_SHFT 3
+
+/* AM_RSQ_SNR_HI_THRESHOLD */
+#define AM_RSQ_SNR_HI_THRESHOLD 0x3201
+#define AM_RSQ_SNR_HI_THRESHOLD_MASK 0x007F
+#define AM_RSQ_SNR_HI_THRESHOLD_SHFT 0
+
+/* AM_RSQ_SNR_LO_THRESHOLD */
+#define AM_RSQ_SNR_LO_THRESHOLD 0x3202
+#define AM_RSQ_SNR_LO_THRESHOLD_MASK 0x007F
+#define AM_RSQ_SNR_LO_THRESHOLD_SHFT 0
+
+/* AM_RSQ_RSSI_HI_THRESHOLD */
+#define AM_RSQ_RSSI_HI_THRESHOLD 0x3203
+#define AM_RSQ_RSSI_HI_THRESHOLD_MASK 0x007F
+#define AM_RSQ_RSSI_HI_THRESHOLD_SHFT 0
+
+/* AM_RSQ_RSSI_LO_THRESHOLD */
+#define AM_RSQ_RSSI_LO_THRESHOLD 0x3204
+#define AM_RSQ_RSSI_LO_THRESHOLD_MASK 0x007F
+#define AM_RSQ_RSSI_LO_THRESHOLD_SHFT 0
+
+/* AM_SOFT_MUTE_RATE */
+#define AM_SOFT_MUTE_RATE 0x3300
+
+/* AM_SOFT_MUTE_SLOPE */
+#define AM_SOFT_MUTE_SLOPE 0x3301
+#define AM_SOFT_MUTE_SLOPE_MASK 0x000F
+#define AM_SOFT_MUTE_SLOPE_SHFT 0
+
+/* AM_SOFT_MUTE_MAX_ATTENUATION */
+#define AM_SOFT_MUTE_MAX_ATTENUATION 0x3302
+#define AM_SOFT_MUTE_MAX_ATTENUATION_MASK 0x003F
+#define AM_SOFT_MUTE_MAX_ATTENUATION_SHFT 0
+
+/* AM_SOFT_MUTE_SNR_THRESHOLD */
+#define AM_SOFT_MUTE_SNR_THRESHOLD 0x3303
+#define AM_SOFT_MUTE_SNR_THRESHOLD_MASK 0x003F
+#define AM_SOFT_MUTE_SNR_THRESHOLD_SHFT 0
+
+/* AM_SEEK_BAND_BOTTOM */
+#define AM_SEEK_BAND_BOTTOM 0x3400
+
+/* AM_SEEK_BAND_TOP */
+#define AM_SEEK_BAND_TOP 0x3401
+
+/* AM_SEEK_FREQ_SPACING */
+#define AM_SEEK_FREQ_SPACING 0x3402
+#define AM_SEEK_FREQ_SPACING_MASK 0x000F
+#define AM_SEEK_FREQ_SPACING_SHFT 0
+
+/* AM_SEEK_TUNE_SNR_THRESHOLD */
+#define AM_SEEK_TUNE_SNR_THRESHOLD 0x3403
+#define AM_SEEK_TUNE_SNR_THRESHOLD_MASK 0x003F
+#define AM_SEEK_TUNE_SNR_THRESHOLD_SHFT 0
+
+/* AM_SEEK_TUNE_RSSI_THRESHOLD */
+#define AM_SEEK_TUNE_RSSI_THRESHOLD 0x3404
+#define AM_SEEK_TUNE_RSSI_THRESHOLD_MASK 0x003F
+#define AM_SEEK_TUNE_RSSI_THRESHOLD_SHFT 0
+
+/*==================================================================
+ General Receive Properties
+==================================================================*/
+
+/* RX_VOLUME */
+#define RX_VOLUME 0x4000
+#define RX_VOLUME_MASK 0x003F
+#define RX_VOLUME_SHFT 0
+
+/* RX_HARD_MUTE */
+#define RX_HARD_MUTE 0x4001
+#define RX_HARD_MUTE_RMUTE_MASK 0x0001
+#define RX_HARD_MUTE_LMUTE_MASK 0x0002
+#define RX_HARD_MUTE_RMUTE_SHFT 0
+#define RX_HARD_MUTE_LMUTE_SHFT 1
+
+/*==================================================================
+ Bit Definitions for Properties
+==================================================================*/
+
+/* DIGITAL_MODE - used for input or output */
+#define DIGITAL_MODE_I2S 0x0
+#define DIGITAL_MODE_LEFT 0x6
+#define DIGITAL_MODE_MSB1ST 0xC
+#define DIGITAL_MODE_MSB2ND 0x8
+
+/* DIGITAL_SIZE - used for input or output */
+#define DIGITAL_SIZE_16 0x0
+#define DIGITAL_SIZE_20 0x1
+#define DIGITAL_SIZE_24 0x2
+#define DIGITAL_SIZE_8 0x3
+
+/* FM_DEEMPH */
+#define FM_DEEMPH_75US 0x2
+#define FM_DEEMPH_50US 0x1
+
+/* FM_RDS_BLETH - used for all block error thresholds */
+#define FM_RDS_BLETH_NO_ERRORS 0x0
+#define FM_RDS_BLETH_1OR2_ERRORS 0x1
+#define FM_RDS_BLETH_3TO5_ERRORS 0x2
+#define FM_RDS_BLETH_UNCORRECTABLE 0x3
+
+/* TX_LINE_INPUT_LEVEL_LIATTEN */
+#define TX_LINE_INPUT_LEVEL_LIATTEN_396kOhm 0x0000
+#define TX_LINE_INPUT_LEVEL_LIATTEN_100kOhm 0x1000
+#define TX_LINE_INPUT_LEVEL_LIATTEN_74kOhm 0x2000
+#define TX_LINE_INPUT_LEVEL_LIATTEN_60kOhm 0x3000
+
+/* TX_DEEMPHASIS */
+#define TX_PREEMPHASIS_75US 0x0
+#define TX_PREEMPHASIS_50US 0x1
+#define TX_PREEMPHASIS_DISABLED 0x2
+
+/* TX_ACOMP_ATTACK_TIME */
+#define TX_ACOMP_ATTACK_TIME_0_5MS 0x0
+#define TX_ACOMP_ATTACK_TIME_1_0MS 0x1
+#define TX_ACOMP_ATTACK_TIME_1_5MS 0x2
+#define TX_ACOMP_ATTACK_TIME_2_0MS 0x3
+#define TX_ACOMP_ATTACK_TIME_2_5MS 0x4
+#define TX_ACOMP_ATTACK_TIME_3_0MS 0x5
+#define TX_ACOMP_ATTACK_TIME_3_5MS 0x6
+#define TX_ACOMP_ATTACK_TIME_4_0MS 0x7
+#define TX_ACOMP_ATTACK_TIME_4_5MS 0x8
+#define TX_ACOMP_ATTACK_TIME_5_0MS 0x9
+
+/* TX_ACOMP_RELEASE_TIME */
+#define TX_ACOMP_RELEASE_TIME_100MS 0x0
+#define TX_ACOMP_RELEASE_TIME_200MS 0x1
+#define TX_ACOMP_RELEASE_TIME_350MS 0x2
+#define TX_ACOMP_RELEASE_TIME_525MS 0x3
+#define TX_ACOMP_RELEASE_TIME_1000MS 0x4
+
+/* TX_RDS_PS_MIX */
+#define TX_RDS_PS_MIX_FIFO_EMPTY 0x0
+#define TX_RDS_PS_MIX_12_5_PCT 0x1
+#define TX_RDS_PS_MIX_25_PCT 0x2
+#define TX_RDS_PS_MIX_50_PCT 0x3
+#define TX_RDS_PS_MIX_75_PCT 0x4
+#define TX_RDS_PS_MIX_87_5_PCT 0x5
+#define TX_RDS_PS_MIX_100_PCT 0x6
+
+/* TX_RDS_PS_MISC_PTY */
+#define TX_RDS_PS_MISC_PTY_NONE 0
+#define TX_RDS_PS_MISC_PTY_NEWS 1
+#define TX_RDS_PS_MISC_PTY_INFO 2
+#define TX_RDS_PS_MISC_PTY_SPORTS 3
+#define TX_RDS_PS_MISC_PTY_TALK 4
+#define TX_RDS_PS_MISC_PTY_ROCK 5
+#define TX_RDS_PS_MISC_PTY_CLROCK 6
+#define TX_RDS_PS_MISC_PTY_ADHITS 7
+#define TX_RDS_PS_MISC_PTY_SOFTROCK 8
+#define TX_RDS_PS_MISC_PTY_TOP40 9
+#define TX_RDS_PS_MISC_PTY_COUNTRY 10
+#define TX_RDS_PS_MISC_PTY_OLDIES 11
+#define TX_RDS_PS_MISC_PTY_SOFT 12
+#define TX_RDS_PS_MISC_PTY_NOST 13
+#define TX_RDS_PS_MISC_PTY_JAZZ 14
+#define TX_RDS_PS_MISC_PTY_CLASS 15
+#define TX_RDS_PS_MISC_PTY_RHYBLUES 16
+#define TX_RDS_PS_MISC_PTY_SOFTRB 17
+#define TX_RDS_PS_MISC_PTY_FGNLANG 18
+#define TX_RDS_PS_MISC_PTY_RMUSIC 19
+#define TX_RDS_PS_MISC_PTY_RTALK 20
+#define TX_RDS_PS_MISC_PTY_PERS 21
+#define TX_RDS_PS_MISC_PTY_PUBLIC 22
+#define TX_RDS_PS_MISC_PTY_COLLEGE 23
+#define TX_RDS_PS_MISC_PTY_UN24 24
+#define TX_RDS_PS_MISC_PTY_UN25 25
+#define TX_RDS_PS_MISC_PTY_UN26 26
+#define TX_RDS_PS_MISC_PTY_UN27 27
+#define TX_RDS_PS_MISC_PTY_UN28 28
+#define TX_RDS_PS_MISC_PTY_WTHR 29
+#define TX_RDS_PS_MISC_PTY_EMERTEST 30
+#define TX_RDS_PS_MISC_PTY_ALERT 31
+
+/* AM_CHANNEL_FILTER_BW */
+#define AM_CHANNEL_FILTER_BW_6KHZ 0
+#define AM_CHANNEL_FILTER_BW_4KHZ 1
+#define AM_CHANNEL_FILTER_BW_3KHZ 2
+#define AM_CHANNEL_FILTER_BW_2KHZ 3
+
+
+/*==================================================================
+ WB Receive Properties
+==================================================================*/
+
+
+/* WB_MAX_TUNE_ERROR */
+#define WB_MAX_TUNE_ERROR 0x5108
+
+/* WB_VALID_SNR_THRESHOLD */
+#define WB_VALID_SNR_THRESHOLD 0x5403
+#define WB_VALID_SNR_THRESHOLD_MASK 0x007F
+#define WB_VALID_SNR_THRESHOLD_SHFT 0
+
+/* WB_VALID_RSSI_THRESHOLD */
+#define WB_VALID_RSSI_THRESHOLD 0x5404
+#define WB_VALID_RSSI_THRESHOLD_MASK 0x007F
+#define WB_VALID_RSSI_THRESHOLD_SHFT 0
+
+#endif