diff options
Diffstat (limited to 'drivers/media/radio')
-rw-r--r-- | drivers/media/radio/Kconfig | 12 | ||||
-rw-r--r-- | drivers/media/radio/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/radio/si4709/Makefile | 6 | ||||
-rwxr-xr-x | drivers/media/radio/si4709/radio-si4709_common.h | 41 | ||||
-rw-r--r-- | drivers/media/radio/si4709/radio-si4709_dev.c | 2563 | ||||
-rw-r--r-- | drivers/media/radio/si4709/radio-si4709_dev.h | 181 | ||||
-rw-r--r-- | drivers/media/radio/si4709/radio-si4709_i2c_drv.c | 196 | ||||
-rw-r--r-- | drivers/media/radio/si4709/radio-si4709_i2c_drv.h | 8 | ||||
-rw-r--r-- | drivers/media/radio/si4709/radio-si4709_ioctl.h | 104 | ||||
-rw-r--r-- | drivers/media/radio/si4709/radio-si4709_main.c | 799 | ||||
-rw-r--r-- | drivers/media/radio/si4709/radio-si4709_main.h | 9 | ||||
-rw-r--r-- | drivers/media/radio/si4709/radio-si4709_regs.h | 859 |
12 files changed, 4779 insertions, 0 deletions
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 52798a1..a7ab498 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -357,6 +357,18 @@ config RADIO_SI470X source "drivers/media/radio/si470x/Kconfig" +config RADIO_SI4709 + bool "Silicon Labs Si4709 FM Radio Receiver support" + ---help--- + This is a driver for I2C devices with the Silicon Labs SI4709 + chip. + + Say Y here if you want to connect this type of radio to your + computer's I2C port. + + To compile this driver as a module, choose M here: the + module will be called radio-i2c-si470x. + config USB_MR800 tristate "AverMedia MR 800 USB FM radio support" depends on USB && VIDEO_V4L2 diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index f484a6e..5d0e62f 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_RADIO_SI470X) += si470x/ +obj-$(CONFIG_RADIO_SI4709) += si4709/ obj-$(CONFIG_USB_MR800) += radio-mr800.o obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o diff --git a/drivers/media/radio/si4709/Makefile b/drivers/media/radio/si4709/Makefile new file mode 100644 index 0000000..d110423 --- /dev/null +++ b/drivers/media/radio/si4709/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for Silicon Labs Si4709 FM Radio Receiver +# + +radio-si4709-i2c-objs := radio-si4709_dev.o radio-si4709_i2c_drv.o radio-si4709_main.o +obj-$(CONFIG_RADIO_SI4709) += radio-si4709-i2c.o diff --git a/drivers/media/radio/si4709/radio-si4709_common.h b/drivers/media/radio/si4709/radio-si4709_common.h new file mode 100755 index 0000000..c81ed92 --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_common.h @@ -0,0 +1,41 @@ +#ifndef _COMMON_H +#define _COMMON_H + +#include <linux/kernel.h> +#include <linux/types.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 + +/*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/media/radio/si4709/radio-si4709_dev.c b/drivers/media/radio/si4709/radio-si4709_dev.c new file mode 100644 index 0000000..6a65da9 --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_dev.c @@ -0,0 +1,2563 @@ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/time.h> +#include <linux/workqueue.h> + +#include <mach/gpio.h> +#include <plat/gpio-cfg.h> +#include <../../../arch/arm/mach-s5pv210/include/mach/gpio-aries.h> + +#include "radio-si4709_regs.h" +#include "radio-si4709_main.h" +#include "radio-si4709_dev.h" +#include "radio-si4709_common.h" + +enum +{ + eTRUE, + eFALSE, +}dev_struct_status_t; + +/*dev_state*/ +/*power_state*/ +#define RADIO_ON 1 +#define RADIO_POWERDOWN 0 +/*seek_state*/ +#define RADIO_SEEK_ON 1 +#define RADIO_SEEK_OFF 0 + +#define FREQ_87500_kHz 8750 +#define FREQ_76000_kHz 7600 + +#define RSSI_seek_th_MAX 0x7F +#define RSSI_seek_th_MIN 0x00 + +#define seek_SNR_th_DISB 0x00 +#define seek_SNR_th_MIN 0x01 /*most stops*/ +#define seek_SNR_th_MAX 0x0F /*fewest stops*/ + +#define seek_FM_ID_th_DISB 0x00 +#define seek_FM_ID_th_MAX 0x01 /*most stops*/ +#define seek_FM_ID_th_MIN 0x0F /*fewest stops*/ + +#define TUNE_RSSI_THRESHOLD 0x00 +#define TUNE_SNR_THRESHOLD 0x01 +#define TUNE_CNT_THRESHOLD 0x00 + +typedef struct +{ + u32 frequency; + u8 rsssi_val; +}channel_into_t; + +typedef struct +{ + u16 band; + u32 bottom_of_band; + u16 channel_spacing; + u32 timeout_RDS; /****For storing the jiffy value****/ + u32 seek_preset[NUM_SEEK_PRESETS]; + u8 curr_snr; + u8 curr_rssi_th; +}dev_settings_t; + +typedef struct +{ + /*Any function which + - views/modifies the fields of this structure + - does i2c communication + should lock the mutex before doing so. + Recursive locking should not be done. + In this file all the exported functions will take care + of this. The static functions will not deal with the + mutex*/ + struct mutex lock; + + struct i2c_client const *client; + + dev_state_t state; + + dev_settings_t settings; + + channel_into_t rssi_freq[50]; + + u16 registers[NUM_OF_REGISTERS]; + + /* This field will be checked by all the functions + exported by this file (except the init function), + to validate the the fields of this structure. + if eTRUE: the fileds are valid + if eFALSE: do not trust the values of the fields + of this structure*/ + unsigned short valid; + + /*will be true is the client ans state fields are correct*/ + unsigned short valid_client_state; +}Si4709_device_t; + + +/*extern functions*/ +/**********************************************/ +/*All the exported functions which view or modify the device + state/data, do i2c com will have to lock the mutex before + doing so*/ +/**********************************************/ +int Si4709_dev_init(struct i2c_client *); +int Si4709_dev_exit(void); + +void Si4709_dev_mutex_init(void); + +int Si4709_dev_suspend(void); +int Si4709_dev_resume(void); + +int Si4709_dev_powerup(void); +int Si4709_dev_powerdown(void); + +int Si4709_dev_band_set(int); +int Si4709_dev_ch_spacing_set(int); + +int Si4709_dev_chan_select(u32); +int Si4709_dev_chan_get(u32*); + +int Si4709_dev_seek_up(u32*); +int Si4709_dev_seek_down(u32*); +int Si4709_dev_seek_auto(u32*); + +int Si4709_dev_RSSI_seek_th_set(u8); +int Si4709_dev_seek_SNR_th_set(u8); +int Si4709_dev_seek_FM_ID_th_set(u8); +int Si4709_dev_cur_RSSI_get(rssi_snr_t*); +int Si4709_dev_VOLEXT_ENB(void); +int Si4709_dev_VOLEXT_DISB(void); +int Si4709_dev_volume_set(u8); +int Si4709_dev_volume_get(u8 *); +int Si4709_dev_DSMUTE_ON(void); +int Si4709_dev_DSMUTE_OFF(void); +int Si4709_dev_MUTE_ON(void); +int Si4709_dev_MUTE_OFF(void); +int Si4709_dev_MONO_SET(void); +int Si4709_dev_STEREO_SET(void); +int Si4709_dev_RDS_ENABLE(void); +int Si4709_dev_RDS_DISABLE(void); +int Si4709_dev_RDS_timeout_set(u32); +int Si4709_dev_rstate_get(dev_state_t*); +int Si4709_dev_RDS_data_get(radio_data_t*); +int Si4709_dev_device_id(device_id *); +int Si4709_dev_chip_id(chip_id *); +int Si4709_dev_sys_config2(sys_config2 *); +int Si4709_dev_power_config(power_config *); +int Si4709_dev_AFCRL_get(u8*); +int Si4709_dev_DE_set(u8); +/***********************************************/ + +#ifdef RDS_INTERRUPT_ON_ALWAYS +#define RDS_BUFFER_LENGTH 50 +static u16 *RDS_Block_Data_buffer; +static u8 *RDS_Block_Error_buffer; +static u8 RDS_Buffer_Index_read; //index number for last read data +static u8 RDS_Buffer_Index_write; //index number for last written data + +int Si4709_RDS_flag; +int RDS_Data_Available; +int RDS_Data_Lost; +int RDS_Groups_Available_till_now; +struct workqueue_struct *Si4709_wq; +struct work_struct Si4709_work; +#endif + +/*static functions*/ +/**********************************************/ +static void wait(void); + +static void wait_RDS(void ); + +static int powerup(void); +static int powerdown(void); + +static int seek(u32*, int); +static int tune_freq(u32); + +static void get_cur_chan_freq(u32 *, u16); + +static u16 freq_to_channel(u32); +static u32 channel_to_freq(u16); + +static int insert_preset(u32,u8,u8*); + +static int i2c_read(u8); +static int i2c_write(u8); +/**********************************************/ + +/*Si4709 device structure*/ +static Si4709_device_t Si4709_dev = +{ + .client = NULL, + .valid = eFALSE, + .valid_client_state = eFALSE, +}; + +/*Wait flag*/ +/*WAITING or WAIT_OVER or NO_WAIT*/ +int Si4709_dev_wait_flag = NO_WAIT; +#ifdef RDS_INTERRUPT_ON_ALWAYS +int Si4709_RDS_flag = NO_WAIT; +#endif + +int Si4709_dev_init(struct i2c_client *client) +{ + int ret = 0; + + debug("Si4709_dev_init called"); + + mutex_lock(&(Si4709_dev.lock)); + + Si4709_dev.client = client; + + /***reset the device here****/ + gpio_set_value(FM_RESET, GPIO_LEVEL_LOW); + mdelay(1); + gpio_set_value(FM_RESET, GPIO_LEVEL_HIGH); + mdelay(2); + + s3c_gpio_setpull(GPIO_FM_INT, S3C_GPIO_PULL_UP); + s3c_gpio_slp_setpull_updown(GPIO_FM_INT, S3C_GPIO_PULL_UP); + + Si4709_dev.state.power_state = RADIO_POWERDOWN; + Si4709_dev.state.seek_state = RADIO_SEEK_OFF; + + if( (ret = i2c_read(BOOTCONFIG) ) < 0 ) + { + debug("i2c_read failed"); + } + else + { + Si4709_dev.valid_client_state = eTRUE; + } + +#ifdef RDS_INTERRUPT_ON_ALWAYS + /*Creating Circular Buffer*/ + /*Single RDS_Block_Data buffer size is 4x16 bits*/ + RDS_Block_Data_buffer = kzalloc(RDS_BUFFER_LENGTH*8,GFP_KERNEL); + if(!RDS_Block_Data_buffer) + { + error("Not sufficient memory for creating RDS_Block_Data_buffer"); + ret = -ENOMEM; + goto EXIT; + } + + /*Single RDS_Block_Error buffer size is 4x8 bits*/ + RDS_Block_Error_buffer = kzalloc(RDS_BUFFER_LENGTH*4,GFP_KERNEL); + if(!RDS_Block_Error_buffer) + { + error("Not sufficient memory for creating RDS_Block_Error_buffer"); + ret = -ENOMEM; + kfree(RDS_Block_Data_buffer); + goto EXIT; + } + + /*Initialising read and write indices*/ + RDS_Buffer_Index_read= 0; + RDS_Buffer_Index_write= 0; + + /*Creating work-queue*/ + Si4709_wq = create_singlethread_workqueue("Si4709_wq"); + if(!Si4709_wq) + { + error("Not sufficient memory for Si4709_wq, work-queue"); + ret = -ENOMEM; + kfree(RDS_Block_Error_buffer); + kfree(RDS_Block_Data_buffer); + goto EXIT; + } + + /*Initialising work_queue*/ + INIT_WORK(&Si4709_work, Si4709_work_func); + + RDS_Data_Available = 0; + RDS_Data_Lost =0; + RDS_Groups_Available_till_now = 0; +EXIT: +#endif + + mutex_unlock(&(Si4709_dev.lock)); + + debug("Si4709_dev_init call over"); + + return ret; +} + +int Si4709_dev_exit(void) +{ + int ret = 0; + + debug("Si4709_dev_exit called"); + + mutex_lock(&(Si4709_dev.lock)); + + // Temporary blocked by abnormal function call(E-CIM 2657654) - DW Shim. 2010.03.04 + printk(KERN_ERR "Si4709_dev_exit() is called!!"); +// Si4709_dev.client = NULL; + +// Si4709_dev.valid_client_state = eFALSE; +// Si4709_dev.valid = eFALSE; + +#ifdef RDS_INTERRUPT_ON_ALWAYS + if(Si4709_wq) + destroy_workqueue(Si4709_wq); + + if(RDS_Block_Error_buffer) + kfree(RDS_Block_Error_buffer); + + if(RDS_Block_Data_buffer) + kfree(RDS_Block_Data_buffer); +#endif + + mutex_unlock(&(Si4709_dev.lock)); + + debug("Si4709_dev_exit call over"); + + return ret; +} + +void Si4709_dev_mutex_init(void) +{ + mutex_init(&(Si4709_dev.lock)); +} + +int Si4709_dev_powerup(void) +{ + int ret = 0; + u32 value = 100; + + debug("Si4709_dev_powerup called"); + + mutex_lock(&(Si4709_dev.lock)); + + if(!(RADIO_ON==Si4709_dev.state.power_state)) + { + if( (ret = powerup()) < 0 ) + { + debug("powerup failed"); + } + else if( Si4709_dev.valid_client_state == eFALSE ) + { + debug("Si4709_dev_powerup called when DS (state, client) is invalid"); + ret = -1; + } + else + { + /*initial settings*/ +#if 0 + POWERCFG_BITSET_RDSM_LOW(&Si4709_dev.registers[POWERCFG]); +#else + POWERCFG_BITSET_RDSM_HIGH(&Si4709_dev.registers[POWERCFG]); +#endif + // POWERCFG_BITSET_SKMODE_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_SKMODE_LOW(&Si4709_dev.registers[POWERCFG]); /*VNVS:18-NOV'09---- wrap at the upper and lower band limit and continue seeking*/ + SYSCONFIG1_BITSET_STCIEN_HIGH(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RDSIEN_LOW(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RDS_HIGH(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_DE_50(&Si4709_dev.registers[SYSCONFIG1]); /*VNVS:18-NOV'09--- Setting DE-Time Constant as 50us(Europe,Japan,Australia)*/ + SYSCONFIG1_BITSET_GPIO_STC_RDS_INT(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG1]); + + // SYSCONFIG2_BITSET_SEEKTH(&Si4709_dev.registers[SYSCONFIG2],2); + SYSCONFIG2_BITSET_SEEKTH(&Si4709_dev.registers[SYSCONFIG2], TUNE_RSSI_THRESHOLD); /*VNVS:18-NOV'09---- modified for detecting more stations of good quality*/ + SYSCONFIG2_BITSET_VOLUME(&Si4709_dev.registers[SYSCONFIG2],0x0F); + SYSCONFIG2_BITSET_BAND_87p5_108_MHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.band = BAND_87500_108000_kHz; + Si4709_dev.settings.bottom_of_band = FREQ_87500_kHz; + + SYSCONFIG2_BITSET_SPACE_100_KHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.channel_spacing = CHAN_SPACING_100_kHz; + + + // SYSCONFIG3_BITSET_SKSNR(&Si4709_dev.registers[SYSCONFIG3],3); + SYSCONFIG3_BITSET_SKSNR(&Si4709_dev.registers[SYSCONFIG3], TUNE_SNR_THRESHOLD);/*VNVS:18-NOV'09---- modified for detecting more stations of good quality*/ + SYSCONFIG3_BITSET_SKCNT(&Si4709_dev.registers[SYSCONFIG3], TUNE_CNT_THRESHOLD); + + SYSCONFIG3_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG3]); + + Si4709_dev.settings.timeout_RDS = msecs_to_jiffies(value); + Si4709_dev.settings.curr_snr = TUNE_SNR_THRESHOLD; + Si4709_dev.settings.curr_rssi_th = TUNE_RSSI_THRESHOLD; + + /*this will write all the above registers*/ + if( (ret = i2c_write(SYSCONFIG3)) < 0 ) + { + debug("Si4709_dev_powerup i2c_write 1 failed"); + } + else + { + Si4709_dev.valid = eTRUE; +#ifdef RDS_INTERRUPT_ON_ALWAYS + /*Initialising read and write indices*/ + RDS_Buffer_Index_read= 0; + RDS_Buffer_Index_write= 0; + + RDS_Data_Available = 0; + RDS_Data_Lost =0; + RDS_Groups_Available_till_now = 0; +#endif + } + + } + } + else + debug("Device already Powered-ON"); + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + +int Si4709_dev_powerdown(void) +{ + int ret = 0; + + msleep(500); // For avoiding turned off pop noise + debug("Si4709_dev_powerdown called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_powerdown called when DS is invalid"); + ret = -1; + } + else if ( ( ret = powerdown()) < 0 ) + { + debug("powerdown failed"); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_suspend(void) +{ + int ret = 0; + + debug("Si4709_dev_suspend called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid_client_state== eFALSE ) + { + debug("Si4709_dev_suspend called when DS (state, client) is invalid"); + ret = -1; + } +#if 0 + else if( Si4709_dev.state.power_state == RADIO_ON ) + { + ret = powerdown(); + } +#endif + + mutex_unlock(&(Si4709_dev.lock)); + + debug("Si4709_dev_enable call over"); + + return ret; +} + +int Si4709_dev_resume(void) +{ + int ret = 0; + +// debug("Si4709_dev_resume called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid_client_state == eFALSE ) + { + debug("Si4709_dev_resume called when DS (state, client) is invalid"); + ret = -1; + } +#if 0 + else if( Si4709_dev.state.power_state == RADIO_POWERDOWN ) + { + if( (ret = powerup()) < 0 ) + { + debug("powerup failed"); + } + } +#endif + + mutex_unlock(&(Si4709_dev.lock)); + +// debug("Si4709_dev_disable call over"); + + return ret; +} + +int Si4709_dev_band_set(int band) +{ + int ret = 0; + u16 sysconfig2 =0; + u16 prev_band = 0; + u32 prev_bottom_of_band = 0; + + debug("Si4709_dev_band_set called"); + + mutex_lock(&(Si4709_dev.lock)); + sysconfig2 = Si4709_dev.registers[SYSCONFIG2]; + prev_band = Si4709_dev.settings.band; + prev_bottom_of_band = Si4709_dev.settings.bottom_of_band; + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_band_set called when DS is invalid"); + ret = -1; + } + else + { + switch (band) + { + case BAND_87500_108000_kHz: + SYSCONFIG2_BITSET_BAND_87p5_108_MHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.band = BAND_87500_108000_kHz; + Si4709_dev.settings.bottom_of_band = FREQ_87500_kHz; + break; + + case BAND_76000_108000_kHz: + SYSCONFIG2_BITSET_BAND_76_108_MHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.band = BAND_76000_108000_kHz; + Si4709_dev.settings.bottom_of_band = FREQ_76000_kHz; + break; + + case BAND_76000_90000_kHz: + SYSCONFIG2_BITSET_BAND_76_90_MHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.band = BAND_76000_90000_kHz; + Si4709_dev.settings.bottom_of_band = FREQ_76000_kHz; + break; + + default: + ret = -1; + } + + if(ret == 0) + { + if( (ret = i2c_write(SYSCONFIG2)) < 0 ) + { + debug("Si4709_dev_band_set i2c_write 1 failed"); + Si4709_dev.settings.band = prev_band; + Si4709_dev.settings.bottom_of_band = prev_bottom_of_band; + Si4709_dev.registers[SYSCONFIG2] = sysconfig2; + } + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_ch_spacing_set(int ch_spacing) +{ + int ret = 0; + u16 sysconfig2 = 0; + u16 prev_ch_spacing = 0; + + debug("Si4709_dev_ch_spacing_set called"); + + mutex_lock(&(Si4709_dev.lock)); + sysconfig2 = Si4709_dev.registers[SYSCONFIG2]; + prev_ch_spacing = Si4709_dev.settings.channel_spacing; + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_ch_spacing_set called when DS is invalid"); + ret = -1; + } + else + { + switch (ch_spacing) + { + case CHAN_SPACING_200_kHz: + SYSCONFIG2_BITSET_SPACE_200_KHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.channel_spacing = CHAN_SPACING_200_kHz; + break; + + case CHAN_SPACING_100_kHz: + SYSCONFIG2_BITSET_SPACE_100_KHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.channel_spacing = CHAN_SPACING_100_kHz; + break; + + case CHAN_SPACING_50_kHz: + SYSCONFIG2_BITSET_SPACE_50_KHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.channel_spacing = CHAN_SPACING_50_kHz; + break; + + default: + ret = -1; + } + + if(ret == 0) + { + if( (ret = i2c_write(SYSCONFIG2)) < 0 ) + { + debug("Si4709_dev_ch_spacing_set i2c_write 1 failed"); + Si4709_dev.settings.channel_spacing = prev_ch_spacing; + Si4709_dev.registers[SYSCONFIG2] = sysconfig2; + } + + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_chan_select(u32 frequency) +{ + int ret = 0; + + debug("Si4709_dev_chan_select called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_chan_select called when DS is invalid"); + ret = -1; + } + else + { + Si4709_dev.state.seek_state = RADIO_SEEK_ON; + + ret = tune_freq(frequency); + debug("Si4709_dev_chan_select called1"); + Si4709_dev.state.seek_state = RADIO_SEEK_OFF; + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_chan_get(u32 *frequency) +{ + int ret = 0; + + + debug("Si4709_dev_chan_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_chan_get called when DS is invalid"); + ret = -1; + } + else if( (ret = i2c_read(READCHAN)) < 0 ) + { + debug("Si4709_dev_chan_get i2c_read failed"); + } + else + { + get_cur_chan_freq(frequency, Si4709_dev.registers[READCHAN]); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_seek_up(u32 *frequency) +{ + int ret = 0; + + debug("Si4709_dev_seek_up called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_seek_up called when DS is invalid"); + ret = -1; + } + else + { + Si4709_dev.state.seek_state = RADIO_SEEK_ON; + + ret = seek(frequency, 1); + + Si4709_dev.state.seek_state = RADIO_SEEK_OFF; + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_seek_down(u32 *frequency) +{ + int ret = 0; + + debug("Si4709_dev_seek_down called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_seek_down called when DS is invalid"); + ret = -1; + } + else + { + Si4709_dev.state.seek_state = RADIO_SEEK_ON; + + ret = seek(frequency, 0); + + Si4709_dev.state.seek_state = RADIO_SEEK_OFF; + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + +#if 0 +int Si4709_dev_seek_auto(u32 *seek_preset_user) +{ + u8 *rssi_seek; + int ret = 0; + int i =0; + int j = 0; + channel_into_t temp; + + debug("Si4709_dev_seek_auto called"); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_seek_auto called when DS is invalid"); + ret = -1; + } + + else if( (rssi_seek = (u8 *)kzalloc(sizeof(u8) * NUM_SEEK_PRESETS, GFP_KERNEL)) == NULL ) + { + debug("Si4709_ioctl: no memory"); + ret = -ENOMEM; + } + + else + { + + if( (ret = tune_freq(FREQ_87500_kHz)) == 0 ) + { + debug("Si4709_dev_seek_auto tune_freq success"); + get_cur_chan_freq(&(Si4709_dev.rssi_freq[0].frequency), Si4709_dev.registers[READCHAN]); + Si4709_dev_cur_RSSI_get(&(Si4709_dev.rssi_freq[0].rsssi_val)); + + } + else + { + debug("tunning failed, seek auto failed"); + ret =-1; + } + #if 0 + for(i=0;i<50; i++) + { + if( (ret = seek(&(Si4709_dev.settings.seek_preset[i]),1)) == 0 ) + { + get_cur_chan_freq(&(Si4709_dev.rssi_freq[i].frequency), Si4709_dev.registers[READCHAN]); + Si4709_dev_cur_RSSI_get(&(Si4709_dev.rssi_freq[i].rsssi_val)); + rssi_seek ++; + } + + else + { + debug("seek failed"); + + } + } + #endif + + + + /***new method ****/ + for(i=1;i<30; i++) + { + if( (ret = seek(&(Si4709_dev.settings.seek_preset[i]),1)) == 0 ) + { + get_cur_chan_freq(&(Si4709_dev.rssi_freq[i].frequency), Si4709_dev.registers[READCHAN]); + Si4709_dev_cur_RSSI_get(&(Si4709_dev.rssi_freq[i].rsssi_val)); + } + + else + { + debug("seek failed"); + + } + } + /***Sort the array of structures on the basis of RSSI value****/ + for(i=0;i<29;i++) + { + + for(j=i+1;j<30;j++) + { + + if( Si4709_dev.rssi_freq[j].rsssi_val>Si4709_dev.rssi_freq[i].rsssi_val) + { + temp=Si4709_dev.rssi_freq[i]; + Si4709_dev.rssi_freq[i]=Si4709_dev.rssi_freq[j]; + Si4709_dev.rssi_freq[j]=temp; + } + + } + + } + + /***Store the frequency in Array*****/ + for(i=0;i<19;i++) + { + Si4709_dev.settings.seek_preset[i]=Si4709_dev.rssi_freq[i].frequency; + } + + + + } + memcpy(seek_preset_user, Si4709_dev.settings.seek_preset , sizeof(int)*NUM_SEEK_PRESETS); + kfree(rssi_seek); + return ret; +} +#endif + + + +int Si4709_dev_RSSI_seek_th_set(u8 seek_th) +{ + int ret = 0; + u16 sysconfig2 = 0; + + debug("Si4709_dev_RSSI_seek_th_set called"); + + mutex_lock(&(Si4709_dev.lock)); + sysconfig2 = Si4709_dev.registers[SYSCONFIG2]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_RSSI_seek_th_set called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG2_BITSET_SEEKTH(&Si4709_dev.registers[SYSCONFIG2], seek_th); + Si4709_dev.settings.curr_rssi_th=seek_th; + if( (ret = i2c_write( SYSCONFIG2 )) < 0 ) + { + debug("Si4709_dev_RSSI_seek_th_set i2c_write 1 failed"); + Si4709_dev.registers[SYSCONFIG2] = sysconfig2; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_seek_SNR_th_set(u8 seek_SNR) +{ + int ret = 0; + u16 sysconfig3 = 0; + + debug("Si4709_dev_seek_SNR_th_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig3 = Si4709_dev.registers[SYSCONFIG3]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_seek_SNR_th_set called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG3_BITSET_SKSNR(&Si4709_dev.registers[SYSCONFIG3], seek_SNR); + SYSCONFIG3_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG3]); + Si4709_dev.settings.curr_snr=seek_SNR; + + if( (ret = i2c_write( SYSCONFIG3 )) < 0 ) + { + debug("Si4709_dev_seek_SNR_th_set i2c_write 1 failed"); + Si4709_dev.registers[SYSCONFIG3] = sysconfig3; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_seek_FM_ID_th_set(u8 seek_FM_ID_th) +{ + int ret = 0; + u16 sysconfig3 = 0; + + debug("Si4709_dev_seek_FM_ID_th_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig3 = Si4709_dev.registers[SYSCONFIG3]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_seek_SNR_th_set called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG3_BITSET_SKCNT(&Si4709_dev.registers[SYSCONFIG3], seek_FM_ID_th); + SYSCONFIG3_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG3]); + + if( (ret = i2c_write( SYSCONFIG3 )) < 0 ) + { + debug("Si4709_dev_seek_FM_ID_th_set i2c_write 1 failed"); + sysconfig3 = Si4709_dev.registers[SYSCONFIG3]; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_cur_RSSI_get(rssi_snr_t *cur_RSSI) +{ + int ret = 0; + + debug("Si4709_dev_cur_RSSI_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_cur_RSSI_get called when DS is invalid"); + ret = -1; + } + else + { + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("Si4709_dev_cur_RSSI_get i2c_read 1 failed"); + } + else + { + + cur_RSSI->curr_rssi= STATUSRSSI_RSSI_SIGNAL_STRENGTH(Si4709_dev.registers[STATUSRSSI]); + cur_RSSI->curr_rssi_th=Si4709_dev.settings.curr_rssi_th; + cur_RSSI->curr_snr=Si4709_dev.settings.curr_snr; + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +/*VNVS:START 13-OCT'09---- Functions which reads device-id,chip-id,power configuration, system configuration2 registers */ +int Si4709_dev_device_id(device_id *dev_id) +{ + int ret = 0; + + debug("Si4709_dev_device_id called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_device_id called when DS is invalid"); + ret = -1; + } + else + { + if( (ret = i2c_read(DEVICE_ID)) < 0 ) + { + debug("Si4709_dev_device_id i2c_read failed"); + } + else + { + + dev_id->part_number= DEVICE_ID_PART_NUMBER(Si4709_dev.registers[DEVICE_ID]); + dev_id->manufact_number = DEVICE_ID_MANUFACT_NUMBER(Si4709_dev.registers[DEVICE_ID]); + + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_chip_id(chip_id *chp_id) +{ + int ret = 0; + + debug("Si4709_dev_chip_id called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_chip_id called when DS is invalid"); + ret = -1; + } + else + { + if( (ret = i2c_read(CHIP_ID)) < 0 ) + { + debug("Si4709_dev_chip_id i2c_read failed"); + } + else + { + + chp_id->chip_version= CHIP_ID_CHIP_VERSION(Si4709_dev.registers[CHIP_ID]); + chp_id->device = CHIP_ID_DEVICE(Si4709_dev.registers[CHIP_ID]); + chp_id->firmware_version = CHIP_ID_FIRMWARE_VERSION(Si4709_dev.registers[CHIP_ID]); + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_sys_config2(sys_config2 *sys_conf2) +{ + int ret = 0; + + debug("Si4709_sys_config2 called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_sys_config2 called when DS is invalid"); + ret = -1; + } + else + { + if((ret = i2c_read(SYSCONFIG2)) < 0) + { + debug("Si4709_sys_config2 i2c_read failed"); + } + else + { + sys_conf2->rssi_th =SYS_CONFIG2_RSSI_TH(Si4709_dev.registers[SYSCONFIG2]); + sys_conf2->fm_band = SYS_CONFIG2_FM_BAND(Si4709_dev.registers[SYSCONFIG2]); + sys_conf2->fm_chan_spac = SYS_CONFIG2_FM_CHAN_SPAC(Si4709_dev.registers[SYSCONFIG2]); + sys_conf2->fm_vol = SYS_CONFIG2_FM_VOL(Si4709_dev.registers[SYSCONFIG2]); + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_sys_config3(sys_config3 *sys_conf3) +{ + int ret = 0; + + debug("Si4709_sys_config3 called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_sys_config3 called when DS is invalid"); + ret = -1; + } + else + { + if((ret = i2c_read(SYSCONFIG3)) < 0) + { + debug("Si4709_sys_config3 i2c_read failed"); + } + else + { + sys_conf3->smmute = (Si4709_dev.registers[SYSCONFIG3] & 0xC000) >> 14; + sys_conf3->smutea = (Si4709_dev.registers[SYSCONFIG3] & 0x3000) >> 12; + sys_conf3->volext = (Si4709_dev.registers[SYSCONFIG3] & 0x0100) >> 8; + sys_conf3->sksnr = (Si4709_dev.registers[SYSCONFIG3] & 0x00F0) >> 4; + sys_conf3->skcnt = (Si4709_dev.registers[SYSCONFIG3] & 0x000F); + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_status_rssi(status_rssi *status) +{ + int ret = 0; + + debug("Si4709_dev_status_rssi called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_status_rssi called when DS is invalid"); + ret = -1; + } + else + { + if((ret = i2c_read(STATUSRSSI)) < 0) + { + debug("Si4709_sys_config3 i2c_read failed"); + } + else + { + status->rdsr = (Si4709_dev.registers[STATUSRSSI] & 0x8000) >> 15; + status->stc = (Si4709_dev.registers[STATUSRSSI] & 0x4000) >> 14; + status->sfbl = (Si4709_dev.registers[STATUSRSSI] & 0x2000) >> 13; + status->afcrl = (Si4709_dev.registers[STATUSRSSI] & 0x1000) >> 12; + status->rdss = (Si4709_dev.registers[STATUSRSSI] & 0x0800) >> 11; + status->blera = (Si4709_dev.registers[STATUSRSSI] & 0x0600) >> 9; + status->st = (Si4709_dev.registers[STATUSRSSI] & 0x0100) >> 8; + status->rssi = (Si4709_dev.registers[STATUSRSSI] & 0x00FF); + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_sys_config2_set(sys_config2 *sys_conf2) +{ + int ret = 0; + u16 register_bak = 0; + + debug("Si4709_dev_sys_config2_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + register_bak = Si4709_dev.registers[SYSCONFIG2]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_sys_config2_set called when DS is invalid"); + ret = -1; + } + else + { + printk(KERN_ERR "Si4709_dev_sys_config2_set() : Register Value = [0x%X], rssi-th = [%X]\n", Si4709_dev.registers[SYSCONFIG2], sys_conf2->rssi_th); + Si4709_dev.registers[SYSCONFIG2] = (Si4709_dev.registers[SYSCONFIG2] & 0x00FF) | ((sys_conf2->rssi_th) << 8); + Si4709_dev.registers[SYSCONFIG2] = (Si4709_dev.registers[SYSCONFIG2] & 0xFF3F) | ((sys_conf2->fm_band) << 6); + Si4709_dev.registers[SYSCONFIG2] = (Si4709_dev.registers[SYSCONFIG2] & 0xFFCF) | ((sys_conf2->fm_chan_spac) << 4); + Si4709_dev.registers[SYSCONFIG2] = (Si4709_dev.registers[SYSCONFIG2] & 0xFFF0) | (sys_conf2->fm_vol); + printk(KERN_ERR "Si4709_dev_sys_config2_set() : After Register Value = [0x%X]\n", Si4709_dev.registers[SYSCONFIG2]); + + if( (ret = i2c_write( SYSCONFIG2 )) < 0 ) + { + debug("Si4709_dev_sys_config2_set i2c_write 1 failed"); + Si4709_dev.registers[SYSCONFIG2] = register_bak; + } + else + printk(KERN_ERR "Si4709_dev_sys_config2_set() : Write Sucess!!"); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_sys_config3_set(sys_config3 *sys_conf3) +{ + int ret = 0; + u16 register_bak = 0; + + debug("Si4709_dev_sys_config3_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + register_bak = Si4709_dev.registers[SYSCONFIG3]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_sys_config3_set called when DS is invalid"); + ret = -1; + } + else + { + printk(KERN_ERR "Si4709_dev_sys_config3_set() : Register Value = [0x%X], sksnrth = [%X]\n", Si4709_dev.registers[SYSCONFIG3], sys_conf3->sksnr); + Si4709_dev.registers[SYSCONFIG3] = (Si4709_dev.registers[SYSCONFIG3] & 0x3FFF) | ((sys_conf3->smmute) << 14); + Si4709_dev.registers[SYSCONFIG3] = (Si4709_dev.registers[SYSCONFIG3] & 0xCFFF) | ((sys_conf3->smutea) << 12); + Si4709_dev.registers[SYSCONFIG3] = (Si4709_dev.registers[SYSCONFIG3] & 0xFEFF) | ((sys_conf3->volext) << 8); + Si4709_dev.registers[SYSCONFIG3] = (Si4709_dev.registers[SYSCONFIG3] & 0xFF0F) | ((sys_conf3->sksnr) << 4); + Si4709_dev.registers[SYSCONFIG3] = (Si4709_dev.registers[SYSCONFIG3] & 0xFFF0) | (sys_conf3->skcnt); + printk(KERN_ERR "Si4709_dev_sys_config3_set() : After Register Value = [0x%X]\n", Si4709_dev.registers[SYSCONFIG3]); + + if((ret = i2c_write( SYSCONFIG3)) < 0) + { + debug("Si4709_dev_sys_config3_set i2c_write 1 failed"); + Si4709_dev.registers[SYSCONFIG3] = register_bak; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_power_config(power_config *pow_conf) +{ + int ret =0; + + debug("Si4709_dev_power_config called"); + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_power_config called when DS is invalid"); + ret = -1; + } + else + { + if( (ret = i2c_read(POWERCFG)) < 0 ) + { + debug("Si4709_dev_power_config i2c_read failed"); + } + else + { + + pow_conf->dsmute =POWER_CONFIG_SOFTMUTE_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->dmute =POWER_CONFIG_MUTE_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->mono =POWER_CONFIG_MONO_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->rds_mode =POWER_CONFIG_RDS_MODE_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->sk_mode =POWER_CONFIG_SKMODE_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->seek_up =POWER_CONFIG_SEEKUP_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->seek =POWER_CONFIG_SEEK_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->power_disable =POWER_CONFIG_DISABLE_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->power_enable =POWER_CONFIG_ENABLE_STATUS(Si4709_dev.registers[POWERCFG]); + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} +/*VNVS:END*/ + +/*VNVS:START 18-NOV'09*/ +/*Reading AFCRL Bit*/ +int Si4709_dev_AFCRL_get(u8 *afc) +{ + int ret = 0; + + debug("Si4709_dev_AFCRL_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_AFCRL_get called when DS is invalid"); + ret = -1; + } + else + { + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("Si4709_dev_AFCRL_get i2c_read failed"); + } + *afc = STATUSRSSI_AFC_RAIL_STATUS(Si4709_dev.registers[STATUSRSSI]); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} +/*Setting DE-emphasis time constant 50us(Europe,Japan,Australia) or 75us(USA)*/ +int Si4709_dev_DE_set(u8 de_tc) +{ + u16 sysconfig1 = 0; + int ret = 0; + + debug("Si4709_dev_DE_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig1 = Si4709_dev.registers[SYSCONFIG1]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_DE_set called when DS is invalid"); + ret = -1; + } + else + { + switch(de_tc) + { + case DE_TIME_CONSTANT_50: + SYSCONFIG1_BITSET_DE_50(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RESERVED( &Si4709_dev.registers[SYSCONFIG1] ); + break; + case DE_TIME_CONSTANT_75: + SYSCONFIG1_BITSET_DE_75(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RESERVED( &Si4709_dev.registers[SYSCONFIG1] ); + break; + default: + ret = -1; + } + + if(0==ret) + if( (ret = i2c_write(SYSCONFIG1)) < 0 ) + { + debug("Si4709_dev_DE_set i2c_write failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +/*Resetting the RDS Data Buffer*/ +int Si4709_dev_reset_rds_data() +{ + int ret = 0; + + debug_rds("Si4709_dev_reset_rds_data called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_reset_rds_data called when DS is invalid"); + ret = -1; + } + else + { + RDS_Buffer_Index_write = 0; + RDS_Buffer_Index_read = 0; + RDS_Data_Lost = 0; + RDS_Data_Available = 0; + memset(RDS_Block_Data_buffer,0,RDS_BUFFER_LENGTH*8); + memset(RDS_Block_Error_buffer,0,RDS_BUFFER_LENGTH*4); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} +/*VNVS:END*/ +int Si4709_dev_VOLEXT_ENB(void) +{ + int ret = 0; + u16 sysconfig3 = 0; + + debug("Si4709_dev_VOLEXT_ENB called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig3 = Si4709_dev.registers[SYSCONFIG3]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_VOLEXT_ENB called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG3_BITSET_VOLEXT_ENB(&Si4709_dev.registers[SYSCONFIG3]); + SYSCONFIG3_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG3]); + + if( (ret = i2c_write( SYSCONFIG3 )) < 0 ) + { + debug("Si4709_dev_VOLEXT_ENB i2c_write failed"); + Si4709_dev.registers[SYSCONFIG3] = sysconfig3; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_VOLEXT_DISB(void) +{ + int ret = 0; + u16 sysconfig3 = 0; + + debug("Si4709_dev_VOLEXT_DISB called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig3 = Si4709_dev.registers[SYSCONFIG3]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_VOLEXT_DISB called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG3_BITSET_VOLEXT_DISB(&Si4709_dev.registers[SYSCONFIG3]); + SYSCONFIG3_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG3]); + + if( (ret = i2c_write( SYSCONFIG3 )) < 0 ) + { + debug("Si4709_dev_VOLEXT_DISB i2c_write failed"); + Si4709_dev.registers[SYSCONFIG3] = sysconfig3; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_volume_set(u8 volume) +{ + int ret = 0; + u16 sysconfig2 = 0; + + debug("Si4709_dev_volume_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig2 = Si4709_dev.registers[SYSCONFIG2]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_volume_set called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG2_BITSET_VOLUME(&Si4709_dev.registers[SYSCONFIG2], volume); + + if( (ret = i2c_write( SYSCONFIG2 )) < 0 ) + { + debug("Si4709_dev_volume_set i2c_write failed"); + Si4709_dev.registers[SYSCONFIG2] = sysconfig2; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_volume_get(u8 *volume) +{ + int ret = 0; + + debug("Si4709_dev_volume_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_volume_get called when DS is invalid"); + ret = -1; + } + else + { + *volume = SYSCONFIG2_GET_VOLUME(Si4709_dev.registers[SYSCONFIG2]); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +/* + VNVS:START 19-AUG'10---- Adding DSMUTE ON/OFF feature.The Soft Mute feature is available to attenuate the audio + outputs and minimize audible noise in very weak signal conditions. + */ +int Si4709_dev_DSMUTE_ON(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_DSMUTE_ON called"); + + mutex_lock(&(Si4709_dev.lock)); + + powercfg = Si4709_dev.registers[POWERCFG]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_DSMUTE_ON called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_DSMUTE_LOW(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + error("Si4709_dev_DSMUTE_ON i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_DSMUTE_OFF(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_DSMUTE_OFF called"); + + mutex_lock(&(Si4709_dev.lock)); + + powercfg = Si4709_dev.registers[POWERCFG]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_DSMUTE_OFF called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_DSMUTE_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + error("Si4709_dev_DSMUTE_OFF i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} +/*VNVS:END*/ + +int Si4709_dev_MUTE_ON(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_MUTE_ON called"); + + mutex_lock(&(Si4709_dev.lock)); + powercfg = Si4709_dev.registers[POWERCFG]; + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_MUTE_ON called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_DMUTE_LOW(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + debug("Si4709_dev_MUTE_ON i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_MUTE_OFF(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_MUTE_OFF called"); + + mutex_lock(&(Si4709_dev.lock)); + + powercfg = Si4709_dev.registers[POWERCFG]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_MUTE_OFF called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_DMUTE_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + debug("Si4709_dev_MUTE_OFF i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_MONO_SET(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_MONO_SET called"); + + mutex_lock(&(Si4709_dev.lock)); + + powercfg = Si4709_dev.registers[POWERCFG]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_MONO_SET called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_MONO_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + debug("Si4709_dev_MONO_SET i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_STEREO_SET(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_STEREO_SET called"); + + mutex_lock(&(Si4709_dev.lock)); + + powercfg = Si4709_dev.registers[POWERCFG]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_STEREO_SET called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_MONO_LOW(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + debug("Si4709_dev_STEREO_SET i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_RDS_ENABLE(void) +{ + u16 sysconfig1 = 0; + int ret = 0; + + debug("Si4709_dev_RDS_ENABLE called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig1 = Si4709_dev.registers[SYSCONFIG1]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_RDS_ENABLE called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG1_BITSET_RDS_HIGH(&Si4709_dev.registers[SYSCONFIG1]); +#ifdef RDS_INTERRUPT_ON_ALWAYS + SYSCONFIG1_BITSET_RDSIEN_HIGH(&Si4709_dev.registers[SYSCONFIG1]); +#endif + SYSCONFIG1_BITSET_RESERVED( &Si4709_dev.registers[SYSCONFIG1] ); + if( (ret = i2c_write(SYSCONFIG1)) < 0 ) + { + debug("Si4709_dev_RDS_ENABLE i2c_write failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + } +#ifdef RDS_INTERRUPT_ON_ALWAYS + else + Si4709_RDS_flag = RDS_WAITING; +#endif + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + + +int Si4709_dev_RDS_DISABLE(void) +{ + u16 sysconfig1 = 0; + int ret = 0; + + debug("Si4709_dev_RDS_DISABLE called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig1 = Si4709_dev.registers[SYSCONFIG1]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_RDS_DISABLE called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG1_BITSET_RDS_LOW(&Si4709_dev.registers[SYSCONFIG1]); +#ifdef RDS_INTERRUPT_ON_ALWAYS + SYSCONFIG1_BITSET_RDSIEN_LOW(&Si4709_dev.registers[SYSCONFIG1]); +#endif + SYSCONFIG1_BITSET_RESERVED( &Si4709_dev.registers[SYSCONFIG1] ); + if( (ret = i2c_write(SYSCONFIG1)) < 0 ) + { + debug("Si4709_dev_RDS_DISABLE i2c_write failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + } +#ifdef RDS_INTERRUPT_ON_ALWAYS + else + Si4709_RDS_flag = NO_WAIT; +#endif + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + +int Si4709_dev_rstate_get(dev_state_t *dev_state) +{ + int ret = 0; + + debug("Si4709_dev_rstate_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_rstate_get called when DS is invalid"); + ret = -1; + } + else + { + dev_state->power_state = Si4709_dev.state.power_state; + dev_state->seek_state = Si4709_dev.state.seek_state; + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + +/*VNVS:START 7-JUNE'10 Function call for work-queue "Si4709_wq"*/ +#ifdef RDS_INTERRUPT_ON_ALWAYS +void Si4709_work_func(struct work_struct *work) +{ + int i,ret = 0; +#ifdef RDS_TESTING + u8 group_type; +#endif + debug_rds("%s",__func__); +// mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + error("Si4709_dev_RDS_data_get called when DS is invalid"); + ret = -1; + } + else + { + + if(RDS_Data_Lost > 1) + debug_rds("No_of_RDS_groups_Lost till now : %d",RDS_Data_Lost); + + + /*RDSR bit and RDS Block data, so reading the RDS registers*/ + if((ret = i2c_read(RDSD)) < 0) + error("Si4709_work_func i2c_read failed"); + else + { + /*Checking whether RDS Ready bit is set or not, if not set return immediately*/ + if(!(STATUSRSSI_RDS_READY_STATUS(Si4709_dev.registers[STATUSRSSI]))) + { + error("RDS Ready Bit Not set"); + return; + } + + debug_rds("RDS Ready bit is set"); + + debug_rds("No_of_RDS_groups_Available : %d",RDS_Data_Available); + + RDS_Data_Available = 0; + + debug_rds("RDS_Buffer_Index_write = %d",RDS_Buffer_Index_write); + + /*Writing into the Circular Buffer*/ + + /*Writing into RDS_Block_Data_buffer*/ + i = 0; + RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_write] = Si4709_dev.registers[RDSA]; + RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_write] = Si4709_dev.registers[RDSB]; + RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_write] = Si4709_dev.registers[RDSC]; + RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_write] = Si4709_dev.registers[RDSD]; + + /*Writing into RDS_Block_Error_buffer*/ + i = 0; + RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_write] = STATUSRSSI_RDS_BLOCK_A_ERRORS(Si4709_dev.registers[STATUSRSSI]); + RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_write] = READCHAN_BLOCK_B_ERRORS(Si4709_dev.registers[READCHAN]); + RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_write] = READCHAN_BLOCK_C_ERRORS(Si4709_dev.registers[READCHAN]); + RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_write] = READCHAN_BLOCK_D_ERRORS(Si4709_dev.registers[READCHAN]); + +#ifdef RDS_TESTING + if(RDS_Block_Error_buffer[0 + 4*RDS_Buffer_Index_write] < 3) + { + debug_rds("PI Code is %d",RDS_Block_Data_buffer[0 + 4*RDS_Buffer_Index_write]); + } + if(RDS_Block_Error_buffer[1 + 4*RDS_Buffer_Index_write] < 2) + { + group_type = RDS_Block_Data_buffer[1 + 4*RDS_Buffer_Index_write] >> 11; + + if (group_type & 0x01) + { + debug_rds("PI Code is %d",RDS_Block_Data_buffer[2 + 4*RDS_Buffer_Index_write]); + } + if(group_type == GROUP_TYPE_2A || group_type == GROUP_TYPE_2B ) + { + if(RDS_Block_Error_buffer[2 + 4*RDS_Buffer_Index_write] < 3) + { + debug_rds("Update RT with RDSC"); + } + else + { + debug_rds("RDS_Block_Error_buffer of Block C is greater than 3"); + } + } + } +#endif + RDS_Buffer_Index_write++; + + if(RDS_Buffer_Index_write >= RDS_BUFFER_LENGTH) + RDS_Buffer_Index_write = 0; + + debug_rds("RDS_Buffer_Index_write = %d",RDS_Buffer_Index_write); + } + } + +// mutex_unlock(&(Si4709_dev.lock)); +} +#endif +/*VNVS:END*/ + +int Si4709_dev_RDS_data_get(radio_data_t *data) +{ + int i,ret = 0; + u16 sysconfig1 = 0; + + debug_rds("Si4709_dev_RDS_data_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig1 = Si4709_dev.registers[SYSCONFIG1]; + + if( Si4709_dev.valid == eFALSE ) + { + error("Si4709_dev_RDS_data_get called when DS is invalid"); + ret = -1; + } + else + { +#ifdef RDS_INTERRUPT_ON_ALWAYS + + debug_rds("RDS_Buffer_Index_read = %d",RDS_Buffer_Index_read); + + /*If No New RDS Data is available return error*/ + if(RDS_Buffer_Index_read == RDS_Buffer_Index_write) + { + debug_rds("No_New_RDS_Data_is_available"); + if((ret = i2c_read(READCHAN)) < 0) + error("Si4709_dev_RDS_data_get i2c_read 1 failed"); + else + { + get_cur_chan_freq(&(data->curr_channel), Si4709_dev.registers[READCHAN]); + data->curr_rssi = STATUSRSSI_RSSI_SIGNAL_STRENGTH(Si4709_dev.registers[STATUSRSSI]); + debug_rds("curr_channel: %u, curr_rssi:%u",data->curr_channel,(u32)data->curr_rssi); + } + ret = -1; + } + else + { + if((ret = i2c_read(READCHAN)) < 0) + error("Si4709_dev_RDS_data_get i2c_read 2 failed"); + else + { + get_cur_chan_freq(&(data->curr_channel), Si4709_dev.registers[READCHAN]); + data->curr_rssi = STATUSRSSI_RSSI_SIGNAL_STRENGTH(Si4709_dev.registers[STATUSRSSI]); + debug_rds("curr_channel: %u, curr_rssi:%u",data->curr_channel,(u32)data->curr_rssi); + + /*Reading from RDS_Block_Data_buffer*/ + i = 0; + data->rdsa = RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->rdsb = RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->rdsc = RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->rdsd = RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_read]; + + /*Reading from RDS_Block_Error_buffer*/ + i = 0; + data->blera = RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->blerb = RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->blerc = RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->blerd = RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_read]; + + /*Flushing the read data*/ + memset(&RDS_Block_Data_buffer[0+4*RDS_Buffer_Index_read],0,8); + memset(&RDS_Block_Error_buffer[0+4*RDS_Buffer_Index_read],0,4); + + RDS_Buffer_Index_read++; + + if(RDS_Buffer_Index_read >= RDS_BUFFER_LENGTH) + RDS_Buffer_Index_read = 0; + } + } + + debug_rds("RDS_Buffer_Index_read = %d",RDS_Buffer_Index_read); + +#else + SYSCONFIG1_BITSET_RDSIEN_HIGH(&Si4709_dev.registers[SYSCONFIG1]); + + if((ret = i2c_write(SYSCONFIG1)) < 0) + { + debug("Si4709_dev_RDS_data_get i2c_write 1 failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + } + else + { + if( (ret=i2c_read(SYSCONFIG1)) < 0) + debug("Si4709_dev_RDS_data_get i2c_read 1 failed"); + + debug("sysconfig1: 0x%x",Si4709_dev.registers[SYSCONFIG1] ); + sysconfig1 = Si4709_dev.registers[SYSCONFIG1]; + + Si4709_dev_wait_flag = RDS_WAITING; + + wait_RDS(); + + if((ret=i2c_read(STATUSRSSI)) < 0) + debug("Si4709_dev_RDS_data_get i2c_read 2 failed"); + + debug("statusrssi: 0x%x",Si4709_dev.registers[STATUSRSSI] ); + SYSCONFIG1_BITSET_RDSIEN_LOW(&Si4709_dev.registers[SYSCONFIG1]); + + if ((ret = i2c_write(SYSCONFIG1)) < 0) + { + debug("Si4709_dev_RDS_data_get i2c_write 2 failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + } + else if(Si4709_dev_wait_flag == WAIT_OVER) + { + Si4709_dev_wait_flag = NO_WAIT; + + if((ret = i2c_read(RDSD)) < 0) + debug("Si4709_dev_RDS_data_get i2c_read 3 failed"); + else + { + data->rdsa = Si4709_dev.registers[RDSA]; + data->rdsb = Si4709_dev.registers[RDSB]; + data->rdsc = Si4709_dev.registers[RDSC]; + data->rdsd = Si4709_dev.registers[RDSD]; + + get_cur_chan_freq(&(data->curr_channel), Si4709_dev.registers[READCHAN]); + debug("curr_channel: %u",data->curr_channel); + data->curr_rssi = STATUSRSSI_RSSI_SIGNAL_STRENGTH(Si4709_dev.registers[STATUSRSSI]); + debug("curr_rssi:%u",(u32)data->curr_rssi); + data->blera = STATUSRSSI_RDS_BLOCK_A_ERRORS(Si4709_dev.registers[STATUSRSSI]); + data->blerb = READCHAN_BLOCK_B_ERRORS(Si4709_dev.registers[READCHAN]); + data->blerc = READCHAN_BLOCK_C_ERRORS(Si4709_dev.registers[READCHAN]); + data->blerd = READCHAN_BLOCK_D_ERRORS(Si4709_dev.registers[READCHAN]); + } + } + else + { + debug("Si4709_dev_RDS_data_get failure no interrupt or timeout"); + Si4709_dev_wait_flag = NO_WAIT; + ret = -1; + } + } +#endif + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_RDS_timeout_set(u32 time_out) +{ + int ret = 0; + u32 jiffy_count = 0; + + debug("Si4709_dev_RDS_timeout_set called"); + /****convert time_out(in milliseconds) into jiffies*****/ + + jiffy_count = msecs_to_jiffies(time_out); + + debug("jiffy_count%d",jiffy_count); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_RDS_timeout_set called when DS is invalid"); + ret = -1; + } + else + { + Si4709_dev.settings.timeout_RDS = jiffy_count; + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + +/**************************************************************/ +static int powerup(void) +{ + int ret=0; + u16 powercfg = Si4709_dev.registers[POWERCFG]; + int reg; + /****Resetting the device****/ + + gpio_set_value(FM_RESET, GPIO_LEVEL_LOW); + gpio_set_value(FM_RESET, GPIO_LEVEL_HIGH); + +#if 0 + /*Add the i2c driver*/ + if ( (ret = Si4709_i2c_drv_init() < 0) ) + { + debug("Si4709_i2c_drv_init failed"); + } +#endif + /*Resetting the Si4709_dev.registers[] array*/ + for(reg=0;reg < NUM_OF_REGISTERS;reg++) + Si4709_dev.registers[reg] = 0; + + debug("Resetting the Si4709_dev.registers[] array"); + + POWERCFG_BITSET_DMUTE_HIGH( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_ENABLE_HIGH( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_DISABLE_LOW( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_RESERVED( &Si4709_dev.registers[POWERCFG] ); + + if( (ret = i2c_write(POWERCFG)) < 0 ) + { + debug("powerup->i2c_write 1 failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + else + { + /*Si4709/09 datasheet: Table 7*/ + mdelay(110); + Si4709_dev.state.power_state = RADIO_ON; + } + + return ret; +} + +static int powerdown(void) +{ + int ret = 0; + u16 test1 = Si4709_dev.registers[TEST1], + sysconfig1 = Si4709_dev.registers[SYSCONFIG1], + powercfg = Si4709_dev.registers[POWERCFG]; + + if(!(RADIO_POWERDOWN==Si4709_dev.state.power_state)) + { + //TEST1_BITSET_AHIZEN_HIGH( &Si4709_dev.registers[TEST1] ); + //TEST1_BITSET_RESERVED( &Si4709_dev.registers[TEST1] ); + + SYSCONFIG1_BITSET_GPIO_LOW(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RESERVED( &Si4709_dev.registers[SYSCONFIG1] ); + /*VNVS: 13-OCT'09---- During Powerdown of the device RDS should be disabled + according to the Si4708/09 datasheet*/ + SYSCONFIG1_BITSET_RDS_LOW(&Si4709_dev.registers[SYSCONFIG1]); + + POWERCFG_BITSET_DMUTE_LOW( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_ENABLE_HIGH( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_DISABLE_HIGH( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_RESERVED( &Si4709_dev.registers[POWERCFG] ); + + /*this will write all the above registers*/ + if( (ret = i2c_write( TEST1 )) < 0 ) + { + debug("powerdown->i2c_write failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + Si4709_dev.registers[POWERCFG] = powercfg; + Si4709_dev.registers[TEST1] = test1; + } + else + { + Si4709_dev.state.power_state = RADIO_POWERDOWN; + } + + /****Resetting the device****/ + gpio_set_value(FM_RESET, GPIO_LEVEL_LOW); + gpio_set_value(FM_RESET, GPIO_LEVEL_HIGH); + gpio_set_value(FM_RESET, GPIO_LEVEL_LOW); + } + else + debug("Device already Powered-OFF"); + + return ret; +} + +static int seek(u32 *frequency, int up) +{ + int ret = 0; + u16 powercfg = Si4709_dev.registers[POWERCFG]; + u16 channel = 0; + int valid_station_found = 0; + + if( up ) + { + POWERCFG_BITSET_SEEKUP_HIGH(&Si4709_dev.registers[POWERCFG]); + } + else + { + POWERCFG_BITSET_SEEKUP_LOW(&Si4709_dev.registers[POWERCFG]); + } + + POWERCFG_BITSET_SKMODE_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_SEEK_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write(POWERCFG)) < 0 ) + { + debug("seek i2c_write 1 failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + else + { + Si4709_dev_wait_flag = SEEK_WAITING; + + wait(); + + if ( Si4709_dev_wait_flag == SEEK_CANCEL ) + { + powercfg = Si4709_dev.registers[POWERCFG]; + POWERCFG_BITSET_SEEK_LOW(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write(POWERCFG)) < 0 ) + { + debug("seek i2c_write 2 failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + + if( (ret = i2c_read( READCHAN )) < 0 ) + { + debug("seek i2c_read 1 failed"); + } + else + { + channel = READCHAN_GET_CHAN(Si4709_dev.registers[READCHAN]); + *frequency = channel_to_freq(channel); + } + *frequency = 0; + } + + Si4709_dev_wait_flag = NO_WAIT; + + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("seek i2c_read 2 failed"); + } + else + { + /*VNVS:START 13-OCT'09---- Checking the status of Seek/Tune Bit*/ +#ifdef TEST_FM + if(STATUSRSSI_SEEK_TUNE_STATUS(Si4709_dev.registers[STATUSRSSI]) == COMPLETE) + { + debug("Seek/Tune Status is set to 1 by device"); + if(STATUSRSSI_SF_BL_STATUS(Si4709_dev.registers[STATUSRSSI]) == SEEK_SUCCESSFUL) + { + debug("Seek Fail/Band Limit Status is set to 0 by device ---SeekUp Operation Completed"); + valid_station_found = 1; + } + else + debug("Seek Fail/Band Limit Status is set to 1 by device ---SeekUp Operation Not Completed"); + } + else + debug("Seek/Tune Status is set to 0 by device ---SeekUp Operation Not Completed"); + +#endif + /*VNVS:END*/ + + powercfg = Si4709_dev.registers[POWERCFG]; + + POWERCFG_BITSET_SEEK_LOW(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write(POWERCFG)) < 0 ) + { + debug("seek i2c_write 2 failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + else + { + do + { + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("seek i2c_read 3 failed"); + break; + } + }while( STATUSRSSI_SEEK_TUNE_STATUS(Si4709_dev.registers[STATUSRSSI]) != CLEAR ); + + if( ret == 0 && valid_station_found == 1 ) + { + if( (ret = i2c_read( READCHAN )) < 0 ) + { + debug("seek i2c_read 4 failed"); + } + else + { + channel = READCHAN_GET_CHAN(Si4709_dev.registers[READCHAN]); + *frequency = channel_to_freq(channel); + debug("Frequency after seek-up is %d \n",*frequency); + } + } + else + { + debug("Valid station not found \n"); + *frequency = 0; + } + } + } + } + + return ret; +} + +static int tune_freq(u32 frequency) +{ + int ret = 0; + u16 channel = Si4709_dev.registers[CHANNEL]; +#ifdef TEST_FM + u16 read_channel; +#endif + debug("tune_freq called"); + + Si4709_dev.registers[CHANNEL] = freq_to_channel(frequency); +#ifdef TEST_FM + read_channel = Si4709_dev.registers[CHANNEL]; + debug(" Input read_channel =%x",read_channel); +#endif + CHANNEL_BITSET_TUNE_HIGH(&Si4709_dev.registers[CHANNEL]); + CHANNEL_BITSET_RESERVED(&Si4709_dev.registers[CHANNEL]); + + if( (ret = i2c_write(CHANNEL)) < 0 ) + { + debug("tune_freq i2c_write 1 failed"); + Si4709_dev.registers[CHANNEL] = channel; + } + else + { + + Si4709_dev_wait_flag = TUNE_WAITING; + debug("Si4709_dev_wait_flag = TUNE_WAITING"); +#ifdef TEST_FM + if( (ret = i2c_read(READCHAN)) < 0 ) + { + debug("tune_freq i2c_read 1 failed"); + } + else + { + read_channel=READCHAN_GET_CHAN(Si4709_dev.registers[READCHAN]); + debug("curr_channel before tuning = %x",read_channel); + } +#endif + + wait(); + + Si4709_dev_wait_flag = NO_WAIT; + + /*VNVS:START 13-OCT'09---- Checking the status of Seek/Tune Bit*/ +#ifdef TEST_FM + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("tune_freq i2c_read 2 failed"); + + } + else if(STATUSRSSI_SEEK_TUNE_STATUS(Si4709_dev.registers[STATUSRSSI]) == COMPLETE) + debug("Seek/Tune Status is set to 1 by device ---Tuning Operation Completed"); + else + debug("Seek/Tune Status is set to 0 by device ---Tuning Operation Not Completed"); +#endif + /*VNVS:END*/ + + channel = Si4709_dev.registers[CHANNEL]; + + CHANNEL_BITSET_TUNE_LOW(&Si4709_dev.registers[CHANNEL]); + CHANNEL_BITSET_RESERVED(&Si4709_dev.registers[CHANNEL]); + + if( (ret = i2c_write(CHANNEL)) < 0 ) + { + debug("tune_freq i2c_write 2 failed"); + Si4709_dev.registers[CHANNEL] = channel; + } + else + { + do + { + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("tune_freq i2c_read 3 failed"); + break; + } + }while( STATUSRSSI_SEEK_TUNE_STATUS(Si4709_dev.registers[STATUSRSSI]) != CLEAR ); + + } + + /*VNVS:START 13-OCT'09---- Reading the READCHAN register after tuning operation*/ +#ifdef TEST_FM + if( (ret = i2c_read(READCHAN)) < 0 ) + { + debug("tune_freq i2c_read 2 failed"); + } + else + { + read_channel=READCHAN_GET_CHAN(Si4709_dev.registers[READCHAN]); + debug("curr_channel after tuning= %x",read_channel); + } +#endif + /*VNVS:END*/ + } + + return ret; +} + +static void get_cur_chan_freq(u32 *frequency, u16 readchan) +{ + + u16 channel = 0; + debug("get_cur_chan_freq called"); + + channel = READCHAN_GET_CHAN(readchan); + debug("read_channel=%x",channel); + + *frequency = channel_to_freq(channel); + + debug("frequency-> %u",*frequency); +} + +static u16 freq_to_channel(u32 frequency) +{ + u16 channel; + + if( frequency < Si4709_dev.settings.bottom_of_band ) + { + frequency = Si4709_dev.settings.bottom_of_band; + } + + channel = (frequency - Si4709_dev.settings.bottom_of_band) + / Si4709_dev.settings.channel_spacing; + + return channel; +} + +static u32 channel_to_freq(u16 channel) +{ + u32 frequency; + + frequency = Si4709_dev.settings.bottom_of_band + + Si4709_dev.settings.channel_spacing * channel; + + return frequency; +} + +/*Only one thread will be able to call this, since this function call is + protected by a mutex, so no race conditions can arise*/ +static void wait(void) +{ + wait_event_interruptible(Si4709_waitq, + (Si4709_dev_wait_flag == WAIT_OVER) || (Si4709_dev_wait_flag == SEEK_CANCEL)); +} + +static void wait_RDS(void) +{ + wait_event_interruptible_timeout(Si4709_waitq, + (Si4709_dev_wait_flag == WAIT_OVER),Si4709_dev.settings.timeout_RDS); +} + +/*i2c read function*/ +/*Si4709_dev.client should be set before calling this function. + If Si4709_dev.valid = eTRUE then Si4709_dev.client will b valid + This function should be called from the functions in this file. The + callers should check if Si4709_dev.valid = eTRUE before + calling this function. If it is eFALSE then this function should not + be called*/ +static int i2c_read( u8 reg ) +{ + u8 idx, reading_reg = STATUSRSSI; + u8 data[NUM_OF_REGISTERS * 2], data_high, data_low; + int msglen = 0, ret = 0; + + for(idx = 0; idx < NUM_OF_REGISTERS * 2; idx++) + { + data[idx] = 0x00; + } + + msglen = reg - reading_reg + 1; + + if(msglen > 0) + { + msglen = msglen * 2; + } + else + { + msglen = (msglen + NUM_OF_REGISTERS) * 2; + } + + ret = i2c_master_recv((struct i2c_client*)(Si4709_dev.client), data, msglen); + + if(ret == msglen) + { + idx = 0; + do + { + data_high = data[idx]; + data_low = data[idx+1]; + + Si4709_dev.registers[reading_reg] = 0x0000; + Si4709_dev.registers[reading_reg] = (data_high << 8) + data_low; + reading_reg = (reading_reg + 1) & RDSD; + idx = idx + 2; + } while(reading_reg != ((reg +1) & RDSD)); + + ret = 0; + } + else + { + ret = -1; + } + + return ret; +} + +/*i2c write function*/ +/*Si4709_dev.client should be set before calling this function. + If Si4709_dev.valid = eTRUE then Si4709_dev.client will b valid + This function should be called from the functions in this file. The + callers should check if Si4709_dev.valid = eTRUE before + calling this function. If it is eFALSE then this function should not + be called*/ +static int i2c_write( u8 reg ) +{ + u8 writing_reg = POWERCFG; + u8 data[NUM_OF_REGISTERS * 2]; + int i, msglen = 0, ret = 0; + + for(i = 0; i < NUM_OF_REGISTERS * 2; i++) + { + data[i] = 0x00; + } + + do + { + data[msglen++] = (u8)(Si4709_dev.registers[writing_reg] >> 8); + data[msglen++] = (u8)(Si4709_dev.registers[writing_reg] & 0xFF); + + writing_reg = (writing_reg +1) & RDSD; + } while(writing_reg != ((reg + 1) & RDSD)); + + ret = i2c_master_send((struct i2c_client*)(Si4709_dev.client), ( const char *)data, msglen); + + if(ret == msglen) + { + ret = 0; + } + else + { + ret = -1; + } + + return ret; +} + +static int insert_preset(u32 frequency,u8 rssi,u8 *seek_preset_rssi) +{ + u8 i; + u8 min_rssi = 0xff; + u8 min_rssi_preset=0; + int ret = 0; + + /* first find the minimum rssi and its location + this will always stop at the first location with a zero rssi */ + + debug("si4709 autoseek : insert preset\n"); + + for (i=0; i<NUM_SEEK_PRESETS; i++) + { + if (seek_preset_rssi[i] < min_rssi) + { + min_rssi = seek_preset_rssi[i]; + min_rssi_preset = i; + } + } + + if (rssi < min_rssi) + ret = -1; + + /***Delete the preset with the minimum rssi, and clear the last preset + since it would only be a copy of the second to last preset after + the deletion ***/ + for (i=min_rssi_preset; i<NUM_SEEK_PRESETS-1; i++) + { + Si4709_dev.settings.seek_preset[i]= Si4709_dev.settings.seek_preset[i+1]; + seek_preset_rssi[i] = seek_preset_rssi[i+1]; + } + + Si4709_dev.settings.seek_preset[i] = 0; + seek_preset_rssi[i] = 0; + + /*** Fill the first preset with a zero for the frequency. This will + always overwrite the last preset once all presets have been filled. ***/ + for (i=min_rssi_preset; i<NUM_SEEK_PRESETS; i++) + { + if(Si4709_dev.settings.seek_preset[i] == 0) + { + Si4709_dev.settings.seek_preset[i]= frequency; + seek_preset_rssi[i] = rssi; + break; + } + } + return ret; +} + + diff --git a/drivers/media/radio/si4709/radio-si4709_dev.h b/drivers/media/radio/si4709/radio-si4709_dev.h new file mode 100644 index 0000000..bdcde4f --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_dev.h @@ -0,0 +1,181 @@ +#ifndef _Si4709_DEV_H +#define _Si4709_DEV_H + +#include <linux/i2c.h> +#include "radio-si4709_common.h" + +typedef struct +{ + int power_state; + int seek_state; +}dev_state_t; + +typedef struct +{ + u8 curr_rssi; + u8 curr_rssi_th; + u8 curr_snr; +}rssi_snr_t; + +typedef struct +{ + u8 part_number; + u16 manufact_number; +} device_id; + +typedef struct +{ + u8 chip_version; + u8 device; + u8 firmware_version; +}chip_id; + +typedef struct +{ + u16 rssi_th; + u8 fm_band; + u8 fm_chan_spac; + u8 fm_vol; +} sys_config2; + +typedef struct +{ + u8 smmute; + u8 smutea; + u8 volext; + u8 sksnr; + u8 skcnt; +} sys_config3; + +typedef struct +{ + u8 rdsr; + u8 stc; + u8 sfbl; + u8 afcrl; + u8 rdss; + u8 blera; + u8 st; + u16 rssi; +} status_rssi; + +typedef struct +{ + 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; +} power_config; + +typedef struct +{ + u16 rdsa; + u16 rdsb; + u16 rdsc; + u16 rdsd; + u8 curr_rssi; + u32 curr_channel; + u8 blera; + u8 blerb; + u8 blerc; + u8 blerd; +}radio_data_t; + +#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*/ + +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 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_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(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(dev_state_t*); +extern int Si4709_dev_RDS_data_get(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(device_id *); +extern int Si4709_dev_chip_id(chip_id *); +extern int Si4709_dev_sys_config2(sys_config2 *); +extern int Si4709_dev_sys_config3(sys_config3 *); +extern int Si4709_dev_power_config(power_config *); +extern int Si4709_dev_AFCRL_get(u8*); +extern int Si4709_dev_DE_set(u8); +extern int Si4709_dev_status_rssi(status_rssi *status); +extern int Si4709_dev_sys_config2_set(sys_config2 *sys_conf2); +extern int Si4709_dev_sys_config3_set(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/media/radio/si4709/radio-si4709_i2c_drv.c b/drivers/media/radio/si4709/radio-si4709_i2c_drv.c new file mode 100644 index 0000000..5885b04 --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_i2c_drv.c @@ -0,0 +1,196 @@ + +#include <linux/kernel.h> +#include <linux/i2c.h> +#include <linux/slab.h> + +#include "radio-si4709_dev.h" +#include "radio-si4709_common.h" + +/*extern functions*/ +int Si4709_i2c_drv_init(void); +void Si4709_i2c_drv_exit(void); + +/*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*/ +#define SI4709_I2C_ADDRESS 0x20 + +static unsigned short Si4709_normal_i2c[] = { I2C_CLIENT_END }; + +static struct i2c_driver Si4709_i2c_driver; + +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; + debug("Si4709_probe: device not supported"); + } + else if( (ret = Si4709_dev_init(client)) < 0 ) + { + debug("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; + debug("Si4709_remove: device not supported"); + } + else if( (ret = Si4709_dev_exit()) < 0 ) + { + debug("Si4709_dev_exit failed"); + } + + return ret; +} + +static int __devinit 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 __devexit si4709_i2c_remove(struct i2c_client *client) +{ + struct si4709_data *si4709_dev = i2c_get_clientdata(client); + + printk("----- %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, + .address_list = Si4709_normal_i2c, +}; + +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; + debug("Si4709_suspend: device not supported"); + } + else if( (ret = Si4709_dev_suspend()) < 0 ) + { + debug("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; + debug("Si4709_resume: device not supported"); + } + else if( (ret = Si4709_dev_resume()) < 0 ) + { + debug("Si4709_dev_enable failed"); + } + + return 0; +} + +int Si4709_i2c_drv_init(void) +{ + int ret = 0; + + debug("Si4709 i2c driver Si4709_i2c_driver_init called"); + + if ( (ret = i2c_add_driver(&Si4709_i2c_driver) < 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/media/radio/si4709/radio-si4709_i2c_drv.h b/drivers/media/radio/si4709/radio-si4709_i2c_drv.h new file mode 100644 index 0000000..fb705a3 --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_i2c_drv.h @@ -0,0 +1,8 @@ +#ifndef _Si4709_I2C_DRV_H +#define _Si4709_I2C_DRV_H + +extern int Si4709_i2c_drv_init(void); +extern int Si4709_i2c_drv_exit(void); + +#endif + diff --git a/drivers/media/radio/si4709/radio-si4709_ioctl.h b/drivers/media/radio/si4709/radio-si4709_ioctl.h new file mode 100644 index 0000000..5165a99 --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_ioctl.h @@ -0,0 +1,104 @@ +#ifndef _Si4709_IOCTL_H +#define _Si4709_IOCTL_H + +#include <linux/types.h> +#include <linux/ioctl.h> + +#include "radio-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, 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, dev_state_t) + +#define Si4709_IOC_RDS_DATA_GET _IOR(Si4709_IOC_MAGIC, 22, 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,device_id) + +#define Si4709_IOC_CHIP_ID_GET _IOR(Si4709_IOC_MAGIC, 28,chip_id) + +#define Si4709_IOC_SYS_CONFIG2_GET _IOR(Si4709_IOC_MAGIC,29,sys_config2) + +#define Si4709_IOC_POWER_CONFIG_GET _IOR(Si4709_IOC_MAGIC,30,power_config) + +#define Si4709_IOC_AFCRL_GET _IOR(Si4709_IOC_MAGIC,31,u8) /*For reading AFCRL bit, to check for a valid channel*/ + +#define Si4709_IOC_DE_SET _IOW(Si4709_IOC_MAGIC,32,u8) /*Setting DE-emphasis Time Constant. For DE=0,TC=50us(Europe,Japan,Australia) and DE=1,TC=75us(USA)*/ +/*VNVS:END*/ + +#define Si4709_IOC_SYS_CONFIG3_GET _IOR(Si4709_IOC_MAGIC, 33, sys_config3) + +#define Si4709_IOC_STATUS_RSSI_GET _IOR(Si4709_IOC_MAGIC, 34, status_rssi) + +#define Si4709_IOC_SYS_CONFIG2_SET _IOW(Si4709_IOC_MAGIC, 35, sys_config2) + +#define Si4709_IOC_SYS_CONFIG3_SET _IOW(Si4709_IOC_MAGIC, 36, 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) + + +/*****************************************/ + +#endif + diff --git a/drivers/media/radio/si4709/radio-si4709_main.c b/drivers/media/radio/si4709/radio-si4709_main.c new file mode 100644 index 0000000..a202b50 --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_main.c @@ -0,0 +1,799 @@ + +#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 <asm/uaccess.h> +#include <linux/irq.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <linux/wait.h> +#include <linux/stat.h> +#include <linux/ioctl.h> + +#include <plat/gpio-cfg.h> +#include <mach/gpio.h> +#include <../../../arch/arm/mach-s5pv210/include/mach/gpio-aries.h> + +#include "radio-si4709_i2c_drv.h" +#include "radio-si4709_dev.h" +#include "radio-si4709_ioctl.h" +#include "radio-si4709_common.h" + +/*******************************************************/ + +/*Si4709 IRQ Number*/ + +#define FM_IRQ_INT (IRQ_EINT_GROUP20_BASE+4) /* J2_4 */ + +/*static functions*/ + +/*file operatons*/ +static int Si4709_open (struct inode *, struct file *); +static int Si4709_release (struct inode *, struct file *); +static int Si4709_ioctl(struct file *, unsigned int, unsigned long); + +static DEFINE_MUTEX(Si4709_mutex); + +/*ISR*/ +static irqreturn_t Si4709_isr( int irq, void *unused ); +//static void __iomem *gpio_mask_mem; +/**********************************************************/ + +static 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 = "radio0", + .fops = &Si4709_fops, +}; +/*VNVS:START 13-OCT'09----dummy struct which is used as a cookie for FM Radio interrupt */ +typedef struct +{ + int i; + int j; +} radio0; +radio0 radio0_1; +/*VNVS:END*/ + +wait_queue_head_t Si4709_waitq; + +/***************************************************************/ + +static int Si4709_open (struct inode *inode, struct file *filp) +{ + debug("Si4709_open called"); + + return nonseekable_open(inode, filp); +} + +static int Si4709_release (struct inode *inode, struct file *filp) +{ + debug("Si4709_release called"); + + return 0; +} + +static int Si4709_ioctl(struct file *filp, unsigned int ioctl_cmd, unsigned long arg) +{ + int ret = 0; + void __user *argp = (void __user *)arg; + + mutex_lock(&Si4709_mutex); + + if( _IOC_TYPE(ioctl_cmd) != Si4709_IOC_MAGIC ) + { + debug("Inappropriate ioctl 1 0x%x",ioctl_cmd); + ret = -ENOTTY; + goto exit; + } + + if( _IOC_NR(ioctl_cmd) > Si4709_IOC_NR_MAX ) + { + debug("Inappropriate ioctl 2 0x%x",ioctl_cmd); + ret = -ENOTTY; + goto exit; + } + + switch (ioctl_cmd) + { + case Si4709_IOC_POWERUP: + debug("Si4709_IOC_POWERUP called"); + + if( (ret = Si4709_dev_powerup()) < 0 ) + debug("Si4709_IOC_POWERUP failed"); + break; + + case Si4709_IOC_POWERDOWN: + debug("Si4709_IOC_POWERDOWN called"); + + if( (ret = Si4709_dev_powerdown()) < 0 ) + debug("Si4709_IOC_POWERDOWN failed"); + break; + + case Si4709_IOC_BAND_SET: + { + int band; + debug("Si4709_IOC_BAND_SET called"); + + if(copy_from_user((void*) &band, argp, sizeof(int))) + ret = -EFAULT; + else if( (ret = Si4709_dev_band_set(band)) < 0) + debug("Si4709_IOC_BAND_SET failed"); + + } + break; + + case Si4709_IOC_CHAN_SPACING_SET: + { + int ch_spacing; + debug("Si4709_IOC_CHAN_SPACING_SET called"); + + if( copy_from_user((void*) &ch_spacing, argp, sizeof(int)) ) + ret = -EFAULT; + else if ((ret = Si4709_dev_ch_spacing_set(ch_spacing)) < 0) + debug("Si4709_IOC_CHAN_SPACING_SET failed"); + + } + break; + + case Si4709_IOC_CHAN_SELECT: + { + u32 frequency; + debug("Si4709_IOC_CHAN_SELECT called"); + + if( copy_from_user((void*) &frequency, argp, sizeof(u32)) ) + ret = -EFAULT; + else if ( (ret = Si4709_dev_chan_select(frequency)) < 0 ) + debug("Si4709_IOC_CHAN_SELECT failed"); + } + break; + + case Si4709_IOC_CHAN_GET: + { + u32 frequency; + debug("Si4709_IOC_CHAN_GET called"); + + if( (ret = Si4709_dev_chan_get(&frequency)) < 0) + debug("Si4709_IOC_CHAN_GET failed"); + else if( copy_to_user(argp, (void*) &frequency, sizeof(u32))) + ret = -EFAULT; + } + break; + + case Si4709_IOC_SEEK_UP: + { + u32 frequency; + debug("Si4709_IOC_SEEK_UP called"); + + if( (ret = Si4709_dev_seek_up(&frequency)) < 0) + debug("Si4709_IOC_SEEK_UP failed"); + else if( copy_to_user(argp, (void*) &frequency, sizeof(u32)) ) + ret = -EFAULT; + } + break; + + case Si4709_IOC_SEEK_DOWN: + { + u32 frequency; + debug("Si4709_IOC_SEEK_DOWN called"); + + if( (ret = Si4709_dev_seek_down(&frequency)) < 0) + debug("Si4709_IOC_SEEK_DOWN failed"); + else if( copy_to_user(argp, (void*) &frequency, sizeof(u32)) ) + ret = -EFAULT; + } + break; + +#if 0 + case Si4709_IOC_SEEK_AUTO: + { + u32 *seek_preset_user; + int i = 0; + + debug("Si4709_IOC_SEEK_AUTO called"); + + if( (seek_preset_user = (u32 *)kzalloc(sizeof(u32) * NUM_SEEK_PRESETS, + GFP_KERNEL)) == NULL ) + { + debug("Si4709_ioctl: no memory"); + ret = -ENOMEM; + } + else + { + if((ret = Si4709_dev_seek_auto(seek_preset_user)) < 0) + { + debug("Si4709_IOC_SEEK_AUTO failed"); + } + + else if ( copy_to_user(argp, (u32*) seek_preset_user, sizeof(int) * NUM_SEEK_PRESETS) ) + { + ret = -EFAULT; + } + + kfree(seek_preset_user); + } + } + break; +#endif + + case Si4709_IOC_RSSI_SEEK_TH_SET: + { + u8 RSSI_seek_th; + debug("Si4709_IOC_RSSI_SEEK_TH_SET called"); + + if( copy_from_user((void*) &RSSI_seek_th, argp, sizeof(u8)) ) + ret = -EFAULT; + else if ( (ret = Si4709_dev_RSSI_seek_th_set(RSSI_seek_th)) < 0 ) + debug("Si4709_IOC_RSSI_SEEK_TH_SET failed"); + } + break; + + case Si4709_IOC_SEEK_SNR_SET: + { + u8 seek_SNR_th; + debug("Si4709_IOC_SEEK_SNR_SET called"); + + if( copy_from_user((void*) &seek_SNR_th, argp, sizeof(u8)) ) + ret = -EFAULT; + else if( (ret = Si4709_dev_seek_SNR_th_set(seek_SNR_th)) < 0 ) + debug("Si4709_IOC_SEEK_SNR_SET failed"); + } + break; + + case Si4709_IOC_SEEK_CNT_SET: + { + u8 seek_FM_ID_th; + debug("Si4709_IOC_SEEK_CNT_SET called"); + + if( copy_from_user((void*) &seek_FM_ID_th, argp, sizeof(u8)) ) + ret = -EFAULT; + else if ( (ret = Si4709_dev_seek_FM_ID_th_set(seek_FM_ID_th)) < 0 ) + debug("Si4709_IOC_SEEK_CNT_SET failed"); + } + break; + + case Si4709_IOC_CUR_RSSI_GET: + { + rssi_snr_t data; + debug("Si4709_IOC_CUR_RSSI_GET called"); + + if( (ret = Si4709_dev_cur_RSSI_get(&data)) < 0) + debug("Si4709_IOC_CUR_RSSI_GET failed"); + else if( copy_to_user(argp, (void*) &data, sizeof(rssi_snr_t )) ) + 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"); + + if( (ret = Si4709_dev_VOLEXT_ENB()) < 0 ) + debug("Si4709_IOC_VOLEXT_ENB failed"); + break; + + case Si4709_IOC_VOLEXT_DISB: + debug("Si4709_IOC_VOLEXT_DISB called"); + + if( (ret = Si4709_dev_VOLEXT_DISB()) < 0 ) + debug("Si4709_IOC_VOLEXT_DISB failed"); + break; + + case Si4709_IOC_VOLUME_SET: + { + u8 volume; + debug("Si4709_IOC_VOLUME_SET called"); + + if( copy_from_user((void*) &volume, argp, sizeof(u8)) ) + ret = -EFAULT; + else if ( (ret = Si4709_dev_volume_set(volume)) < 0 ) + debug("Si4709_IOC_VOLUME_SET failed"); + } + break; + + case Si4709_IOC_VOLUME_GET: + { + u8 volume; + debug("Si4709_IOC_VOLUME_GET called"); + + if( (ret = Si4709_dev_volume_get(&volume)) < 0) + debug("Si4709_IOC_VOLUME_GET failed"); + else if( copy_to_user(argp, (void*) &volume, sizeof(u8)) ) + ret = -EFAULT; + } + break; + + case Si4709_IOC_DSMUTE_ON: + debug("Si4709_IOC_DSMUTE_ON called"); + + if( (ret = Si4709_dev_DSMUTE_ON()) < 0 ) + error("Si4709_IOC_DSMUTE_ON failed"); + break; + + case Si4709_IOC_DSMUTE_OFF: + debug("Si4709_IOC_DSMUTE_OFF called"); + + if( (ret = Si4709_dev_DSMUTE_OFF()) < 0 ) + error("Si4709_IOC_DSMUTE_OFF failed"); + break; + + case Si4709_IOC_MUTE_ON: + debug("Si4709_IOC_MUTE_ON called"); + + if( (ret = Si4709_dev_MUTE_ON()) < 0 ) + debug("Si4709_IOC_MUTE_ON failed"); + break; + + case Si4709_IOC_MUTE_OFF: + debug("Si4709_IOC_MUTE_OFF called"); + + if( (ret = Si4709_dev_MUTE_OFF()) < 0 ) + debug("Si4709_IOC_MUTE_OFF failed"); + break; + + case Si4709_IOC_MONO_SET: + debug("Si4709_IOC_MONO_SET called"); + + if( (ret = Si4709_dev_MONO_SET()) < 0 ) + debug("Si4709_IOC_MONO_SET failed"); + break; + + case Si4709_IOC_STEREO_SET: + debug("Si4709_IOC_STEREO_SET called"); + + if( (ret = Si4709_dev_STEREO_SET()) < 0 ) + debug("Si4709_IOC_STEREO_SET failed"); + break; + + case Si4709_IOC_RSTATE_GET: + { + dev_state_t dev_state; + + debug("Si4709_IOC_RSTATE_GET called"); + + if( (ret = Si4709_dev_rstate_get(&dev_state)) < 0) + debug("Si4709_IOC_RSTATE_GET failed"); + else if( copy_to_user(argp, (void*) &dev_state, sizeof(dev_state_t)) ) + ret = -EFAULT; + } + break; + + case Si4709_IOC_RDS_DATA_GET: + { + radio_data_t data; + debug("Si4709_IOC_RDS_DATA_GET called"); + + if( (ret = Si4709_dev_RDS_data_get(&data)) < 0) + debug("Si4709_IOC_RDS_DATA_GET failed"); + else if( copy_to_user(argp, (void*) &data, sizeof(radio_data_t)) ) + ret = -EFAULT; + } + break; + + case Si4709_IOC_RDS_ENABLE: + debug("Si4709_IOC_RDS_ENABLE called"); + + if( (ret = Si4709_dev_RDS_ENABLE()) < 0 ) + debug("Si4709_IOC_RDS_ENABLE failed"); + break; + + case Si4709_IOC_RDS_DISABLE: + debug("Si4709_IOC_RDS_DISABLE called"); + + if( (ret = Si4709_dev_RDS_DISABLE()) < 0 ) + debug("Si4709_IOC_RDS_DISABLE failed"); + break; + + case Si4709_IOC_RDS_TIMEOUT_SET: + { + u32 time_out; + debug("Si4709_IOC_RDS_TIMEOUT_SET called"); + + if( copy_from_user((void*) &time_out, argp, sizeof(u32)) ) + ret = -EFAULT; + else if ( (ret = Si4709_dev_RDS_timeout_set(time_out)) < 0 ) + debug("Si4709_IOC_RDS_TIMEOUT_SET failed"); + } + break; + + case Si4709_IOC_SEEK_CANCEL: + debug("Si4709_IOC_SEEK_CANCEL called"); + + 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: + { + chip_id chp_id; + debug("Si4709_IOC_CHIP_ID called"); + + if( (ret = Si4709_dev_chip_id(&chp_id)) < 0) + debug("Si4709_IOC_CHIP_ID failed"); + else if( copy_to_user(argp, (void*) &chp_id, sizeof(chip_id)) ) + ret = -EFAULT; + } + break; + + case Si4709_IOC_DEVICE_ID_GET: + { + device_id dev_id; + debug("Si4709_IOC_DEVICE_ID called"); + + if( (ret = Si4709_dev_device_id(&dev_id)) < 0) + debug("Si4709_IOC_DEVICE_ID failed"); + else if( copy_to_user(argp, (void*) &dev_id, sizeof(device_id)) ) + ret = -EFAULT; + } + break; + + case Si4709_IOC_SYS_CONFIG2_GET: + { + sys_config2 sys_conf2; + debug("Si4709_IOC_SYS_CONFIG2 called"); + + if( (ret = Si4709_dev_sys_config2(&sys_conf2)) < 0) + debug("Si4709_IOC_SYS_CONFIG2 failed"); + else if( copy_to_user(argp, (void*) &sys_conf2, sizeof(sys_config2)) ) + ret = -EFAULT; + } + break; + + case Si4709_IOC_SYS_CONFIG3_GET: + { + sys_config3 sys_conf3; + debug("Si4709_IOC_SYS_CONFIG3 called"); + + if( (ret = Si4709_dev_sys_config3(&sys_conf3)) < 0) + debug("Si4709_IOC_SYS_CONFIG3 failed"); + else if(copy_to_user(argp, (void*) &sys_conf3, sizeof(sys_config3))) + ret = -EFAULT; + } + break; + + case Si4709_IOC_POWER_CONFIG_GET: + { + power_config pow_conf; + debug("Si4709_IOC_POWER_CONFIG called"); + + if( (ret = Si4709_dev_power_config(&pow_conf)) < 0) + debug("Si4709_IOC_POWER_CONFIG failed"); + else if( copy_to_user(argp, (void*) &pow_conf, sizeof(power_config)) ) + 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"); + + if( (ret = Si4709_dev_AFCRL_get(&afc)) < 0) + debug("Si4709_IOC_AFCRL_GET failed"); + 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"); + + if( copy_from_user((void*) &de_tc, argp, sizeof(u8)) ) + ret = -EFAULT; + else if ( (ret = Si4709_dev_DE_set(de_tc)) < 0 ) + debug("Si4709_IOC_DE_SET failed"); + } + break; + + case Si4709_IOC_STATUS_RSSI_GET: + { + status_rssi status; + debug("Si4709_IOC_STATUS_RSSI_GET called"); + + if( (ret = Si4709_dev_status_rssi(&status)) < 0) + debug("Si4709_IOC_STATUS_RSSI_GET failed"); + else if(copy_to_user(argp, (void*) &status, sizeof(status_rssi))) + ret = -EFAULT; + } + break; + + + case Si4709_IOC_SYS_CONFIG2_SET: + { + sys_config2 sys_conf2; + unsigned long n; + debug("Si4709_IOC_SYS_CONFIG2_SET called"); + + n = copy_from_user((void*) &sys_conf2, argp, sizeof(sys_config2)); + + if(n) + { + debug("Si4709_IOC_SYS_CONFIG2_SET() : copy_from_user() has error!!Failed to read [%d] byes!", n); + ret = -EFAULT; + } + else if ( (ret = Si4709_dev_sys_config2_set(&sys_conf2)) < 0 ) + debug("Si4709_IOC_SYS_CONFIG2_SET failed"); + } + break; + + case Si4709_IOC_SYS_CONFIG3_SET: + { + sys_config3 sys_conf3; + unsigned long n; + + debug("Si4709_IOC_SYS_CONFIG3_SET called"); + + n = copy_from_user((void*) &sys_conf3, argp, sizeof(sys_config3)); + + if(n < 0) + { + debug("Si4709_IOC_SYS_CONFIG3_SET() : copy_from_user() has error!!Failed to read [%d] byes!", n); + ret = -EFAULT; + }else if ( (ret = Si4709_dev_sys_config3_set(&sys_conf3)) < 0 ) + debug("Si4709_IOC_SYS_CONFIG3_SET failed"); + } + break; + /*Resetting the RDS Data Buffer*/ + case Si4709_IOC_RESET_RDS_DATA: + { + debug("Si4709_IOC_RESET_RDS_DATA called"); + + if( (ret = Si4709_dev_reset_rds_data()) < 0) + error("Si4709_IOC_RESET_RDS_DATA failed"); + } + break; + + /*VNVS:END*/ + default: + debug(" ioctl default"); + ret = -ENOTTY; + break; + } + +exit: + mutex_unlock(&Si4709_mutex); + 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",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; +} + +#if 0 +int Si4709_dev_abort_seek(void) +{ + int ret = 0; + + if( Si4709_dev_wait_flag = SEEK_WAITING ) + { + wake_up_interruptible(&Si4709_waitq); + } + return ret; +} +#endif + + +/************************************************************/ + + +void debug_ioctls(void) +{ + + debug("------------------------------------------------"); + + 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("------------------------------------------------"); + +} + + + + + int __init Si4709_driver_init(void) +{ + int ret = 0; + + + debug("Si4709_driver_init called"); + + /*Initialize the Si4709 dev mutex*/ + Si4709_dev_mutex_init(); + + + /*misc device registration*/ + if( (ret = misc_register(&Si4709_misc_device)) < 0 ) + { + error("Si4709_driver_init misc_register failed"); + return ret; + } + + s3c_gpio_cfgpin(GPIO_FM_INT, S3C_GPIO_SFN(0xF)); + s3c_gpio_setpull(GPIO_FM_INT, S3C_GPIO_PULL_NONE); + + irq_set_irq_type(FM_IRQ_INT, IRQ_TYPE_EDGE_FALLING); + + /*KGVS: Configuring the GPIO_FM_INT in mach-jupiter.c*/ + if( (ret = request_irq(FM_IRQ_INT, Si4709_isr, IRQF_DISABLED , "Si4709", NULL )) ) + { + error("Si4709_driver_init request_irq failed %d", GPIO_FM_INT); + goto MISC_DREG; + } + else + debug("Si4709_driver_init request_irq success %d", GPIO_FM_INT); + + if (gpio_is_valid(FM_RESET)) { + if (gpio_request(FM_RESET, "GPJ2")) + printk(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(GPIO_FM_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*/ + if ( (ret = Si4709_i2c_drv_init() < 0) ) + { + goto MISC_IRQ_DREG; + } + + init_waitqueue_head(&Si4709_waitq); + + debug("Si4709_driver_init successful"); + + return ret; + +MISC_IRQ_DREG: + free_irq(FM_IRQ_INT, NULL); +MISC_DREG: + misc_deregister(&Si4709_misc_device); + + return ret; +} + + +void __exit Si4709_driver_exit(void) +{ + debug("Si4709_driver_exit called"); + + /*Delete the i2c driver*/ + Si4709_i2c_drv_exit(); + free_irq(FM_IRQ_INT, 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/media/radio/si4709/radio-si4709_main.h b/drivers/media/radio/si4709/radio-si4709_main.h new file mode 100644 index 0000000..adf98e1 --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_main.h @@ -0,0 +1,9 @@ +#ifndef _Si4709_MAIN_H +#define _Si4709_MAIN_H + +#include <linux/wait.h> + +extern wait_queue_head_t Si4709_waitq; + +#endif + diff --git a/drivers/media/radio/si4709/radio-si4709_regs.h b/drivers/media/radio/si4709/radio-si4709_regs.h new file mode 100644 index 0000000..599d009 --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_regs.h @@ -0,0 +1,859 @@ +#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) //vnv.srikanth +{ + data = data>>12; + return((u8)(0x000F & data)); +} + +static inline u16 DEVICE_ID_MANUFACT_NUMBER(u16 data) //vnv.srikanth +{ + return((u16)(0x0FFF & data)); +} + +static inline u8 CHIP_ID_CHIP_VERSION(u16 data) //vnv.srikanth +{ + data = data>>10; + return((u8)(0x003F & data)); +} + +static inline u8 CHIP_ID_DEVICE(u16 data) //vnv.srikanth +{ + data = data>>6; + return((u8)(0x000F & data)); +} + +static inline u8 CHIP_ID_FIRMWARE_VERSION(u16 data) //vnv.srikanth +{ + return((u8)(0x003F & data)); +} + +static inline u8 SYS_CONFIG2_RSSI_TH(u16 data) //vnv.srikanth +{ + data=data>>8; + return((u8)(0x00FF&data)); +} + +static inline u8 SYS_CONFIG2_FM_BAND(u16 data) //vnv.srikanth +{ + data=data>>6; + return((u8)(0x0003&data)); +} + +static inline u8 SYS_CONFIG2_FM_CHAN_SPAC(u16 data) //vnv.srikanth +{ + data=data>>4; + return((u8)(0x0003&data)); +} + +static inline u8 SYS_CONFIG2_FM_VOL(u16 data) //vnv.srikanth +{ + return((u8)(0x000F&data)); +} + +//POWER_CONFIG_STATUS + //vnv.srikanth-start +#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; + } +} //vnv.srikanth-end +/********************************************************************/ + +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 + |