diff options
Diffstat (limited to 'drivers/samsung')
-rw-r--r-- | drivers/samsung/Kconfig | 9 | ||||
-rw-r--r-- | drivers/samsung/Makefile | 4 | ||||
-rw-r--r-- | drivers/samsung/fm_si4709/Si4705_dev.c | 2064 | ||||
-rw-r--r-- | drivers/samsung/fm_si4709/Si4705_main.c | 24 | ||||
-rw-r--r-- | drivers/samsung/fm_si4709/Si4709_dev.c | 35 | ||||
-rw-r--r-- | drivers/samsung/fm_si4709/Si4709_dev.h | 3 | ||||
-rw-r--r-- | drivers/samsung/fm_si4709/Si4709_main.c | 14 | ||||
-rw-r--r-- | drivers/samsung/fm_si47xx/Makefile | 7 | ||||
-rw-r--r-- | drivers/samsung/fm_si47xx/Si47xx_dev.c | 1791 | ||||
-rw-r--r-- | drivers/samsung/fm_si47xx/Si47xx_dev.h | 246 | ||||
-rw-r--r-- | drivers/samsung/fm_si47xx/Si47xx_i2c_drv.c | 768 | ||||
-rw-r--r-- | drivers/samsung/fm_si47xx/Si47xx_ioctl.h | 129 | ||||
-rw-r--r-- | drivers/samsung/fm_si47xx/commanddefs.h | 199 | ||||
-rw-r--r-- | drivers/samsung/fm_si47xx/propertydefs.h | 585 |
14 files changed, 3790 insertions, 2088 deletions
diff --git a/drivers/samsung/Kconfig b/drivers/samsung/Kconfig index ab0026b..2d70864 100644 --- a/drivers/samsung/Kconfig +++ b/drivers/samsung/Kconfig @@ -1,17 +1,8 @@ # # # - -menuconfig SAMSUNG_MODULES - tristate "Samsung Kernel Modules" - default n - help - Say Y to enable Samsung kernel modules. j4fs and param - modules are included. - menuconfig FM_RADIO tristate "FM Radio Driver" - depends on SAMSUNG_MODULES default n help Say Y to enable FM Radio Driver diff --git a/drivers/samsung/Makefile b/drivers/samsung/Makefile index 811c209..68916b7 100644 --- a/drivers/samsung/Makefile +++ b/drivers/samsung/Makefile @@ -3,5 +3,5 @@ # # Object files in subdirectories - -obj-$(CONFIG_FM_RADIO) += fm_si4709/ +obj-$(CONFIG_FM_SI4705) += fm_si47xx/ +obj-$(CONFIG_FM_SI4709) += fm_si4709/ diff --git a/drivers/samsung/fm_si4709/Si4705_dev.c b/drivers/samsung/fm_si4709/Si4705_dev.c deleted file mode 100644 index 0898882..0000000 --- a/drivers/samsung/fm_si4709/Si4705_dev.c +++ /dev/null @@ -1,2064 +0,0 @@ -#include <linux/kernel.h> -#include <linux/i2c.h> -#include <linux/mutex.h> -#include <linux/delay.h> -#include <linux/time.h> -#include <linux/workqueue.h> -#include <linux/interrupt.h> - -#include <mach/gpio.h> -#include <plat/gpio-cfg.h> - -#include "Si4709_regs.h" -#include "Si4709_main.h" -#include "Si4709_dev.h" -#include "Si4709_common.h" - -#if 1 /* To do */ -#include "commanddefs.h" -#include "propertydefs.h" -#endif - - -enum { - eTRUE, - eFALSE, -} dev_struct_status_t; - -/*dev_state*/ -/*power_state*/ -#define RADIO_ON 1 -#define RADIO_POWERDOWN 0 -/*seek_state*/ -#define RADIO_SEEK_ON 1 -#define RADIO_SEEK_OFF 0 - -#define FREQ_87500_kHz 8750 -#define FREQ_76000_kHz 7600 - -#define RSSI_seek_th_MAX 0x7F -#define RSSI_seek_th_MIN 0x00 - -#define seek_SNR_th_DISB 0x00 -#define seek_SNR_th_MIN 0x01 /*most stops */ -#define seek_SNR_th_MAX 0x0F /*fewest stops */ - -#define seek_FM_ID_th_DISB 0x00 -#define seek_FM_ID_th_MAX 0x01 /*most stops */ -#define seek_FM_ID_th_MIN 0x0F /*fewest stops */ - -#define TUNE_RSSI_THRESHOLD 10 -#define TUNE_SNR_THRESHOLD 4 -#define TUNE_CNT_THRESHOLD 0x00 - -#define _ENABLE_RDS_ - -#ifdef RDS_INTERRUPT_ON_ALWAYS -#define RDS_BUFFER_LENGTH 50 -static u16 *RDS_Block_Data_buffer; -static u8 *RDS_Block_Error_buffer; -static u8 RDS_Buffer_Index_read; /* index number for last read data */ -static u8 RDS_Buffer_Index_write; /* index number for last written data */ - -int Si4709_RDS_flag; -int RDS_Data_Available; -int RDS_Data_Lost; -int RDS_Groups_Available_till_now; -struct workqueue_struct *Si4709_wq; -struct work_struct Si4709_work; -#endif - -u8 cmd[8]; -u8 rsp[13]; -u8 RsqInts; -u8 Status; -u8 SMUTE; -u8 AFCRL; -u8 Valid; -u8 Pilot; -u8 Blend; -u16 Freq; -u8 RSSI; -u8 ASNR; -u8 FreqOff; -u8 STC; -u8 BLTF; -u16 AntCap; -u8 RdsInts; -u8 RdsSync; -u8 GrpLost; -u8 RdsFifoUsed; -u16 BlockA; -u16 BlockB; -u16 BlockC; -u16 BlockD; -u8 BleA; -u8 BleB; -u8 BleC; -u8 BleD; - - - -/*static functions*/ -/**********************************************/ -static void wait(void); - -#ifndef RDS_INTERRUPT_ON_ALWAYS -static void wait_RDS(void); -#endif - -static int powerup(void); -static int powerdown(void); - -static int seek(u32 *, int, int); -static int tune_freq(u32); -static u16 freq_to_channel(u32); -static void fmTuneStatus(u8 cancel, u8 intack); -static void fmRsqStatus(u8 intack); -static void si47xx_set_property(u16 propNumber, u16 propValue); -static int si47xx_command(u8 cmd_size, u8 *cmd, u8 reply_size, u8 *reply); -static void fmRdsStatus(u8 intack, u8 mtfifo); -static void fmTuneFreq(u16 frequency); -static void fmSeekStart(u8 seekUp, u8 wrap); -static u8 si47xx_readStatus(void); -static void si47xx_waitForCTS(void); -static u8 getIntStatus(void); -static int i2c_write(u8 number_bytes, u8 *data_out); -static int i2c_read(u8 number_bytes, u8 *data_in); -/**********************************************/ - -/*Si4709 device structure*/ -static struct Si4709_device_t Si4709_dev = { - .client = NULL, - .valid = eFALSE, - .valid_client_state = eFALSE, -}; - -/*Wait flag*/ -/*WAITING or WAIT_OVER or NO_WAIT*/ -int Si4709_dev_wait_flag = NO_WAIT; -#ifdef RDS_INTERRUPT_ON_ALWAYS -int Si4709_RDS_flag = NO_WAIT; -#endif - -unsigned int Si4709_dev_int; -unsigned int Si4709_dev_irq; - -#if defined(CONFIG_MACH_M0) -unsigned int Si4709_dev_sw; -#endif - -#if defined(CONFIG_MACH_M0_CTC) -static const u16 rx_vol[] = { -0x0, 0x15, 0x18, 0x1B, 0x1E, 0x21, 0x24, 0x27, -0x2A, 0x2D, 0x30, 0x33, 0x36, 0x39, 0x3C, 0x3F}; -#else -static const u16 rx_vol[] = { -0x0, 0x13, 0x16, 0x19, 0x1C, 0x1F, 0x22, 0x25, -0x28, 0x2B, 0x2E, 0x31, 0x34, 0x37, 0x3A, 0x3D}; -#endif - - -int Si4709_dev_init(struct i2c_client *client) -{ - int ret = 0; - - debug("Si4709_dev_init called"); - - mutex_lock(&(Si4709_dev.lock)); - - Si4709_dev.client = client; - -#if defined(CONFIG_MACH_M0) - if (system_rev >= 15) - Si4709_dev_int = GPIO_FM_INT_REV15; - else -#endif - Si4709_dev_int = GPIO_FM_INT; - - Si4709_dev_irq = gpio_to_irq(Si4709_dev_int); - -#if defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_M0_CTC) - Si4709_dev_sw = GPIO_FM_MIC_SW; -#endif - - disable_irq(Si4709_dev_irq); - - Si4709_dev.state.power_state = RADIO_POWERDOWN; - Si4709_dev.state.seek_state = RADIO_SEEK_OFF; - Si4709_dev.valid_client_state = eTRUE; - -#ifdef RDS_INTERRUPT_ON_ALWAYS - /*Creating Circular Buffer */ - /*Single RDS_Block_Data buffer size is 4x16 bits */ - RDS_Block_Data_buffer = kzalloc(RDS_BUFFER_LENGTH * 8, GFP_KERNEL); - if (!RDS_Block_Data_buffer) { - error("Not sufficient memory for creating " - "RDS_Block_Data_buffer"); - ret = -ENOMEM; - goto EXIT; - } - - /*Single RDS_Block_Error buffer size is 4x8 bits */ - RDS_Block_Error_buffer = kzalloc(RDS_BUFFER_LENGTH * 4, GFP_KERNEL); - if (!RDS_Block_Error_buffer) { - error("Not sufficient memory for creating " - "RDS_Block_Error_buffer"); - ret = -ENOMEM; - kfree(RDS_Block_Data_buffer); - goto EXIT; - } - - /*Initialising read and write indices */ - RDS_Buffer_Index_read = 0; - RDS_Buffer_Index_write = 0; - - /*Creating work-queue */ - Si4709_wq = create_singlethread_workqueue("Si4709_wq"); - if (!Si4709_wq) { - error("Not sufficient memory for Si4709_wq, work-queue"); - ret = -ENOMEM; - kfree(RDS_Block_Error_buffer); - kfree(RDS_Block_Data_buffer); - goto EXIT; - } - - /*Initialising work_queue */ - INIT_WORK(&Si4709_work, Si4709_work_func); - - RDS_Data_Available = 0; - RDS_Data_Lost = 0; - RDS_Groups_Available_till_now = 0; -EXIT: -#endif - - mutex_unlock(&(Si4709_dev.lock)); - - debug("Si4709_dev_init call over"); - - return ret; -} - -int Si4709_dev_exit(void) -{ - int ret = 0; - - debug("Si4709_dev_exit called"); - - mutex_lock(&(Si4709_dev.lock)); - - /* Temporary blocked by abnormal function call(E-CIM 2657654) */ - /* DW Shim. 2010.03.04 */ - /* Si4709_dev.client = NULL; */ - - /* Si4709_dev.valid_client_state = eFALSE; */ - /* Si4709_dev.valid = eFALSE; */ - -#ifdef RDS_INTERRUPT_ON_ALWAYS - if (Si4709_wq) - destroy_workqueue(Si4709_wq); - - kfree(RDS_Block_Error_buffer); - kfree(RDS_Block_Data_buffer); -#endif - - mutex_unlock(&(Si4709_dev.lock)); - - debug("Si4709_dev_exit call over"); - - return ret; -} - -void Si4709_dev_mutex_init(void) -{ - mutex_init(&(Si4709_dev.lock)); -} - -int Si4709_dev_powerup(void) -{ - int ret = 0; - u32 value = 100; - - debug("Si4709_dev_powerup called"); - - if (!(RADIO_ON == Si4709_dev.state.power_state)) { - ret = powerup(); - if (ret < 0) { - debug("powerup failed"); - } else if (Si4709_dev.valid_client_state == eFALSE) { - debug("Si4709_dev_powerup called " - "when DS(state, client) is invalid"); - ret = -1; - } else { -/* initial settings */ -#ifdef _ENABLE_RDS_ - si47xx_set_property(FM_RDS_CONFIG, 1); - si47xx_set_property(GPO_IEN, GPO_IEN_STCIEN_MASK | - GPO_IEN_STCREP_MASK); - si47xx_set_property(GPO_IEN, GPO_IEN_STCIEN_MASK | - GPO_IEN_RDSIEN_MASK | GPO_IEN_STCREP_MASK); - si47xx_set_property(FM_RDS_INTERRUPT_SOURCE, - FM_RDS_INTERRUPT_SOURCE_RECV_MASK); - si47xx_set_property(FM_RDS_CONFIG, - FM_RDS_CONFIG_RDSEN_MASK | - (3 << FM_RDS_CONFIG_BLETHA_SHFT) | - (3 << FM_RDS_CONFIG_BLETHB_SHFT) | - (3 << FM_RDS_CONFIG_BLETHC_SHFT) | - (3 << FM_RDS_CONFIG_BLETHD_SHFT)); -#endif -/*VNVS:18-NOV'09 : Setting DE-Time Constant as 50us(Europe,Japan,Australia)*/ - si47xx_set_property(FM_DEEMPHASIS, FM_DEEMPH_50US); - /* SYSCONFIG2_BITSET_SEEKTH( */ - /* &Si4709_dev.registers[SYSCONFIG2],2); */ -/*VNVS:18-NOV'09 : modified for detecting more stations of good quality*/ - si47xx_set_property(FM_SEEK_TUNE_RSSI_THRESHOLD, - TUNE_RSSI_THRESHOLD); - si47xx_set_property(FM_SEEK_BAND_BOTTOM, 8750); - si47xx_set_property(FM_SEEK_BAND_TOP, 10800); - Si4709_dev.settings.band = BAND_87500_108000_kHz; - Si4709_dev.settings.bottom_of_band = FREQ_87500_kHz; - si47xx_set_property(FM_SEEK_FREQ_SPACING, - CHAN_SPACING_100_kHz); - Si4709_dev.settings.channel_spacing = - CHAN_SPACING_100_kHz; - - /* SYSCONFIG3_BITSET_SKSNR( */ - /* &Si4709_dev.registers[SYSCONFIG3],3); */ -/*VNVS:18-NOV'09 : modified for detecting more stations of good quality*/ - si47xx_set_property(FM_SEEK_TUNE_SNR_THRESHOLD, - TUNE_SNR_THRESHOLD); - Si4709_dev.settings.timeout_RDS = - msecs_to_jiffies(value); - Si4709_dev.settings.curr_snr = TUNE_SNR_THRESHOLD; - Si4709_dev.settings.curr_rssi_th = TUNE_RSSI_THRESHOLD; - Si4709_dev_STEREO_SET(); - -/*this will write all the above registers */ - if (ret < 0) - debug("Si4709_dev_powerup i2c_write 1 failed"); - else { - Si4709_dev.valid = eTRUE; -#ifdef RDS_INTERRUPT_ON_ALWAYS -/*Initialising read and write indices */ - RDS_Buffer_Index_read = 0; - RDS_Buffer_Index_write = 0; - - RDS_Data_Available = 0; - RDS_Data_Lost = 0; - RDS_Groups_Available_till_now = 0; -#endif - } - } - } else - debug("Device already Powered-ON"); - enable_irq(Si4709_dev_irq); - si47xx_set_property(0xff00, 0); - - return ret; -} - -int Si4709_dev_powerdown(void) -{ - int ret = 0; - - msleep(500); /* For avoiding turned off pop noise */ - debug("Si4709_dev_powerdown called"); - - mutex_lock(&(Si4709_dev.lock)); - - disable_irq(Si4709_dev_irq); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_powerdown called when DS is invalid"); - ret = -1; - } else { - ret = powerdown(); - if (ret < 0) - debug("powerdown failed"); - } - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_suspend(void) -{ - int ret = 0; - - debug("Si4709_dev_suspend called"); - -#ifndef _ENABLE_RDS_ - disable_irq(Si4709_dev_irq); -#endif - - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid_client_state == eFALSE) { - debug("Si4709_dev_suspend called " - "when DS(state, client) is invalid"); - ret = -1; - } - mutex_unlock(&(Si4709_dev.lock)); - - debug("Si4709_dev_enable call over"); - - return ret; -} - -int Si4709_dev_resume(void) -{ - int ret = 0; - - debug("Si4709_dev_resume called"); - -#ifndef _ENABLE_RDS_ - enable_irq(Si4709_dev_irq); -#endif - - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid_client_state == eFALSE) { - debug("Si4709_dev_resume called " - "when DS(state, client) is invalid"); - ret = -1; - } - - mutex_unlock(&(Si4709_dev.lock)); - debug("Si4709_dev_disable call over"); - - return ret; -} - -int Si4709_dev_band_set(int band) -{ - int ret = 0; - u16 prev_band = 0; - u32 prev_bottom_of_band = 0; - - debug("Si4709_dev_band_set called"); - - prev_band = Si4709_dev.settings.band; - prev_bottom_of_band = Si4709_dev.settings.bottom_of_band; - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_band_set called when DS is invalid"); - ret = -1; - } else { - switch (band) { - case BAND_87500_108000_kHz: - si47xx_set_property(FM_SEEK_BAND_BOTTOM, 8750); - si47xx_set_property(FM_SEEK_BAND_TOP, 10800); - Si4709_dev.settings.band = BAND_87500_108000_kHz; - Si4709_dev.settings.bottom_of_band = FREQ_87500_kHz; - break; - case BAND_76000_108000_kHz: - si47xx_set_property(FM_SEEK_BAND_BOTTOM, 7600); - si47xx_set_property(FM_SEEK_BAND_TOP, 10800); - Si4709_dev.settings.band = BAND_76000_108000_kHz; - Si4709_dev.settings.bottom_of_band = FREQ_76000_kHz; - break; - case BAND_76000_90000_kHz: - si47xx_set_property(FM_SEEK_BAND_BOTTOM, 7600); - si47xx_set_property(FM_SEEK_BAND_TOP, 9000); - Si4709_dev.settings.band = BAND_76000_90000_kHz; - Si4709_dev.settings.bottom_of_band = FREQ_76000_kHz; - break; - default: - ret = -1; - } - } - - return ret; -} - -int Si4709_dev_ch_spacing_set(int ch_spacing) -{ - int ret = 0; - u16 prev_ch_spacing = 0; - - debug("Si4709_dev_ch_spacing_set called"); - - mutex_lock(&(Si4709_dev.lock)); - prev_ch_spacing = Si4709_dev.settings.channel_spacing; - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_ch_spacing_set called " - "when DS is invalid"); - ret = -1; - } else { - switch (ch_spacing) { - case CHAN_SPACING_200_kHz: - si47xx_set_property(FM_SEEK_FREQ_SPACING, 20); - Si4709_dev.settings.channel_spacing = - CHAN_SPACING_200_kHz; - break; - - case CHAN_SPACING_100_kHz: - si47xx_set_property(FM_SEEK_FREQ_SPACING, 10); - Si4709_dev.settings.channel_spacing = - CHAN_SPACING_100_kHz; - break; - - case CHAN_SPACING_50_kHz: - si47xx_set_property(FM_SEEK_FREQ_SPACING, 5); - Si4709_dev.settings.channel_spacing = - CHAN_SPACING_50_kHz; - break; - - default: - ret = -1; - } - - if (ret == 0) { - if (ret < 0) { - debug("Si4709_dev_ch_spacing_set " - "i2c_write 1 failed"); - Si4709_dev.settings.channel_spacing = - prev_ch_spacing; - } - } - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_chan_select(u32 frequency) -{ - int ret = 0; - - debug("Si4709_dev_chan_select called"); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_chan_select called when DS is invalid"); - ret = -1; - } else { - Si4709_dev.state.seek_state = RADIO_SEEK_ON; - - ret = tune_freq(frequency); - debug("Si4709_dev_chan_select called1"); - Si4709_dev.state.seek_state = RADIO_SEEK_OFF; - } - return ret; -} - -int Si4709_dev_chan_get(u32 *frequency) -{ - int ret = 0; - - debug("Si4709_dev_chan_get called"); - - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_chan_get called when DS is invalid"); - ret = -1; - } else { - if (ret < 0) - debug("Si4709_dev_chan_get i2c_read failed"); - else { - fmTuneStatus(0, 0); - *frequency = Freq; - } - } - mutex_unlock(&(Si4709_dev.lock)); - return ret; -} - -int Si4709_dev_seek_full(u32 *frequency) -{ - int ret = 0; - - debug("Si4709_dev_seek_full called\n"); - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_seek_full called when DS is invalid"); - ret = -1; - } else { - Si4709_dev.state.seek_state = RADIO_SEEK_ON; - ret = seek(frequency, 1, 0); - Si4709_dev.state.seek_state = RADIO_SEEK_OFF; - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_seek_up(u32 *frequency) -{ - int ret = 0; - - debug("Si4709_dev_seek_up called\n"); - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_seek_up called when DS is invalid"); - ret = -1; - } else { - Si4709_dev.state.seek_state = RADIO_SEEK_ON; - ret = seek(frequency, 1, 1); - Si4709_dev.state.seek_state = RADIO_SEEK_OFF; - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_seek_down(u32 *frequency) -{ - int ret = 0; - - debug("Si4709_dev_seek_down called\n"); - - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_seek_down called when DS is invalid"); - ret = -1; - } else { - Si4709_dev.state.seek_state = RADIO_SEEK_ON; - - ret = seek(frequency, 0, 1); - - Si4709_dev.state.seek_state = RADIO_SEEK_OFF; - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_RSSI_seek_th_set(u8 seek_th) -{ - int ret = 0; - - debug("Si4709_dev_RSSI_seek_th_set called"); - - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_RSSI_seek_th_set called " - "when DS is invalid"); - ret = -1; - } else { - si47xx_set_property(FM_SEEK_TUNE_RSSI_THRESHOLD, seek_th); - Si4709_dev.settings.curr_rssi_th = seek_th; - if (ret < 0) - debug("Si4709_dev_RSSI_seek_th_set i2c_write 1 failed"); - } - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_seek_SNR_th_set(u8 seek_SNR) -{ - int ret = 0; - - debug("Si4709_dev_seek_SNR_th_set called"); - - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_seek_SNR_th_set called " - "when DS is invalid"); - ret = -1; - } else { - si47xx_set_property(FM_SEEK_TUNE_SNR_THRESHOLD, seek_SNR); - Si4709_dev.settings.curr_snr = seek_SNR; - - if (ret < 0) - debug("Si4709_dev_seek_SNR_th_set i2c_write 1 failed"); - } - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_seek_FM_ID_th_set(u8 seek_FM_ID_th) -{ - int ret = 0; - - debug("Si4709_dev_seek_FM_ID_th_set called"); - - return ret; -} - -int Si4709_dev_cur_RSSI_get(struct rssi_snr_t *cur_RSSI) -{ - int ret = 0; - - debug("Si4709_dev_cur_RSSI_get called"); - - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_cur_RSSI_get called when DS is invalid"); - ret = -1; - } else { - fmRsqStatus(0); - if (ret < 0) { - debug("Si4709_dev_cur_RSSI_get i2c_read 1 failed"); - } else { - cur_RSSI->curr_rssi = RSSI; - cur_RSSI->curr_rssi_th = - Si4709_dev.settings.curr_rssi_th; - cur_RSSI->curr_snr = Si4709_dev.settings.curr_snr; - } - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -/* VNVS:START 13-OCT'09 : - Functions which reads device-id,chip-id,power configuration, - system configuration2 registers - */ -int Si4709_dev_device_id(struct device_id *dev_id) -{ - int ret = 0; - - debug("Si4709_dev_device_id called"); -#if 0 /*To Do*/ - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_device_id called when DS is invalid"); - ret = -1; - } else { - ret = i2c_read(DEVICE_ID); - if (ret < 0) { - debug("Si4709_dev_device_id i2c_read failed"); - } else { - dev_id->part_number = - DEVICE_ID_PART_NUMBER(Si4709_dev. - registers[DEVICE_ID]); - dev_id->manufact_number = - DEVICE_ID_MANUFACT_NUMBER(Si4709_dev. - registers[DEVICE_ID]); - } - } - - mutex_unlock(&(Si4709_dev.lock)); -#endif - return ret; -} - -int Si4709_dev_chip_id(struct chip_id *chp_id) -{ - int ret = 0; - - debug("Si4709_dev_chip_id called"); -#if 0 /*To Do*/ - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_chip_id called when DS is invalid"); - ret = -1; - } else { - ret = i2c_read(CHIP_ID); - if (ret < 0) { - debug("Si4709_dev_chip_id i2c_read failed"); - } else { - chp_id->chip_version = - CHIP_ID_CHIP_VERSION( - Si4709_dev.registers[CHIP_ID]); - chp_id->device = - CHIP_ID_DEVICE(Si4709_dev.registers[CHIP_ID]); - chp_id->firmware_version = - CHIP_ID_FIRMWARE_VERSION(Si4709_dev. - registers[CHIP_ID]); - } - } - - mutex_unlock(&(Si4709_dev.lock)); -#endif - return ret; -} - -int Si4709_dev_sys_config2(struct sys_config2 *sys_conf2) -{ - int ret = 0; - - debug("Si4709_sys_config2 called\n"); - - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_sys_config2 called when DS is invalid"); - ret = -1; - } else { - if (ret < 0) { - debug("Si4709_sys_config2 i2c_read failed"); - } else { - sys_conf2->rssi_th = Si4709_dev.settings.curr_rssi_th; - sys_conf2->fm_band = Si4709_dev.settings.band; - sys_conf2->fm_chan_spac = - Si4709_dev.settings.channel_spacing; - sys_conf2->fm_vol = 0; - } - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_sys_config3(struct sys_config3 *sys_conf3) -{ - int ret = 0; - - debug("Si4709_sys_config3 called\n"); - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_sys_config3 called when DS is invalid"); - mutex_unlock(&(Si4709_dev.lock)); - return -1; - } - if (ret < 0) { - debug("Si4709_sys_config3 i2c_read failed"); - } else { - sys_conf3->smmute = 0; - sys_conf3->smutea = 0; - sys_conf3->volext = 0; - sys_conf3->sksnr = Si4709_dev.settings.curr_snr; - sys_conf3->skcnt = 0; - } - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_status_rssi(struct status_rssi *status) -{ - int ret = 0; - - debug("Si4709_dev_status_rssi called"); - - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_status_rssi called when DS is invalid"); - mutex_unlock(&(Si4709_dev.lock)); - return -1; - } - fmRsqStatus(0); - if (ret < 0) { - debug("Si4709_sys_config3 i2c_read failed"); - } else { - debug("Si4709_dev_status_rssi %d\n", RSSI); - status->rssi = RSSI; - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_sys_config2_set(struct sys_config2 *sys_conf2) -{ - int ret = 0; - u16 register_bak = 0; - - debug("Si4709_dev_sys_config2_set called"); - - mutex_lock(&(Si4709_dev.lock)); - - register_bak = Si4709_dev.registers[SYSCONFIG2]; - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_sys_config2_set called when DS is invalid"); - ret = -1; - } else { - si47xx_set_property(FM_SEEK_TUNE_RSSI_THRESHOLD, - sys_conf2->rssi_th); - Si4709_dev_band_set(sys_conf2->fm_band); - si47xx_set_property(FM_SEEK_FREQ_SPACING, - sys_conf2->fm_chan_spac); - Si4709_dev.settings.curr_rssi_th = sys_conf2->rssi_th; - Si4709_dev.settings.band = sys_conf2->fm_band; - Si4709_dev.settings.channel_spacing = sys_conf2->fm_chan_spac; - - if (ret < 0) { - debug("Si4709_dev_sys_config2_set i2c_write 1 failed"); - } else - debug(KERN_ERR "Si4709_dev_sys_config2_set() " - ": Write Sucess!!"); - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_sys_config3_set(struct sys_config3 *sys_conf3) -{ - int ret = 0; - u16 register_bak = 0; - - debug("Si4709_dev_sys_config3_set called"); - - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_sys_config3_set called " - "when DS is invalid"); - ret = -1; - } else { - si47xx_set_property(FM_SEEK_TUNE_SNR_THRESHOLD, - sys_conf3->sksnr); - Si4709_dev.settings.curr_snr = sys_conf3->sksnr; - if (ret < 0) { - debug("Si4709_dev_sys_config3_set i2c_write 1 failed"); - Si4709_dev.registers[SYSCONFIG3] = register_bak; - } - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_power_config(struct power_config *pow_conf) -{ - int ret = 0; - - debug("Si4709_dev_power_config called"); - - return ret; -} - -/* VNVS:END */ - -/* VNVS:START 18-NOV'09 */ -/* Reading AFCRL Bit */ -int Si4709_dev_AFCRL_get(u8 *afc) -{ - int ret = 0; - - debug("Si4709_dev_AFCRL_get called"); - - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_AFCRL_get called when DS is invalid"); - ret = -1; - } else { - fmRsqStatus(0); - if (ret < 0) - debug("Si4709_dev_AFCRL_get i2c_read failed"); - *afc = AFCRL; - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -/* Setting DE - emphasis time constant 50us(Europe,Japan,Australia) or 75us(USA) - */ -int Si4709_dev_DE_set(u8 de_tc) -{ - u16 sysconfig1 = 0; - int ret = 0; - - debug("Si4709_dev_DE_set called"); - - mutex_lock(&(Si4709_dev.lock)); - - sysconfig1 = Si4709_dev.registers[SYSCONFIG1]; - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_DE_set called when DS is invalid"); - ret = -1; - } else { - switch (de_tc) { - case DE_TIME_CONSTANT_50: - si47xx_set_property(FM_DEEMPHASIS, FM_DEEMPH_50US); - break; - - case DE_TIME_CONSTANT_75: - si47xx_set_property(FM_DEEMPHASIS, FM_DEEMPH_75US); - break; - - default: - ret = -1; - } - - if (0 == ret) { - if (ret < 0) - debug("Si4709_dev_DE_set i2c_write failed"); - } - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -/*Resetting the RDS Data Buffer*/ -int Si4709_dev_reset_rds_data() -{ - int ret = 0; - - debug_rds("Si4709_dev_reset_rds_data called"); - - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_reset_rds_data called when DS is invalid"); - ret = -1; - } else { - RDS_Buffer_Index_write = 0; - RDS_Buffer_Index_read = 0; - RDS_Data_Lost = 0; - RDS_Data_Available = 0; - memset(RDS_Block_Data_buffer, 0, RDS_BUFFER_LENGTH * 8); - memset(RDS_Block_Error_buffer, 0, RDS_BUFFER_LENGTH * 4); - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -/*VNVS:END*/ - -int Si4709_dev_VOLEXT_ENB(void) -{ - int ret = 0; - - debug("Si4709_dev_VOLEXT_ENB called"); - - return ret; -} - -int Si4709_dev_VOLEXT_DISB(void) -{ - int ret = 0; - - debug("Si4709_dev_VOLEXT_DISB called"); - - return ret; -} - -int Si4709_dev_volume_set(u8 volume) -{ - int ret = 0; - u16 sysconfig2 = 0; - - debug("Si4709_dev_volume_set called"); - - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_volume_set called when DS is invalid"); - ret = -1; - } else { - si47xx_set_property(RX_VOLUME, rx_vol[volume] & RX_VOLUME_MASK); - - if (ret < 0) { - debug("Si4709_dev_volume_set i2c_write failed"); - Si4709_dev.registers[SYSCONFIG2] = sysconfig2; - } - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_volume_get(u8 *volume) -{ - int ret = 0; - - debug("Si4709_dev_volume_get called"); -#if 0 /*To Do*/ - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_volume_get called when DS is invalid"); - ret = -1; - } else - *volume = - SYSCONFIG2_GET_VOLUME(Si4709_dev.registers[SYSCONFIG2]); - - mutex_unlock(&(Si4709_dev.lock)); -#endif - return ret; -} - -/* -VNVS:START 19-AUG'10 : Adding DSMUTE ON/OFF feature. -The Soft Mute feature is available to attenuate the audio -outputs and minimize audible noise in very weak signal conditions. - */ -int Si4709_dev_DSMUTE_ON(void) -{ - int ret = 0; - u16 powercfg = 0; - - debug("Si4709_dev_DSMUTE_ON called"); - - mutex_lock(&(Si4709_dev.lock)); - - powercfg = Si4709_dev.registers[POWERCFG]; - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_DSMUTE_ON called when DS is invalid"); - ret = -1; - } else { - si47xx_set_property(FM_SOFT_MUTE_RATE, 64); - si47xx_set_property(FM_SOFT_MUTE_MAX_ATTENUATION, 0); - si47xx_set_property(FM_SOFT_MUTE_SNR_THRESHOLD, 4); - if (ret < 0) - error("Si4709_dev_DSMUTE_ON i2c_write failed"); - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_DSMUTE_OFF(void) -{ - int ret = 0; - u16 powercfg = 0; - - debug("Si4709_dev_DSMUTE_OFF called"); - - mutex_lock(&(Si4709_dev.lock)); - - powercfg = Si4709_dev.registers[POWERCFG]; - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_DSMUTE_OFF called when DS is invalid"); - ret = -1; - } else { - si47xx_set_property(FM_SOFT_MUTE_RATE, 64); - si47xx_set_property(FM_SOFT_MUTE_MAX_ATTENUATION, 16); - si47xx_set_property(FM_SOFT_MUTE_SNR_THRESHOLD, 4); - if (ret < 0) - error("Si4709_dev_DSMUTE_OFF i2c_write failed"); - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -/*VNVS:END*/ - -int Si4709_dev_MUTE_ON(void) -{ - int ret = 0; - u16 powercfg = 0; - - debug("Si4709_dev_MUTE_ON called"); - - mutex_lock(&(Si4709_dev.lock)); - - powercfg = Si4709_dev.registers[POWERCFG]; - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_MUTE_ON called when DS is invalid"); - ret = -1; - } else { - si47xx_set_property(RX_HARD_MUTE, - RX_HARD_MUTE_RMUTE_MASK | - RX_HARD_MUTE_LMUTE_MASK); - if (ret < 0) - debug("Si4709_dev_MUTE_ON i2c_write failed"); - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_MUTE_OFF(void) -{ - int ret = 0; - u16 powercfg = 0; - - debug("Si4709_dev_MUTE_OFF called"); - - mutex_lock(&(Si4709_dev.lock)); - - powercfg = Si4709_dev.registers[POWERCFG]; - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_MUTE_OFF called when DS is invalid"); - ret = -1; - } else { - si47xx_set_property(RX_HARD_MUTE, 0); - if (ret < 0) - debug("Si4709_dev_MUTE_OFF i2c_write failed"); - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_MONO_SET(void) -{ - int ret = 0; - u16 powercfg = 0; - - debug("Si4709_dev_MONO_SET called"); - - mutex_lock(&(Si4709_dev.lock)); - - powercfg = Si4709_dev.registers[POWERCFG]; - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_MONO_SET called when DS is invalid"); - ret = -1; - } else { - si47xx_set_property(FM_BLEND_MONO_THRESHOLD, 127); - si47xx_set_property(FM_BLEND_STEREO_THRESHOLD, 127); - if (ret < 0) - debug("Si4709_dev_MONO_SET i2c_write failed"); - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_STEREO_SET(void) -{ - int ret = 0; - u16 powercfg = 0; - - debug("Si4709_dev_STEREO_SET called"); - - mutex_lock(&(Si4709_dev.lock)); - - powercfg = Si4709_dev.registers[POWERCFG]; - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_STEREO_SET called when DS is invalid"); - ret = -1; - } else { - si47xx_set_property(FM_BLEND_MONO_THRESHOLD, 30); - si47xx_set_property(FM_BLEND_STEREO_THRESHOLD, 49); - if (ret < 0) - debug("Si4709_dev_STEREO_SET i2c_write failed"); - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_RDS_ENABLE(void) -{ - int ret = 0; - - debug("Si4709_dev_RDS_ENABLE called"); - - mutex_lock(&(Si4709_dev.lock)); - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_RDS_ENABLE called when DS is invalid"); - ret = -1; - } else { -#ifdef RDS_INTERRUPT_ON_ALWAYS - si47xx_set_property(GPO_IEN, GPO_IEN_STCIEN_MASK | - GPO_IEN_STCREP_MASK | GPO_IEN_RDSIEN_MASK | - GPO_IEN_RDSREP_MASK); -#endif - si47xx_set_property(FM_RDS_INTERRUPT_SOURCE, - FM_RDS_INTERRUPT_SOURCE_RECV_MASK); - si47xx_set_property(FM_RDS_CONFIG, FM_RDS_CONFIG_RDSEN_MASK | - (3 << FM_RDS_CONFIG_BLETHA_SHFT) | - (3 << FM_RDS_CONFIG_BLETHB_SHFT) | - (3 << FM_RDS_CONFIG_BLETHC_SHFT) | - (3 << FM_RDS_CONFIG_BLETHD_SHFT)); - if (ret < 0) - debug("Si4709_dev_RDS_ENABLE i2c_write failed"); -#ifdef RDS_INTERRUPT_ON_ALWAYS - else - Si4709_RDS_flag = RDS_WAITING; -#endif - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_RDS_DISABLE(void) -{ - int ret = 0; - - debug("Si4709_dev_RDS_DISABLE called"); - - mutex_lock(&(Si4709_dev.lock)); - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_RDS_DISABLE called when DS is invalid"); - ret = -1; - } else { - si47xx_set_property(FM_RDS_CONFIG, 0); - - if (ret < 0) - debug("Si4709_dev_RDS_DISABLE i2c_write failed"); -#ifdef RDS_INTERRUPT_ON_ALWAYS - else - Si4709_RDS_flag = NO_WAIT; -#endif - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_rstate_get(struct dev_state_t *dev_state) -{ - int ret = 0; - - debug("Si4709_dev_rstate_get called"); - - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_rstate_get called when DS is invalid"); - ret = -1; - } else { - dev_state->power_state = Si4709_dev.state.power_state; - dev_state->seek_state = Si4709_dev.state.seek_state; - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -/* VNVS:START 7-JUNE'10 Function call for work-queue "Si4709_wq" */ -#ifdef RDS_INTERRUPT_ON_ALWAYS -void Si4709_work_func(struct work_struct *work) -{ - int i = 0; -#ifdef RDS_TESTING - u8 group_type; -#endif - debug_rds("%s", __func__); -mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - error("Si4709_dev_RDS_data_get called when DS is invalid"); - return; - } - - if (RDS_Data_Lost > 1) - debug_rds("No_of_RDS_groups_Lost till now : %d", - RDS_Data_Lost); - fmRdsStatus(1, 0); - /* RDSR bit and RDS Block data, so reading the RDS registers */ - do { - /* Writing into RDS_Block_Data_buffer */ - i = 0; - RDS_Block_Data_buffer[i++ + 4 * RDS_Buffer_Index_write] = - BlockA; - RDS_Block_Data_buffer[i++ + 4 * RDS_Buffer_Index_write] = - BlockB; - RDS_Block_Data_buffer[i++ + 4 * RDS_Buffer_Index_write] = - BlockC; - RDS_Block_Data_buffer[i++ + 4 * RDS_Buffer_Index_write] = - BlockD; - - /*Writing into RDS_Block_Error_buffer */ - i = 0; - - RDS_Block_Error_buffer[i++ + 4 * RDS_Buffer_Index_write] = - BleA; - RDS_Block_Error_buffer[i++ + 4 * RDS_Buffer_Index_write] = - BleB; - RDS_Block_Error_buffer[i++ + 4 * RDS_Buffer_Index_write] = - BleC; - RDS_Block_Error_buffer[i++ + 4 * RDS_Buffer_Index_write] = - BleD; - fmRdsStatus(1, 0); - } while (RdsFifoUsed != 0); - -#ifdef RDS_TESTING - if (RDS_Block_Error_buffer - [0 + 4 * RDS_Buffer_Index_write] < 3) { - debug_rds("PI Code is %d", - RDS_Block_Data_buffer[0 + 4 - * RDS_Buffer_Index_write]); - } - if (RDS_Block_Error_buffer - [1 + 4 * RDS_Buffer_Index_write] < 2) { - group_type = RDS_Block_Data_buffer[1 + 4 - * RDS_Buffer_Index_write] >> 11; - - if (group_type & 0x01) { - debug_rds("PI Code is %d", - RDS_Block_Data_buffer[2 + 4 - * RDS_Buffer_Index_write]); - } - if (group_type == GROUP_TYPE_2A - || group_type == GROUP_TYPE_2B) { - if (RDS_Block_Error_buffer - [2 + 4 * RDS_Buffer_Index_write] < 3) { - debug_rds("Update RT with RDSC"); - } else { - debug_rds("RDS_Block_Error_buffer" - " of Block C is greater than 3"); - } - } - } -#endif - RDS_Buffer_Index_write++; - - if (RDS_Buffer_Index_write >= RDS_BUFFER_LENGTH) - RDS_Buffer_Index_write = 0; - - debug_rds("RDS_Buffer_Index_write = %d", RDS_Buffer_Index_write); - mutex_unlock(&(Si4709_dev.lock)); -} -#endif -/*VNVS:END*/ - -int Si4709_dev_RDS_data_get(struct radio_data_t *data) -{ - int i, ret = 0; - - debug_rds("Si4709_dev_RDS_data_get called"); - - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - error("Si4709_dev_RDS_data_get called when DS is invalid"); - mutex_unlock(&(Si4709_dev.lock)); - return -1; - } -#ifdef RDS_INTERRUPT_ON_ALWAYS - debug_rds("RDS_Buffer_Index_read = %d", RDS_Buffer_Index_read); - - /*If No New RDS Data is available return error */ - if (RDS_Buffer_Index_read == RDS_Buffer_Index_write) { - debug_rds("No_New_RDS_Data_is_available"); - if (ret < 0) - error("Si4709_dev_RDS_data_get i2c_read 1 failed"); - else { - fmTuneStatus(0, 0); - data->curr_channel = Freq; - data->curr_rssi = RSSI; - debug_rds("curr_channel: %u, curr_rssi:%u", - data->curr_channel, - (u32) data->curr_rssi); - } - mutex_unlock(&(Si4709_dev.lock)); - return -1; - } - if (ret < 0) - error("Si4709_dev_RDS_data_get i2c_read 2 failed"); - else { - fmTuneStatus(0, 0); - data->curr_channel = Freq; - data->curr_rssi = RSSI; - debug_rds("curr_channel: %u, curr_rssi:%u", - data->curr_channel, (u32) data->curr_rssi); - - /* Reading from RDS_Block_Data_buffer */ - i = 0; - data->rdsa = RDS_Block_Data_buffer[i++ + 4 - * RDS_Buffer_Index_read]; - data->rdsb = RDS_Block_Data_buffer[i++ + 4 - * RDS_Buffer_Index_read]; - data->rdsc = RDS_Block_Data_buffer[i++ + 4 - * RDS_Buffer_Index_read]; - data->rdsd = RDS_Block_Data_buffer[i++ + 4 - * RDS_Buffer_Index_read]; - - /* Reading from RDS_Block_Error_buffer */ - i = 0; - data->blera = RDS_Block_Error_buffer[i++ + 4 - * RDS_Buffer_Index_read]; - data->blerb = RDS_Block_Error_buffer[i++ + 4 - * RDS_Buffer_Index_read]; - data->blerc = RDS_Block_Error_buffer[i++ + 4 - * RDS_Buffer_Index_read]; - data->blerd = RDS_Block_Error_buffer[i++ + 4 - * RDS_Buffer_Index_read]; - - /*Flushing the read data */ - memset(&RDS_Block_Data_buffer[0 + 4 * RDS_Buffer_Index_read], - 0, 8); - memset(&RDS_Block_Error_buffer[0 + 4 * RDS_Buffer_Index_read], - 0, 4); - - RDS_Buffer_Index_read++; - - if (RDS_Buffer_Index_read >= RDS_BUFFER_LENGTH) - RDS_Buffer_Index_read = 0; - } - - debug_rds("RDS_Buffer_Index_read = %d", RDS_Buffer_Index_read); -#else -#if 0 /*To Do*/ - SYSCONFIG1_BITSET_RDSIEN_HIGH(&Si4709_dev.registers[SYSCONFIG1]); - - ret = i2c_write(SYSCONFIG1); - if (ret < 0) { - debug("Si4709_dev_RDS_data_get i2c_write 1 failed"); - Si4709_dev.registers[SYSCONFIG1] = sysconfig1; - } else { - ret = i2c_read(SYSCONFIG1); - if (ret < 0) - debug("Si4709_dev_RDS_data_get i2c_read 1 failed"); - - debug("sysconfig1: 0x%x", Si4709_dev.registers[SYSCONFIG1]); - - sysconfig1 = Si4709_dev.registers[SYSCONFIG1]; - - Si4709_dev_wait_flag = RDS_WAITING; - - wait_RDS(); - - ret = i2c_read(STATUSRSSI); - if (ret < 0) - debug("Si4709_dev_RDS_data_get i2c_read 2 failed"); - - debug("statusrssi: 0x%x", Si4709_dev.registers[STATUSRSSI]); - - SYSCONFIG1_BITSET_RDSIEN_LOW(&Si4709_dev.registers[SYSCONFIG1]); - - ret = i2c_write(SYSCONFIG1); - if (ret < 0) { - debug("Si4709_dev_RDS_data_get i2c_write 2 failed"); - Si4709_dev.registers[SYSCONFIG1] = sysconfig1; - } else if (Si4709_dev_wait_flag == WAIT_OVER) { - Si4709_dev_wait_flag = NO_WAIT; - - ret = i2c_read(RDSD); - if (ret < 0) - debug("Si4709_dev_RDS_data_get " - "i2c_read 3 failed"); - else { - data->rdsa = Si4709_dev.registers[RDSA]; - data->rdsb = Si4709_dev.registers[RDSB]; - data->rdsc = Si4709_dev.registers[RDSC]; - data->rdsd = Si4709_dev.registers[RDSD]; - - get_cur_chan_freq(&(data->curr_channel), - Si4709_dev.registers[READCHAN]); - debug("curr_channel: %u", data->curr_channel); - data->curr_rssi = - STATUSRSSI_RSSI_SIGNAL_STRENGTH - (Si4709_dev.registers[STATUSRSSI]); - debug("curr_rssi:%u", (u32)data->curr_rssi); - data->blera = - STATUSRSSI_RDS_BLOCK_A_ERRORS - (Si4709_dev.registers[STATUSRSSI]); - data->blerb = - READCHAN_BLOCK_B_ERRORS(Si4709_dev. - registers[READCHAN]); - data->blerc = - READCHAN_BLOCK_C_ERRORS(Si4709_dev. - registers[READCHAN]); - data->blerd = - READCHAN_BLOCK_D_ERRORS(Si4709_dev. - registers[READCHAN]); - } - } else { - debug("Si4709_dev_RDS_data_get failure " - "no interrupt or timeout"); - Si4709_dev_wait_flag = NO_WAIT; - mutex_unlock(&(Si4709_dev.lock)); - return -1; - } - } -#endif -#endif - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -int Si4709_dev_RDS_timeout_set(u32 time_out) -{ - int ret = 0; - u32 jiffy_count = 0; - - debug("Si4709_dev_RDS_timeout_set called"); - /****convert time_out(in milliseconds) into jiffies*****/ - - jiffy_count = msecs_to_jiffies(time_out); - - debug("jiffy_count%d", jiffy_count); - - mutex_lock(&(Si4709_dev.lock)); - - if (Si4709_dev.valid == eFALSE) { - debug("Si4709_dev_RDS_timeout_set called when DS is invalid"); - ret = -1; - } else { - Si4709_dev.settings.timeout_RDS = jiffy_count; - } - - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -/**************************************************************/ -static int powerup(void) -{ - int ret = 0; - u16 powercfg = Si4709_dev.registers[POWERCFG]; - -#if defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_M0_CTC) - gpio_set_value(Si4709_dev_sw, GPIO_LEVEL_HIGH); -#endif - - gpio_set_value(GPIO_FM_RST, GPIO_LEVEL_LOW); - usleep_range(5, 10); - s3c_gpio_cfgpin(Si4709_dev_int, S3C_GPIO_OUTPUT); - s3c_gpio_setpull(Si4709_dev_int, S3C_GPIO_PULL_DOWN); - gpio_set_value(Si4709_dev_int, GPIO_LEVEL_LOW); - usleep_range(10, 15); - gpio_set_value(GPIO_FM_RST, GPIO_LEVEL_HIGH); - usleep_range(5, 10); - s3c_gpio_cfgpin(Si4709_dev_int, S3C_GPIO_SFN(0xF)); - s3c_gpio_setpull(Si4709_dev_int, S3C_GPIO_PULL_UP); - usleep_range(10, 15); - - cmd[0] = POWER_UP; - cmd[1] = POWER_UP_IN_GPO2OEN; - cmd[1] |= POWER_UP_IN_FUNC_FMRX; - cmd[2] = POWER_UP_IN_OPMODE_RX_ANALOG; - ret = si47xx_command(3, cmd, 8, rsp); - - if (ret < 0) { - debug("powerup->i2c_write 1 failed"); - Si4709_dev.registers[POWERCFG] = powercfg; - } else { - /* Si4709/09 datasheet: Table 7 */ - msleep(110); - Si4709_dev.state.power_state = RADIO_ON; - } - return ret; -} - -static int powerdown(void) -{ - int ret = 0; - - if (!(RADIO_POWERDOWN == Si4709_dev.state.power_state)) { - cmd[0] = POWER_DOWN; - ret = si47xx_command(1, cmd, 1, rsp); - msleep(110); - - if (ret < 0) - debug("powerdown->i2c_write failed"); - else - Si4709_dev.state.power_state = RADIO_POWERDOWN; - - gpio_set_value(GPIO_FM_RST, GPIO_LEVEL_LOW); - } else - debug("Device already Powered-OFF\n"); - -#if defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_M0_CTC) - gpio_set_value(Si4709_dev_sw, GPIO_LEVEL_LOW); -#endif - - return ret; -} - -static int seek(u32 *frequency, int up, int mode) -{ - int ret = 0; - u8 get_int; - - if (ret < 0) { - debug("seek i2c_write 1 failed"); - } else { - Si4709_dev_wait_flag = SEEK_WAITING; - fmSeekStart(up, mode); /* mode 0 is full scan */ - wait(); - do { - get_int = getIntStatus(); - } while (!(get_int & STCINT)); - - if (Si4709_dev_wait_flag == SEEK_CANCEL) { - fmTuneStatus(1, 0); - if (ret < 0) { - debug("seek i2c_write 2 failed"); - } - if (ret < 0) - debug("seek i2c_read 1 failed"); - else - *frequency = Freq; - - *frequency = 0; - } - - Si4709_dev_wait_flag = NO_WAIT; - - fmTuneStatus(0, 1); - if (BLTF != 1) - *frequency = Freq; - - else { - if (Valid) - *frequency = Freq; - else - *frequency = 0; - } - } - return ret; -} - -static int tune_freq(u32 frequency) -{ - int ret = 0; - - u16 channel = Si4709_dev.registers[CHANNEL]; - mutex_lock(&(Si4709_dev.lock)); - - channel = freq_to_channel(frequency); - if (ret < 0) { - debug("tune_freq i2c_write 1 failed"); - Si4709_dev.registers[CHANNEL] = channel; - } else { - Si4709_dev_wait_flag = TUNE_WAITING; - fmTuneFreq(frequency); - wait(); - Si4709_dev_wait_flag = NO_WAIT; - debug("Si4709_dev_wait_flag = TUNE_WAITING\n"); - - if (!(getIntStatus() & STCINT)) { - printk(KERN_INFO "%s tune is failed!\n", __func__); - fmTuneStatus(1, 1); - mutex_unlock(&(Si4709_dev.lock)); - return -1; - } - - fmTuneStatus(0, 1); - - debug("Si4709 tune_freq fmTuneStatus %x\n", rsp[0]); - - } - mutex_unlock(&(Si4709_dev.lock)); - - return ret; -} - -static u16 freq_to_channel(u32 frequency) -{ - u16 channel; - - if (frequency < Si4709_dev.settings.bottom_of_band) - frequency = Si4709_dev.settings.bottom_of_band; - - channel = (frequency - Si4709_dev.settings.bottom_of_band) - / Si4709_dev.settings.channel_spacing; - - return channel; -} - -/* Only one thread will be able to call this, since this function call is - protected by a mutex, so no race conditions can arise */ -static void wait(void) -{ - wait_event_interruptible(Si4709_waitq, - (Si4709_dev_wait_flag == WAIT_OVER) || - (Si4709_dev_wait_flag == SEEK_CANCEL)); -} - -#ifndef RDS_INTERRUPT_ON_ALWAYS -static void wait_RDS(void) -{ - wait_event_interruptible_timeout(Si4709_waitq, - (Si4709_dev_wait_flag == WAIT_OVER), - Si4709_dev.settings.timeout_RDS); -} -#endif - -/*----------------------------------------------------------------------------- - Helper function that sends the GET_INT_STATUS command to the part - - Returns: - The status byte from the part. ------------------------------------------------------------------------------*/ -u8 getIntStatus(void) -{ - cmd[0] = GET_INT_STATUS; - si47xx_command(1, cmd, 1, rsp); - - debug("Si4709 getIntStatus return %x\n", rsp[0]); - return rsp[0]; -} - -/*----------------------------------------------------------------------------- - Helper function that sends the FM_TUNE_FREQ command to the part - - Inputs: - frequency in 10kHz steps ------------------------------------------------------------------------------*/ -static void fmTuneFreq(u16 frequency) -{ - cmd[0] = FM_TUNE_FREQ; - cmd[1] = 0; - cmd[2] = (u8)(frequency >> 8); - cmd[3] = (u8)(frequency & 0x00FF); - cmd[4] = (u8)0; - si47xx_command(5, cmd, 1, rsp); -} - -/*----------------------------------------------------------------------------- - Helper function that sends the FM_TUNE_STATUS command to the part - - Inputs: - cancel: If non-zero the current seek will be cancelled. - intack: If non-zero the interrupt for STCINT will be cleared. - -Outputs: These are global variables and are set by this method -STC: The seek/tune is complete -BLTF: The seek reached the band limit or original start frequency -AFCRL: The AFC is railed if this is non-zero -Valid: The station is valid if this is non-zero -Freq: The current frequency -RSSI: The RSSI level read at tune. -ASNR: The audio SNR level read at tune. -AntCap: The current level of the tuning capacitor. ------------------------------------------------------------------------------*/ - -static void fmTuneStatus(u8 cancel, u8 intack) -{ - cmd[0] = FM_TUNE_STATUS; - cmd[1] = 0; - if (cancel) - cmd[1] |= FM_TUNE_STATUS_IN_CANCEL; - if (intack) - cmd[1] |= FM_TUNE_STATUS_IN_INTACK; - - si47xx_command(2, cmd, 8, rsp); - - STC = !!(rsp[0] & STCINT); - BLTF = !!(rsp[1] & FM_TUNE_STATUS_OUT_BTLF); - AFCRL = !!(rsp[1] & FM_TUNE_STATUS_OUT_AFCRL); - Valid = !!(rsp[1] & FM_TUNE_STATUS_OUT_VALID); - Freq = ((u16)rsp[2] << 8) | (u16)rsp[3]; - RSSI = rsp[4]; - ASNR = rsp[5]; - AntCap = rsp[7]; -} - -/*----------------------------------------------------------------------------- - Helper function that sends the FM_RDS_STATUS command to the part - - Inputs: - intack: If non-zero the interrupt for STCINT will be cleared. - mtfifo: If non-zero the fifo will be cleared. - -Outputs: -Status: Contains bits about the status returned from the part. -RdsInts: Contains bits about the interrupts that have fired -related to RDS. -RdsSync: If non-zero the RDS is currently synced. -GrpLost: If non-zero some RDS groups were lost. -RdsFifoUsed: The amount of groups currently remaining -in the RDS fifo. -BlockA: Block A group data from the oldest FIFO entry. -BlockB: Block B group data from the oldest FIFO entry. -BlockC: Block C group data from the oldest FIFO entry. -BlockD: Block D group data from the oldest FIFO entry. -BleA: Block A corrected error information. -BleB: Block B corrected error information. -BleC: Block C corrected error information. -BleD: Block D corrected error information. ------------------------------------------------------------------------------*/ -void fmRdsStatus(u8 intack, u8 mtfifo) -{ - cmd[0] = FM_RDS_STATUS; - cmd[1] = 0; - if (intack) - cmd[1] |= FM_RDS_STATUS_IN_INTACK; - if (mtfifo) - cmd[1] |= FM_RDS_STATUS_IN_MTFIFO; - - si47xx_command(2, cmd, 13, rsp); - - Status = rsp[0]; - RdsInts = rsp[1]; - RdsSync = !!(rsp[2] & FM_RDS_STATUS_OUT_SYNC); - GrpLost = !!(rsp[2] & FM_RDS_STATUS_OUT_GRPLOST); - RdsFifoUsed = rsp[3]; - BlockA = ((u16)rsp[4] << 8) | (u16)rsp[5]; - BlockB = ((u16)rsp[6] << 8) | (u16)rsp[7]; - BlockC = ((u16)rsp[8] << 8) | (u16)rsp[9]; - BlockD = ((u16)rsp[10] << 8) | (u16)rsp[11]; - BleA = (rsp[12] & FM_RDS_STATUS_OUT_BLEA) >> - FM_RDS_STATUS_OUT_BLEA_SHFT; - BleB = (rsp[12] & FM_RDS_STATUS_OUT_BLEB) >> - FM_RDS_STATUS_OUT_BLEB_SHFT; - BleC = (rsp[12] & FM_RDS_STATUS_OUT_BLEC) >> - FM_RDS_STATUS_OUT_BLEC_SHFT; - BleD = (rsp[12] & FM_RDS_STATUS_OUT_BLED) >> - FM_RDS_STATUS_OUT_BLED_SHFT; -} - - -/*----------------------------------------------------------------------------- - Helper function that sends the FM_RSQ_STATUS command to the part - - Inputs: - intack: If non-zero the interrupt for STCINT will be cleared. - -Outputs: -Status: Contains bits about the status returned from the part. -RsqInts: Contains bits about the interrupts that have fired related to RSQ. -SMUTE: The soft mute function is currently enabled -AFCRL: The AFC is railed if this is non-zero -Valid: The station is valid if this is non-zero -Pilot: A pilot tone is currently present -Blend: Percentage of blend for stereo. (100 = full stereo) -RSSI: The RSSI level read at tune. -ASNR: The audio SNR level read at tune. -FreqOff: The frequency offset in kHz of the current station from the tuned -frequency. ------------------------------------------------------------------------------*/ -static void fmRsqStatus(u8 intack) -{ - cmd[0] = FM_RSQ_STATUS; - cmd[1] = 0; - if (intack) - cmd[1] |= FM_RSQ_STATUS_IN_INTACK; - - si47xx_command(2, cmd, 8, rsp); - - Status = rsp[0]; - RsqInts = rsp[1]; - SMUTE = !!(rsp[2] & FM_RSQ_STATUS_OUT_SMUTE); - AFCRL = !!(rsp[2] & FM_RSQ_STATUS_OUT_AFCRL); - Valid = !!(rsp[2] & FM_RSQ_STATUS_OUT_VALID); - Pilot = !!(rsp[3] & FM_RSQ_STATUS_OUT_PILOT); - Blend = rsp[3] & FM_RSQ_STATUS_OUT_STBLEND; - RSSI = rsp[4]; - ASNR = rsp[5]; - FreqOff = rsp[7]; -} - - -/*----------------------------------------------------------------------------- - Helper function that sends the FM_SEEK_START command to the part - -Inputs: -seekUp: If non-zero seek will increment otherwise decrement -wrap: If non-zero seek will wrap around band limits when hitting the end -of the band limit. ------------------------------------------------------------------------------*/ -static void fmSeekStart(u8 seekUp, u8 wrap) -{ - cmd[0] = FM_SEEK_START; - cmd[1] = 0; - if (seekUp) - cmd[1] |= FM_SEEK_START_IN_SEEKUP; - if (wrap) - cmd[1] |= FM_SEEK_START_IN_WRAP; - - si47xx_command(2, cmd, 1, rsp); -} - - -/*----------------------------------------------------------------------------- - Set the passed property number to the passed value. - - Inputs: - propNumber: The number identifying the property to set - propValue: The value of the property. ------------------------------------------------------------------------------*/ -void si47xx_set_property(u16 propNumber, u16 propValue) -{ - cmd[0] = SET_PROPERTY; - cmd[1] = 0; - cmd[2] = (u8)(propNumber >> 8); - cmd[3] = (u8)(propNumber & 0x00FF); - cmd[4] = (u8)(propValue >> 8); - cmd[5] = (u8)(propValue & 0x00FF); - - si47xx_command(6, cmd, 0, NULL); -} - -/*----------------------------------------------------------------------------- - This command returns the status ------------------------------------------------------------------------------*/ -u8 si47xx_readStatus(void) -{ - u8 status; - i2c_read(1, &status); - - return status; -} - - -/*----------------------------------------------------------------------------- - Command that will wait for CTS before returning ------------------------------------------------------------------------------*/ -void si47xx_waitForCTS(void) -{ - u16 i = 1000; - u8 rStatus = 0; - - do { - rStatus = si47xx_readStatus(); - usleep_range(5, 10); - } while (--i && !(rStatus & CTS)); -} - -/*----------------------------------------------------------------------------- - Sends a command to the part and returns the reply bytes ------------------------------------------------------------------------------*/ -int si47xx_command(u8 cmd_size, u8 *cmd, u8 reply_size, u8 *reply) -{ - int ret = 0; - ret = i2c_write(cmd_size, cmd); - si47xx_waitForCTS(); - - if (reply_size) - i2c_read(reply_size, reply); - - if (ret < 0) - printk(KERN_INFO "%s i2c_write failed %d\n", __func__, ret); - - return ret; -} - -static int i2c_write(u8 number_bytes, u8 *data_out) -{ - int ret = 0; - - ret = i2c_master_send((struct i2c_client *)(Si4709_dev.client), - (const char *)data_out, number_bytes); - if (ret == number_bytes) - ret = 0; - else - ret = -1; - - return ret; -} - -static int i2c_read(u8 number_bytes, u8 *data_in) -{ - int ret = 0; - - ret = i2c_master_recv((struct i2c_client *)(Si4709_dev.client), data_in, - number_bytes); - if (ret < 0) - printk(KERN_INFO "%s i2c_read failed %d\n", __func__, ret); - - return ret; -} diff --git a/drivers/samsung/fm_si4709/Si4705_main.c b/drivers/samsung/fm_si4709/Si4705_main.c index aaccd5f..0695e17 100644 --- a/drivers/samsung/fm_si4709/Si4705_main.c +++ b/drivers/samsung/fm_si4709/Si4705_main.c @@ -329,6 +329,7 @@ static long Si4709_ioctl(struct file *filp, unsigned int ioctl_cmd, debug("Si4709_IOC_VOLUME_GET called\n"); ret = (long)Si4709_dev_volume_get(&volume); + if (ret < 0) debug("Si4709_IOC_VOLUME_GET failed\n"); else if (copy_to_user @@ -757,9 +758,14 @@ void debug_ioctls(void) int __init Si4709_driver_init(void) { int ret = 0; + unsigned int gpio_fm_rst = GPIO_FM_RST; debug("Si4709_driver_init called\n"); +#if defined(CONFIG_MACH_T0) + if (system_rev >= 3) + gpio_fm_rst = GPIO_FM_RST_REV03; +#endif /*Initialize the Si4709 dev mutex */ Si4709_dev_mutex_init(); @@ -791,19 +797,19 @@ int __init Si4709_driver_init(void) debug("Si4709_driver_init request_irq " "success %d", Si4709_int); - if (gpio_is_valid(GPIO_FM_RST)) { - if (gpio_request(GPIO_FM_RST, "GPC1")) + if (gpio_is_valid(gpio_fm_rst)) { + if (gpio_request(gpio_fm_rst, "FM_RST")) debug(KERN_ERR "Failed to request " "FM_RESET!\n\n"); - gpio_direction_output(GPIO_FM_RST, GPIO_LEVEL_LOW); + gpio_direction_output(gpio_fm_rst, GPIO_LEVEL_LOW); } #if defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_M0_CTC) if (gpio_is_valid(GPIO_FM_MIC_SW)) { - if (gpio_request(GPIO_FM_MIC_SW, "GPL0")) + if (gpio_request(GPIO_FM_MIC_SW, "FM_MIC_SW")) debug(KERN_ERR "Failed to request " "FM_MIC_SW!\n\n"); - gpio_direction_output(GPIO_FM_RST, GPIO_LEVEL_LOW); + gpio_direction_output(GPIO_FM_MIC_SW, GPIO_LEVEL_LOW); } #endif @@ -812,15 +818,15 @@ int __init Si4709_driver_init(void) as the FM Radio device gives 5ms low pulse*/ s3c_gpio_setpull(Si4709_int, S3C_GPIO_PULL_UP); /****Resetting the device****/ - gpio_set_value(GPIO_FM_RST, GPIO_LEVEL_LOW); + gpio_set_value(gpio_fm_rst, GPIO_LEVEL_LOW); s3c_gpio_cfgpin(Si4709_int, S3C_GPIO_OUTPUT); s3c_gpio_setpull(Si4709_int, S3C_GPIO_PULL_DOWN); - gpio_set_value(GPIO_FM_RST, GPIO_LEVEL_HIGH); + gpio_set_value(gpio_fm_rst, GPIO_LEVEL_HIGH); usleep_range(10, 15); s3c_gpio_cfgpin(Si4709_int, S3C_GPIO_SFN(0xF)); s3c_gpio_setpull(Si4709_int, S3C_GPIO_PULL_UP); - gpio_free(FM_RESET); + gpio_free(gpio_fm_rst); /*Add the i2c driver */ ret = Si4709_i2c_drv_init(); @@ -838,6 +844,8 @@ MISC_IRQ_DREG: MISC_DREG: misc_deregister(&Si4709_misc_device); + Si4709_dev_mutex_destroy(); + return ret; } diff --git a/drivers/samsung/fm_si4709/Si4709_dev.c b/drivers/samsung/fm_si4709/Si4709_dev.c index 32ef932..6b483e1 100644 --- a/drivers/samsung/fm_si4709/Si4709_dev.c +++ b/drivers/samsung/fm_si4709/Si4709_dev.c @@ -71,7 +71,7 @@ static void wait_RDS(void); static int powerup(void); static int powerdown(void); -static int seek(u32 *, int); +static int seek(u32 *, int, int); static int tune_freq(u32); static void get_cur_chan_freq(u32 *, u16); @@ -602,6 +602,24 @@ int Si4709_dev_chan_get(u32 *frequency) return ret; } +int Si4709_dev_seek_full(u32 *frequency) +{ + int ret = 0; + + debug("Si47xx_dev_seek_full called\n"); + + if (Si4709_dev.valid == eFALSE) { + error("Si4709_dev_seek_full called when DS is invalid"); + ret = -1; + } else { + Si4709_dev.state.seek_state = RADIO_SEEK_ON; + ret = seek(frequency, 1, 1); + Si4709_dev.state.seek_state = RADIO_SEEK_OFF; + } + + return ret; +} + int Si4709_dev_seek_up(u32 *frequency) { int ret = 0; @@ -616,7 +634,7 @@ int Si4709_dev_seek_up(u32 *frequency) } else { Si4709_dev.state.seek_state = RADIO_SEEK_ON; - ret = seek(frequency, 1); + ret = seek(frequency, 1, 0); Si4709_dev.state.seek_state = RADIO_SEEK_OFF; } @@ -640,7 +658,7 @@ int Si4709_dev_seek_down(u32 *frequency) } else { Si4709_dev.state.seek_state = RADIO_SEEK_ON; - ret = seek(frequency, 0); + ret = seek(frequency, 0, 0); Si4709_dev.state.seek_state = RADIO_SEEK_OFF; } @@ -2102,7 +2120,7 @@ static int powerdown(void) return ret; } -static int seek(u32 *frequency, int up) +static int seek(u32 *frequency, int up, int mode) { int ret = 0; u16 powercfg = Si4709_dev.registers[POWERCFG]; @@ -2114,7 +2132,14 @@ static int seek(u32 *frequency, int up) else POWERCFG_BITSET_SEEKUP_LOW(&Si4709_dev.registers[POWERCFG]); - POWERCFG_BITSET_SKMODE_HIGH(&Si4709_dev.registers[POWERCFG]); + /* add mode that configure skmode high(1) is stop freq if it reach end, + * low is wrap freq and this value is default value + */ + if (mode) + POWERCFG_BITSET_SKMODE_HIGH(&Si4709_dev.registers[POWERCFG]); + else + POWERCFG_BITSET_SKMODE_LOW(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_SEEK_HIGH(&Si4709_dev.registers[POWERCFG]); POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); diff --git a/drivers/samsung/fm_si4709/Si4709_dev.h b/drivers/samsung/fm_si4709/Si4709_dev.h index 8b8371f..7a0ba73 100644 --- a/drivers/samsung/fm_si4709/Si4709_dev.h +++ b/drivers/samsung/fm_si4709/Si4709_dev.h @@ -147,6 +147,8 @@ struct Si4709_device_t { /*will be true is the client ans state fields are correct */ unsigned short valid_client_state; + + u8 vol_idx; }; extern int Si4709_dev_wait_flag; @@ -174,6 +176,7 @@ extern int Si4709_dev_init(struct i2c_client *); extern int Si4709_dev_exit(void); extern void Si4709_dev_mutex_init(void); +extern void Si4709_dev_mutex_destroy(void); extern int Si4709_dev_suspend(void); extern int Si4709_dev_resume(void); diff --git a/drivers/samsung/fm_si4709/Si4709_main.c b/drivers/samsung/fm_si4709/Si4709_main.c index 5531c12..c0fcbfc 100644 --- a/drivers/samsung/fm_si4709/Si4709_main.c +++ b/drivers/samsung/fm_si4709/Si4709_main.c @@ -182,6 +182,20 @@ static long Si4709_ioctl(struct file *filp, unsigned int ioctl_cmd, } break; + case Si4709_IOC_SEEK_FULL: + { + u32 frequency = 0; + debug("Si4709_IOC_SEEK_FULL called\n"); + + ret = (long)Si4709_dev_seek_full(&frequency); + if (ret < 0) + debug("Si4709_IOC_SEEK_FULL failed\n"); + else if (copy_to_user + (argp, (void *)&frequency, sizeof(u32))) + ret = -EFAULT; + } + break; + case Si4709_IOC_SEEK_UP: { u32 frequency = 0; diff --git a/drivers/samsung/fm_si47xx/Makefile b/drivers/samsung/fm_si47xx/Makefile new file mode 100644 index 0000000..33a4e59 --- /dev/null +++ b/drivers/samsung/fm_si47xx/Makefile @@ -0,0 +1,7 @@ +ifeq ($(CONFIG_FM_SI4705),y) +obj-$(CONFIG_FM_SI4705) += si47xx-drv.o +si47xx-drv-y := Si47xx_i2c_drv.o Si47xx_dev.o +else +obj-$(CONFIG_FM_SI4705) += Si4709_driver.o +Si4709_driver-y := Si47xx_i2c_drv.o Si47xx_dev.o +endif
\ No newline at end of file diff --git a/drivers/samsung/fm_si47xx/Si47xx_dev.c b/drivers/samsung/fm_si47xx/Si47xx_dev.c new file mode 100644 index 0000000..bf64915 --- /dev/null +++ b/drivers/samsung/fm_si47xx/Si47xx_dev.c @@ -0,0 +1,1791 @@ +/* drivers/samsung/fm_si47xx/Si47xx_dev.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/kernel.h> +#include <linux/i2c.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/time.h> +#include <linux/workqueue.h> +#include <linux/interrupt.h> + +#include <mach/gpio.h> +#include <plat/gpio-cfg.h> + +#include "Si47xx_dev.h" +#include <linux/i2c/si47xx_common.h> + +#include "commanddefs.h" +#include "propertydefs.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 TUNE_RSSI_THRESHOLD 10 +#define TUNE_SNR_THRESHOLD 4 +#define TUNE_CNT_THRESHOLD 0x00 + +#define _ENABLE_RDS_ + +#ifdef RDS_INTERRUPT_ON_ALWAYS +#define RDS_BUFFER_LENGTH 50 +static u16 *RDS_Block_Data_buffer; +static u8 *RDS_Block_Error_buffer; +static u8 RDS_Buffer_Index_read; /* index number for last read data */ +static u8 RDS_Buffer_Index_write; /* index number for last written data */ + +int Si47xx_RDS_flag; +int RDS_Data_Available; +int RDS_Data_Lost; +int RDS_Groups_Available_till_now; +struct workqueue_struct *Si47xx_wq; +struct work_struct Si47xx_work; +#endif + +/*Si47xx device structure*/ +static struct Si47xx_device_t *Si47xx_dev; +static struct si47xx_platform_data *pSi47xxdata; + +static int si47xx_irq; +wait_queue_head_t Si47xx_waitq; + +/*Wait flag*/ +/*WAITING or WAIT_OVER or NO_WAIT*/ +int Si47xx_dev_wait_flag = NO_WAIT; +#ifdef RDS_INTERRUPT_ON_ALWAYS +int Si47xx_RDS_flag = NO_WAIT; +#endif + +static irqreturn_t Si47xx_isr(int irq, void *unused) +{ + debug("Si47xx_isr: FM device called IRQ: %d\n", irq); +#ifdef RDS_INTERRUPT_ON_ALWAYS + if ((Si47xx_dev_wait_flag == SEEK_WAITING) || + (Si47xx_dev_wait_flag == TUNE_WAITING)) { + debug("Si47xx_isr: FM Seek/Tune Interrupt " + "called IRQ %d\n", irq); + Si47xx_dev_wait_flag = WAIT_OVER; + wake_up_interruptible(&Si47xx_waitq); + } else if (Si47xx_RDS_flag == RDS_WAITING) { /* RDS Interrupt */ + debug_rds("Si47xx_isr: FM RDS Interrupt " + "called IRQ %d", irq); + + debug_rds("RDS_Groups_Available_till_now b/w " + "Power ON/OFF : %d", + RDS_Groups_Available_till_now); + + if (!work_pending(&Si47xx_work)) + queue_work(Si47xx_wq, &Si47xx_work); + } +#else + if ((Si47xx_dev_wait_flag == SEEK_WAITING) || + (Si47xx_dev_wait_flag == TUNE_WAITING) || + (Si47xx_dev_wait_flag == RDS_WAITING)) { + Si47xx_dev_wait_flag = WAIT_OVER; + wake_up_interruptible(&Si47xx_waitq); + } +#endif + return IRQ_HANDLED; +} + + +/*----------------------------------------------------------------------------- + This command returns the status +-----------------------------------------------------------------------------*/ +static u8 si47xx_readStatus(void) +{ + u8 status; + int ret = 0; + ret = i2c_master_recv((struct i2c_client *)(Si47xx_dev->client), + &status, 1); + + if (ret < 0) { + dev_err(Si47xx_dev->dev, "%s si47xx_readStatus failed %d\n", + __func__, ret); + + return ret; + } + + return status; +} + + +/*----------------------------------------------------------------------------- + Command that will wait for CTS before returning +-----------------------------------------------------------------------------*/ +static void si47xx_waitForCTS(void) +{ + u16 i = 1000; + u8 rStatus = 0; + + do { + rStatus = si47xx_readStatus(); + usleep_range(5, 10); + } while (--i && !(rStatus & CTS)); +} + +/*----------------------------------------------------------------------------- + Sends a command to the part and returns the reply bytes +-----------------------------------------------------------------------------*/ +static int si47xx_command(u8 cmd_size, u8 *cmd, u8 reply_size, u8 *reply) +{ + int ret = 0; + ret = i2c_master_send((struct i2c_client *)(Si47xx_dev->client), + cmd, cmd_size); + if (ret < 0) { + dev_err(Si47xx_dev->dev, "%s si47xx_command failed %d\n", + __func__, ret); + + return ret; + } + si47xx_waitForCTS(); + + if (reply_size) { + ret = i2c_master_recv((struct i2c_client *)(Si47xx_dev->client), + reply, reply_size); + + if (ret < 0) + dev_err(Si47xx_dev->dev, + "%s si47xx_command failed %d\n", __func__, ret); + + return ret; + } + + return ret; +} + +/*----------------------------------------------------------------------------- + Set the passed property number to the passed value. + + Inputs: + propNumber: The number identifying the property to set + propValue: The value of the property. +-----------------------------------------------------------------------------*/ +static void si47xx_set_property(u16 propNumber, u16 propValue) +{ + u8 cmd[8]; + int ret = 0; + + cmd[0] = SET_PROPERTY; + cmd[1] = 0; + cmd[2] = (u8)(propNumber >> 8); + cmd[3] = (u8)(propNumber & 0x00FF); + cmd[4] = (u8)(propValue >> 8); + cmd[5] = (u8)(propValue & 0x00FF); + + ret = si47xx_command(6, cmd, 0, NULL); + + if (ret < 0) + dev_err(Si47xx_dev->dev, + "%s si47xx_set_property failed %d\n", __func__, ret); +} + +static int powerup(void) +{ + int ret = 0; + u8 cmd[8]; + u8 rsp[13]; + + pSi47xxdata->power(1); + + cmd[0] = POWER_UP; + cmd[1] = POWER_UP_IN_GPO2OEN | POWER_UP_IN_FUNC_FMRX; + cmd[2] = POWER_UP_IN_OPMODE_RX_ANALOG; + ret = si47xx_command(3, cmd, 8, rsp); + + if (ret < 0) { + dev_err(Si47xx_dev->dev, "%s failed %d\n", __func__, ret); + } else { + /* Si4709/09 datasheet: Table 7 */ + msleep(110); + Si47xx_dev->state.power_state = RADIO_ON; + } + return ret; +} + +static int powerdown(void) +{ + int ret = 0; + u8 cmd[8]; + u8 rsp[13]; + + if (!(RADIO_POWERDOWN == Si47xx_dev->state.power_state)) { + cmd[0] = POWER_DOWN; + ret = si47xx_command(1, cmd, 1, rsp); + + if (ret < 0) + dev_err(Si47xx_dev->dev, "%s failed %d\n", + __func__, ret); + else + Si47xx_dev->state.power_state = RADIO_POWERDOWN; + + msleep(110); + pSi47xxdata->power(0); + } else + debug("Device already Powered-OFF\n"); + + return ret; +} + +/*----------------------------------------------------------------------------- + Helper function that sends the GET_INT_STATUS command to the part + + Returns: + The status byte from the part. +-----------------------------------------------------------------------------*/ +static s8 getIntStatus(void) +{ + u8 cmd[8]; + u8 rsp[13]; + int ret = 0; + cmd[0] = GET_INT_STATUS; + ret = si47xx_command(1, cmd, 1, rsp); + + if (ret < 0) { + dev_err(Si47xx_dev->dev, "%s getIntStatus failed %d\n", + __func__, ret); + return ret; + } + return rsp[0]; +} + +/*----------------------------------------------------------------------------- + Helper function that sends the FM_SEEK_START command to the part + +Inputs: +seekUp: If non-zero seek will increment otherwise decrement +wrap: If non-zero seek will wrap around band limits when hitting the end +of the band limit. +-----------------------------------------------------------------------------*/ +static int fmSeekStart(u8 seekUp, u8 wrap) +{ + u8 cmd[8]; + u8 rsp[13]; + int ret; + + cmd[0] = FM_SEEK_START; + cmd[1] = 0; + if (seekUp) + cmd[1] |= FM_SEEK_START_IN_SEEKUP; + if (wrap) + cmd[1] |= FM_SEEK_START_IN_WRAP; + + ret = si47xx_command(2, cmd, 1, rsp); + return ret; + +} + +static u16 freq_to_channel(u32 frequency) +{ + u16 channel; + + if (frequency < Si47xx_dev->settings.bottom_of_band) + frequency = Si47xx_dev->settings.bottom_of_band; + + channel = (frequency - Si47xx_dev->settings.bottom_of_band) + / Si47xx_dev->settings.channel_spacing; + + return channel; +} + +/* Only one thread will be able to call this, since this function call is + protected by a mutex, so no race conditions can arise */ +static void wait(void) +{ + wait_event_interruptible(Si47xx_waitq, + (Si47xx_dev_wait_flag == WAIT_OVER) || + (Si47xx_dev_wait_flag == SEEK_CANCEL)); +} + +#ifndef RDS_INTERRUPT_ON_ALWAYS +static void wait_RDS(void) +{ + wait_event_interruptible_timeout(Si47xx_waitq, + (Si47xx_dev_wait_flag == WAIT_OVER), + Si47xx_dev->settings.timeout_RDS); +} +#endif + +/*----------------------------------------------------------------------------- + Helper function that sends the FM_TUNE_FREQ command to the part + + Inputs: + frequency in 10kHz steps +-----------------------------------------------------------------------------*/ +static int fmTuneFreq(u16 frequency) +{ + u8 cmd[8]; + u8 rsp[13]; + int ret; + + cmd[0] = FM_TUNE_FREQ; + cmd[1] = 0; + cmd[2] = (u8)(frequency >> 8); + cmd[3] = (u8)(frequency & 0x00FF); + cmd[4] = (u8)0; + ret = si47xx_command(5, cmd, 1, rsp); + + return ret; +} + +/*----------------------------------------------------------------------------- + Helper function that sends the FM_TUNE_STATUS command to the part + + Inputs: + cancel: If non-zero the current seek will be cancelled. + intack: If non-zero the interrupt for STCINT will be cleared. + +Outputs: These are global variables and are set by this method +STC: The seek/tune is complete +BLTF: The seek reached the band limit or original start frequency +AFCRL: The AFC is railed if this is non-zero +Valid: The station is valid if this is non-zero +Freq: The current frequency +RSSI: The RSSI level read at tune. +ASNR: The audio SNR level read at tune. +AntCap: The current level of the tuning capacitor. +-----------------------------------------------------------------------------*/ + +static int fmTuneStatus(u8 cancel, u8 intack, struct tune_data_t *tune_data) +{ + u8 cmd[8]; + u8 rsp[13]; + int ret; + + cmd[0] = FM_TUNE_STATUS; + cmd[1] = 0; + if (cancel) + cmd[1] |= FM_TUNE_STATUS_IN_CANCEL; + if (intack) + cmd[1] |= FM_TUNE_STATUS_IN_INTACK; + + ret = si47xx_command(2, cmd, 8, rsp); + + tune_data->stc = !!(rsp[0] & STCINT); + tune_data->bltf = !!(rsp[1] & FM_TUNE_STATUS_OUT_BTLF); + tune_data->afcrl = !!(rsp[1] & FM_TUNE_STATUS_OUT_AFCRL); + tune_data->valid = !!(rsp[1] & FM_TUNE_STATUS_OUT_VALID); + tune_data->freq = ((u16)rsp[2] << 8) | (u16)rsp[3]; + tune_data->rssi = rsp[4]; + tune_data->asnr = rsp[5]; + tune_data->antcap = rsp[7]; + + return ret; +} + +/* ----------------------------------------------------------------------------- + Helper function that sends the FM_RSQ_STATUS command to the part + + Inputs: + intack: If non-zero the interrupt for STCINT will be cleared. + + Outputs: + Si47xx_status.Status: Contains bits about the status returned from the part. + Si47xx_status.RsqInts: Contains bits about the interrupts + that have fired related to RSQ. + SMUTE: The soft mute function is currently enabled + AFCRL: The AFC is railed if this is non-zero + Valid: The station is valid if this is non-zero + Pilot: A pilot tone is currently present + Blend: Percentage of blend for stereo. (100 = full stereo) + RSSI: The RSSI level read at tune. + ASNR: The audio SNR level read at tune. + FreqOff: The frequency offset in kHz of the current station + from the tuned frequency. +-----------------------------------------------------------------------------*/ +static void fmRsqStatus(u8 intack, struct rsq_data_t *rsq_data) +{ + u8 cmd[8]; + u8 rsp[13]; + + cmd[0] = FM_RSQ_STATUS; + cmd[1] = 0; + + if (intack) + cmd[1] |= FM_RSQ_STATUS_IN_INTACK; + + si47xx_command(2, cmd, 8, rsp); + + rsq_data->rsqints = rsp[1]; + rsq_data->smute = !!(rsp[2] & FM_RSQ_STATUS_OUT_SMUTE); + rsq_data->afcrl = !!(rsp[2] & FM_RSQ_STATUS_OUT_AFCRL); + rsq_data->valid = !!(rsp[2] & FM_RSQ_STATUS_OUT_VALID); + rsq_data->pilot = !!(rsp[3] & FM_RSQ_STATUS_OUT_PILOT); + rsq_data->blend = rsp[3] & FM_RSQ_STATUS_OUT_STBLEND; + rsq_data->rssi = rsp[4]; + rsq_data->snr = rsp[5]; + rsq_data->freqoff = rsp[7]; +} + +/*----------------------------------------------------------------------------- + Helper function that sends the FM_RDS_STATUS command to the part + + Inputs: + intack: If non-zero the interrupt for STCINT will be cleared. + mtfifo: If non-zero the fifo will be cleared. + +Outputs: +Status: Contains bits about the status returned from the part. +RdsInts: Contains bits about the interrupts that have fired +related to RDS. +RdsSync: If non-zero the RDS is currently synced. +GrpLost: If non-zero some RDS groups were lost. +RdsFifoUsed: The amount of groups currently remaining +in the RDS fifo. +BlockA: Block A group data from the oldest FIFO entry. +BlockB: Block B group data from the oldest FIFO entry. +BlockC: Block C group data from the oldest FIFO entry. +BlockD: Block D group data from the oldest FIFO entry. +BleA: Block A corrected error information. +BleB: Block B corrected error information. +BleC: Block C corrected error information. +BleD: Block D corrected error information. +-----------------------------------------------------------------------------*/ +static void fmRdsStatus(u8 intack, u8 mtfifo, struct radio_data_t *rds_data, + u8 *RdsFifoUsed) +{ + u8 cmd[8]; + u8 rsp[13]; + int ret = 0; + + cmd[0] = FM_RDS_STATUS; + cmd[1] = 0; + if (intack) + cmd[1] |= FM_RDS_STATUS_IN_INTACK; + if (mtfifo) + cmd[1] |= FM_RDS_STATUS_IN_MTFIFO; + + ret = si47xx_command(2, cmd, 13, rsp); + if (ret < 0) { + dev_err(Si47xx_dev->dev, "%s fmRdsStatusfailed %d\n", + __func__, ret); + return; + } + + *RdsFifoUsed = rsp[3]; + rds_data->rdsa = ((u16)rsp[4] << 8) | (u16)rsp[5]; + rds_data->rdsb = ((u16)rsp[6] << 8) | (u16)rsp[7]; + rds_data->rdsc = ((u16)rsp[8] << 8) | (u16)rsp[9]; + rds_data->rdsd = ((u16)rsp[10] << 8) | (u16)rsp[11]; + rds_data->blera = (rsp[12] & FM_RDS_STATUS_OUT_BLEA) >> + FM_RDS_STATUS_OUT_BLEA_SHFT; + rds_data->blerb = (rsp[12] & FM_RDS_STATUS_OUT_BLEB) >> + FM_RDS_STATUS_OUT_BLEB_SHFT; + rds_data->blerc = (rsp[12] & FM_RDS_STATUS_OUT_BLEC) >> + FM_RDS_STATUS_OUT_BLEC_SHFT; + rds_data->blerd = (rsp[12] & FM_RDS_STATUS_OUT_BLED) >> + FM_RDS_STATUS_OUT_BLED_SHFT; +} + +static int seek(u32 *frequency, int up, int mode) +{ + int ret = 0; + struct tune_data_t tune_data; + + Si47xx_dev_wait_flag = SEEK_WAITING; + ret = fmSeekStart(up, mode); /* mode 0 is full scan */ + wait(); + + if (Si47xx_dev_wait_flag == SEEK_CANCEL) { + ret = fmTuneStatus(1, 1, &tune_data); + + *frequency = 0; + + Si47xx_dev_wait_flag = NO_WAIT; + + return ret; + } + + Si47xx_dev_wait_flag = NO_WAIT; + + if (!(getIntStatus() & STCINT)) { + dev_err(Si47xx_dev->dev, "%s seek is failed!\n", __func__); + fmTuneStatus(1, 1, &tune_data); + return -1; + } + + ret = fmTuneStatus(0, 1, &tune_data); + if (tune_data.bltf != 1) + *frequency = tune_data.freq; + + else { + if (tune_data.valid) + *frequency = tune_data.freq; + else + *frequency = 0; + } + return ret; +} + +static int tune_freq(u32 frequency) +{ + int ret = 0; + + u16 channel = 0; + struct tune_data_t tune_data; + mutex_lock(&(Si47xx_dev->lock)); + + channel = freq_to_channel(frequency); + + Si47xx_dev_wait_flag = TUNE_WAITING; + ret = fmTuneFreq(frequency); + wait(); + Si47xx_dev_wait_flag = NO_WAIT; + debug("Si47xx_dev_wait_flag = TUNE_WAITING\n"); + + if (!(getIntStatus() & STCINT)) { + dev_err(Si47xx_dev->dev, "%s tune is failed!\n", __func__); + fmTuneStatus(1, 1, &tune_data); + mutex_unlock(&(Si47xx_dev->lock)); + return -1; + } + + ret = fmTuneStatus(0, 1, &tune_data); + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + + +int Si47xx_dev_init(struct Si47xx_device_t *si47xx_dev) +{ + int ret = 0; + Si47xx_dev = si47xx_dev; + Si47xx_dev->client = si47xx_dev->client; + pSi47xxdata = si47xx_dev->pdata; + si47xx_irq = Si47xx_dev->client->irq; + + debug("Si47xx_dev_init called"); + + mutex_lock(&Si47xx_dev->lock); + + Si47xx_dev->state.power_state = RADIO_POWERDOWN; + Si47xx_dev->state.seek_state = RADIO_SEEK_OFF; + Si47xx_dev->valid_client_state = eTRUE; + Si47xx_dev->valid = eFALSE; + +#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) { + dev_err(Si47xx_dev->dev, "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) { + dev_err(Si47xx_dev->dev, "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 */ + Si47xx_wq = create_singlethread_workqueue("Si47xx_wq"); + if (!Si47xx_wq) { + dev_err(Si47xx_dev->dev, "Not sufficient memory for Si47xx_wq, work-queue"); + ret = -ENOMEM; + kfree(RDS_Block_Error_buffer); + kfree(RDS_Block_Data_buffer); + goto EXIT; + } + + /*Initialising work_queue */ + INIT_WORK(&Si47xx_work, Si47xx_work_func); + + RDS_Data_Available = 0; + RDS_Data_Lost = 0; + RDS_Groups_Available_till_now = 0; +EXIT: +#endif + + mutex_unlock(&(Si47xx_dev->lock)); + + debug("Si47xx_dev_init call over"); + + return ret; +} + +int Si47xx_dev_exit(void) +{ + int ret = 0; + + debug("Si47xx_dev_exit called"); + + mutex_lock(&(Si47xx_dev->lock)); +#ifdef RDS_INTERRUPT_ON_ALWAYS + if (Si47xx_wq) + destroy_workqueue(Si47xx_wq); + + kfree(RDS_Block_Error_buffer); + kfree(RDS_Block_Data_buffer); +#endif + + mutex_unlock(&(Si47xx_dev->lock)); + + debug("Si47xx_dev_exit call over"); + + return ret; +} + +int Si47xx_dev_powerup(void) +{ + int ret = 0; + u32 value = 100; + + debug("Si47xx_dev_powerup called"); + + if (!(RADIO_ON == Si47xx_dev->state.power_state)) { + ret = powerup(); + if (ret < 0) { + dev_err(Si47xx_dev->dev, "%s failed %d\n", + __func__, ret); + } else if (Si47xx_dev->valid_client_state == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_powerup called " + "when DS(state, client) is invalid"); + ret = -1; + } else { +/* initial settings */ +#ifdef _ENABLE_RDS_ + si47xx_set_property(FM_RDS_CONFIG, 1); + si47xx_set_property(GPO_IEN, GPO_IEN_STCIEN_MASK | + GPO_IEN_STCREP_MASK); + si47xx_set_property(GPO_IEN, GPO_IEN_STCIEN_MASK | + GPO_IEN_RDSIEN_MASK | GPO_IEN_STCREP_MASK); + si47xx_set_property(FM_RDS_INTERRUPT_SOURCE, + FM_RDS_INTERRUPT_SOURCE_RECV_MASK); + si47xx_set_property(FM_RDS_CONFIG, + FM_RDS_CONFIG_RDSEN_MASK | + (3 << FM_RDS_CONFIG_BLETHA_SHFT) | + (3 << FM_RDS_CONFIG_BLETHB_SHFT) | + (3 << FM_RDS_CONFIG_BLETHC_SHFT) | + (3 << FM_RDS_CONFIG_BLETHD_SHFT)); +#endif +/*VNVS:18-NOV'09 : Setting DE-Time Constant as 50us(Europe,Japan,Australia)*/ + si47xx_set_property(FM_DEEMPHASIS, FM_DEEMPH_50US); + /* SYSCONFIG2_BITSET_SEEKTH( */ + /* &Si47xx_dev->registers[SYSCONFIG2],2); */ +/*VNVS:18-NOV'09 : modified for detecting more stations of good quality*/ + si47xx_set_property(FM_SEEK_TUNE_RSSI_THRESHOLD, + TUNE_RSSI_THRESHOLD); + si47xx_set_property(FM_SEEK_BAND_BOTTOM, 8750); + si47xx_set_property(FM_SEEK_BAND_TOP, 10800); + Si47xx_dev->settings.band = BAND_87500_108000_kHz; + Si47xx_dev->settings.bottom_of_band = FREQ_87500_kHz; + si47xx_set_property(FM_SEEK_FREQ_SPACING, + CHAN_SPACING_100_kHz); + Si47xx_dev->settings.channel_spacing = + CHAN_SPACING_100_kHz; + + /* SYSCONFIG3_BITSET_SKSNR( */ + /* &Si47xx_dev->registers[SYSCONFIG3],3); */ +/*VNVS:18-NOV'09 : modified for detecting more stations of good quality*/ + si47xx_set_property(FM_SEEK_TUNE_SNR_THRESHOLD, + TUNE_SNR_THRESHOLD); + Si47xx_dev->settings.timeout_RDS = + msecs_to_jiffies(value); + Si47xx_dev->settings.curr_snr = TUNE_SNR_THRESHOLD; + Si47xx_dev->settings.curr_rssi_th = TUNE_RSSI_THRESHOLD; + Si47xx_dev->valid = eTRUE; + + Si47xx_dev_STEREO_SET(); +#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"); + + ret = request_irq(si47xx_irq, Si47xx_isr, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "Si47xx", NULL); + si47xx_set_property(0xff00, 0); + + /* tune initial frequency to remove tunestatus func err + * sometimes occur tunestatus func err when execute tunestatus function + * before to complete tune_freq. + * so run tune_freq just after to complete booting sequence*/ + ret = tune_freq(Si47xx_dev->settings.bottom_of_band); + + return ret; +} + +int Si47xx_dev_powerdown(void) +{ + int ret = 0; + + msleep(500); /* For avoiding turned off pop noise */ + debug("Si47xx_dev_powerdown called"); + + mutex_lock(&(Si47xx_dev->lock)); + + free_irq(si47xx_irq, NULL); + + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_powerdown called when DS is invalid"); + ret = -1; + } else { + ret = powerdown(); + if (ret < 0) + dev_err(Si47xx_dev->dev, "%s failed %d\n", + __func__, ret); + } + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_suspend(void) +{ + int ret = 0; + + debug("Si47xx_dev_suspend called"); + +#ifndef _ENABLE_RDS_ + disable_irq(si47xx_irq); +#endif + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid_client_state == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_suspend called " + "when DS(state, client) is invalid"); + ret = -1; + } + mutex_unlock(&(Si47xx_dev->lock)); + + debug("Si47xx_dev_enable call over"); + + return ret; +} + +int Si47xx_dev_resume(void) +{ + int ret = 0; + + debug("Si47xx_dev_resume called"); + +#ifndef _ENABLE_RDS_ + enable_irq(si47xx_irq); +#endif + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid_client_state == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_resume called " + "when DS(state, client) is invalid"); + ret = -1; + } + + mutex_unlock(&(Si47xx_dev->lock)); + debug("Si47xx_dev_disable call over"); + + return ret; +} + +int Si47xx_dev_band_set(int band) +{ + int ret = 0; + u16 prev_band = 0; + u32 prev_bottom_of_band = 0; + + debug("Si47xx_dev_band_set called"); + + prev_band = Si47xx_dev->settings.band; + prev_bottom_of_band = Si47xx_dev->settings.bottom_of_band; + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_band_set called when DS is invalid"); + ret = -1; + } else { + switch (band) { + case BAND_87500_108000_kHz: + si47xx_set_property(FM_SEEK_BAND_BOTTOM, 8750); + si47xx_set_property(FM_SEEK_BAND_TOP, 10800); + Si47xx_dev->settings.band = BAND_87500_108000_kHz; + Si47xx_dev->settings.bottom_of_band = FREQ_87500_kHz; + break; + case BAND_76000_108000_kHz: + si47xx_set_property(FM_SEEK_BAND_BOTTOM, 7600); + si47xx_set_property(FM_SEEK_BAND_TOP, 10800); + Si47xx_dev->settings.band = BAND_76000_108000_kHz; + Si47xx_dev->settings.bottom_of_band = FREQ_76000_kHz; + break; + case BAND_76000_90000_kHz: + si47xx_set_property(FM_SEEK_BAND_BOTTOM, 7600); + si47xx_set_property(FM_SEEK_BAND_TOP, 9000); + Si47xx_dev->settings.band = BAND_76000_90000_kHz; + Si47xx_dev->settings.bottom_of_band = FREQ_76000_kHz; + break; + default: + ret = -1; + } + } + + return ret; +} + +int Si47xx_dev_ch_spacing_set(int ch_spacing) +{ + int ret = 0; + u16 prev_ch_spacing = 0; + + debug("Si47xx_dev_ch_spacing_set called"); + + mutex_lock(&(Si47xx_dev->lock)); + prev_ch_spacing = Si47xx_dev->settings.channel_spacing; + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_ch_spacing_set called " + "when DS is invalid"); + ret = -1; + } else { + switch (ch_spacing) { + case CHAN_SPACING_200_kHz: + si47xx_set_property(FM_SEEK_FREQ_SPACING, 20); + Si47xx_dev->settings.channel_spacing = + CHAN_SPACING_200_kHz; + break; + + case CHAN_SPACING_100_kHz: + si47xx_set_property(FM_SEEK_FREQ_SPACING, 10); + Si47xx_dev->settings.channel_spacing = + CHAN_SPACING_100_kHz; + break; + + case CHAN_SPACING_50_kHz: + si47xx_set_property(FM_SEEK_FREQ_SPACING, 5); + Si47xx_dev->settings.channel_spacing = + CHAN_SPACING_50_kHz; + break; + + default: + ret = -1; + } + + if (ret == 0) { + if (ret < 0) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_ch_spacing_set " + "i2c_write 1 failed"); + Si47xx_dev->settings.channel_spacing = + prev_ch_spacing; + } + } + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_chan_select(u32 frequency) +{ + int ret = 0; + + debug("Si47xx_dev_chan_select called"); + + if (Si47xx_dev->valid == eFALSE) { + debug("Si47xx_dev_chan_select called when DS is invalid"); + ret = -1; + } else { + Si47xx_dev->state.seek_state = RADIO_SEEK_ON; + + ret = tune_freq(frequency); + debug("Si47xx_dev_chan_select called1"); + Si47xx_dev->state.seek_state = RADIO_SEEK_OFF; + } + return ret; +} + +int Si47xx_dev_chan_get(u32 *frequency) +{ + int ret = 0; + struct tune_data_t tune_data; + + debug("Si47xx_dev_chan_get called\n"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_chan_get called when DS is invalid"); + ret = -1; + } else { + if (ret < 0) + debug("Si47xx_dev_chan_get i2c_read failed"); + else { + ret = fmTuneStatus(0, 1, &tune_data); + *frequency = tune_data.freq; + } + } + mutex_unlock(&(Si47xx_dev->lock)); + return ret; +} + +int Si47xx_dev_seek_full(u32 *frequency) +{ + int ret = 0; + + debug("Si47xx_dev_seek_full called\n"); + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_seek_full called when DS is invalid"); + ret = -1; + } else { + Si47xx_dev->state.seek_state = RADIO_SEEK_ON; + ret = seek(frequency, 1, 0); + Si47xx_dev->state.seek_state = RADIO_SEEK_OFF; + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_seek_up(u32 *frequency) +{ + int ret = 0; + + debug("Si47xx_dev_seek_up called\n"); + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_seek_up called when DS is invalid"); + ret = -1; + } else { + Si47xx_dev->state.seek_state = RADIO_SEEK_ON; + ret = seek(frequency, 1, 1); + Si47xx_dev->state.seek_state = RADIO_SEEK_OFF; + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_seek_down(u32 *frequency) +{ + int ret = 0; + + debug("Si47xx_dev_seek_down called\n"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + debug("Si47xx_dev_seek_down called when DS is invalid"); + ret = -1; + } else { + Si47xx_dev->state.seek_state = RADIO_SEEK_ON; + + ret = seek(frequency, 0, 1); + + Si47xx_dev->state.seek_state = RADIO_SEEK_OFF; + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_RSSI_seek_th_set(u8 seek_th) +{ + int ret = 0; + + debug("Si47xx_dev_RSSI_seek_th_set called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + debug("Si47xx_dev_RSSI_seek_th_set called " + "when DS is invalid"); + ret = -1; + } else { + si47xx_set_property(FM_SEEK_TUNE_RSSI_THRESHOLD, seek_th); + Si47xx_dev->settings.curr_rssi_th = seek_th; + if (ret < 0) + debug("Si47xx_dev_RSSI_seek_th_set i2c_write 1 failed"); + } + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_seek_SNR_th_set(u8 seek_SNR) +{ + int ret = 0; + + debug("Si47xx_dev_seek_SNR_th_set called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_seek_SNR_th_set called " + "when DS is invalid"); + ret = -1; + } else { + si47xx_set_property(FM_SEEK_TUNE_SNR_THRESHOLD, seek_SNR); + Si47xx_dev->settings.curr_snr = seek_SNR; + + if (ret < 0) + debug("Si47xx_dev_seek_SNR_th_set i2c_write 1 failed"); + } + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +/*ToDo Don't use anymore*/ +int Si47xx_dev_seek_FM_ID_th_set(u8 seek_FM_ID_th) +{ + int ret = 0; + + debug("Si47xx_dev_seek_FM_ID_th_set called"); + + return ret; +} + +int Si47xx_dev_cur_RSSI_get(struct rssi_snr_t *cur_RSSI) +{ + int ret = 0; + + struct rsq_data_t rsq_data; + debug("Si47xx_dev_cur_RSSI_get called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_cur_RSSI_get called when DS is invalid"); + ret = -1; + } else { + fmRsqStatus(0, &rsq_data); + cur_RSSI->curr_rssi = rsq_data.rssi; + cur_RSSI->curr_rssi_th = + Si47xx_dev->settings.curr_rssi_th; + cur_RSSI->curr_snr = rsq_data.snr; + + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +/*ToDo Don't use anymore*/ +int Si47xx_dev_device_id(struct device_id *dev_id) +{ + int ret = 0; + + debug("Si47xx_dev_device_id called"); + + return ret; +} + +/*ToDo Don't use anymore*/ +int Si47xx_dev_chip_id(struct chip_id *chp_id) +{ + int ret = 0; + + debug("Si47xx_dev_chip_id called"); + + return ret; +} + +int Si47xx_dev_sys_config2(struct sys_config2 *sys_conf2) +{ + int ret = 0; + + debug("Si4709_sys_config2 called\n"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si4709_sys_config2 called when DS is invalid"); + ret = -1; + } else { + sys_conf2->rssi_th = Si47xx_dev->settings.curr_rssi_th; + sys_conf2->fm_band = Si47xx_dev->settings.band; + sys_conf2->fm_chan_spac = + Si47xx_dev->settings.channel_spacing; + sys_conf2->fm_vol = 0; + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_sys_config3(struct sys_config3 *sys_conf3) +{ + int ret = 0; + + debug("Si4709_sys_config3 called\n"); + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si4709_sys_config3 called when DS is invalid"); + ret = -1; + } else { + sys_conf3->smmute = 0; + sys_conf3->smutea = 0; + sys_conf3->volext = 0; + sys_conf3->sksnr = Si47xx_dev->settings.curr_snr; + sys_conf3->skcnt = 0; + } + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_status_rssi(struct status_rssi *status) +{ + int ret = 0; + struct rsq_data_t rsq_data; + + debug("Si47xx_dev_status_rssi called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + debug("Si47xx_dev_status_rssi called when DS is invalid"); + mutex_unlock(&(Si47xx_dev->lock)); + return -1; + } + fmRsqStatus(0, &rsq_data); + + pr_debug("%s: Si47xx_dev_status_rssi %d\n", + __func__, rsq_data.rssi); + + Si47xx_dev->settings.curr_rssi = rsq_data.rssi; + status->rssi = rsq_data.rssi; + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_sys_config2_set(struct sys_config2 *sys_conf2) +{ + int ret = 0; + + debug("Si47xx_dev_sys_config2_set called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_sys_config2_set called when DS is invalid"); + ret = -1; + } else { + si47xx_set_property(FM_SEEK_TUNE_RSSI_THRESHOLD, + sys_conf2->rssi_th); + Si47xx_dev_band_set(sys_conf2->fm_band); + si47xx_set_property(FM_SEEK_FREQ_SPACING, + sys_conf2->fm_chan_spac); + Si47xx_dev->settings.curr_rssi_th = sys_conf2->rssi_th; + Si47xx_dev->settings.band = sys_conf2->fm_band; + Si47xx_dev->settings.channel_spacing = sys_conf2->fm_chan_spac; + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_sys_config3_set(struct sys_config3 *sys_conf3) +{ + int ret = 0; + + debug("Si47xx_dev_sys_config3_set called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_sys_config3_set called " + "when DS is invalid"); + ret = -1; + } else { + si47xx_set_property(FM_SEEK_TUNE_SNR_THRESHOLD, + sys_conf3->sksnr); + Si47xx_dev->settings.curr_snr = sys_conf3->sksnr; + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +/* VNVS:END */ + +/* VNVS:START 18-NOV'09 */ +/* Reading AFCRL Bit */ +int Si47xx_dev_AFCRL_get(u8 *afc) +{ + int ret = 0; + struct rsq_data_t rsq_data; + + debug("Si47xx_dev_AFCRL_get called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_AFCRL_get called when DS is invalid"); + ret = -1; + } else { + fmRsqStatus(0, &rsq_data); + *afc = rsq_data.afcrl; + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +/* Setting DE + emphasis time constant 50us(Europe,Japan,Australia) or 75us(USA) + */ +int Si47xx_dev_DE_set(u8 de_tc) +{ + int ret = 0; + + debug("Si47xx_dev_DE_set called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_DE_set called when DS is invalid"); + ret = -1; + } else { + switch (de_tc) { + case DE_TIME_CONSTANT_50: + si47xx_set_property(FM_DEEMPHASIS, FM_DEEMPH_50US); + break; + + case DE_TIME_CONSTANT_75: + si47xx_set_property(FM_DEEMPHASIS, FM_DEEMPH_75US); + break; + + default: + ret = -1; + } + + if (0 == ret) { + if (ret < 0) + dev_err(Si47xx_dev->dev, "%s failed %d\n", + __func__, ret); + } + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +/*Resetting the RDS Data Buffer*/ +int Si47xx_dev_reset_rds_data() +{ + int ret = 0; + + debug_rds("Si47xx_dev_reset_rds_data called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_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(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_volume_set(u8 volume) +{ + int ret = 0; + + debug("Si47xx_dev_volume_set called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_volume_set called when DS is invalid"); + ret = -1; + } else { + si47xx_set_property(RX_VOLUME, pSi47xxdata->rx_vol[volume] & + RX_VOLUME_MASK); + Si47xx_dev->vol_idx = volume; + + if (ret < 0) + dev_err(Si47xx_dev->dev, "%s failed %d\n", + __func__, ret); + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_volume_get(u8 *volume) +{ + int ret = 0; + + debug("Si4709_dev_volume_get called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + debug("Si4709_dev_volume_get called when DS is invalid"); + ret = -1; + } else + *volume = Si47xx_dev->vol_idx; + + mutex_unlock(&(Si47xx_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 Si47xx_dev_DSMUTE_ON(void) +{ + int ret = 0; + + debug("Si47xx_dev_DSMUTE_ON called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + debug("Si47xx_dev_DSMUTE_ON called when DS is invalid"); + ret = -1; + } else { + si47xx_set_property(FM_SOFT_MUTE_RATE, 64); + si47xx_set_property(FM_SOFT_MUTE_MAX_ATTENUATION, 0); + si47xx_set_property(FM_SOFT_MUTE_SNR_THRESHOLD, 4); + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_DSMUTE_OFF(void) +{ + int ret = 0; + + debug("Si47xx_dev_DSMUTE_OFF called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + debug("Si47xx_dev_DSMUTE_OFF called when DS is invalid"); + ret = -1; + } else { + si47xx_set_property(FM_SOFT_MUTE_RATE, 64); + si47xx_set_property(FM_SOFT_MUTE_MAX_ATTENUATION, 16); + si47xx_set_property(FM_SOFT_MUTE_SNR_THRESHOLD, 4); + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +/*VNVS:END*/ + +int Si47xx_dev_MUTE_ON(void) +{ + int ret = 0; + + debug("Si47xx_dev_MUTE_ON called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + debug("Si47xx_dev_MUTE_ON called when DS is invalid"); + ret = -1; + } else { + si47xx_set_property(RX_HARD_MUTE, + RX_HARD_MUTE_RMUTE_MASK | + RX_HARD_MUTE_LMUTE_MASK); + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_MUTE_OFF(void) +{ + int ret = 0; + + debug("Si47xx_dev_MUTE_OFF called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + debug("Si47xx_dev_MUTE_OFF called when DS is invalid"); + ret = -1; + } else { + si47xx_set_property(RX_HARD_MUTE, 0); + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_MONO_SET(void) +{ + int ret = 0; + + debug("Si47xx_dev_MONO_SET called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + debug("Si47xx_dev_MONO_SET called when DS is invalid"); + ret = -1; + } else { + si47xx_set_property(FM_BLEND_MONO_THRESHOLD, 127); + si47xx_set_property(FM_BLEND_STEREO_THRESHOLD, 127); + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_STEREO_SET(void) +{ + int ret = 0; + + debug("Si47xx_dev_STEREO_SET called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + debug("Si47xx_dev_STEREO_SET called when DS is invalid"); + ret = -1; + } else { + si47xx_set_property(FM_BLEND_MONO_THRESHOLD, 30); + si47xx_set_property(FM_BLEND_STEREO_THRESHOLD, 49); + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_RDS_ENABLE(void) +{ + int ret = 0; + + debug("Si47xx_dev_RDS_ENABLE called"); + + mutex_lock(&(Si47xx_dev->lock)); + if (Si47xx_dev->valid == eFALSE) { + debug("Si47xx_dev_RDS_ENABLE called when DS is invalid"); + ret = -1; + } else { +#ifdef RDS_INTERRUPT_ON_ALWAYS + si47xx_set_property(GPO_IEN, GPO_IEN_STCIEN_MASK | + GPO_IEN_STCREP_MASK | GPO_IEN_RDSIEN_MASK | + GPO_IEN_RDSREP_MASK); +#endif + si47xx_set_property(FM_RDS_INTERRUPT_SOURCE, + FM_RDS_INTERRUPT_SOURCE_RECV_MASK); + si47xx_set_property(FM_RDS_CONFIG, FM_RDS_CONFIG_RDSEN_MASK | + (3 << FM_RDS_CONFIG_BLETHA_SHFT) | + (3 << FM_RDS_CONFIG_BLETHB_SHFT) | + (3 << FM_RDS_CONFIG_BLETHC_SHFT) | + (3 << FM_RDS_CONFIG_BLETHD_SHFT)); +#ifdef RDS_INTERRUPT_ON_ALWAYS + Si47xx_RDS_flag = RDS_WAITING; +#endif + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_RDS_DISABLE(void) +{ + int ret = 0; + + debug("Si47xx_dev_RDS_DISABLE called"); + + mutex_lock(&(Si47xx_dev->lock)); + if (Si47xx_dev->valid == eFALSE) { + debug("Si47xx_dev_RDS_DISABLE called when DS is invalid"); + ret = -1; + } else { + si47xx_set_property(FM_RDS_CONFIG, 0); +#ifdef RDS_INTERRUPT_ON_ALWAYS + Si47xx_RDS_flag = NO_WAIT; +#endif + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_rstate_get(struct dev_state_t *dev_state) +{ + int ret = 0; + + debug("Si47xx_dev_rstate_get called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + debug("Si47xx_dev_rstate_get called when DS is invalid"); + ret = -1; + } else { + dev_state->power_state = Si47xx_dev->state.power_state; + dev_state->seek_state = Si47xx_dev->state.seek_state; + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +/* VNVS:START 7-JUNE'10 Function call for work-queue "Si47xx_wq" */ +#ifdef RDS_INTERRUPT_ON_ALWAYS +void Si47xx_work_func(struct work_struct *work) +{ + struct radio_data_t rds_data; + int i = 0; + u8 RdsFifoUsed; +#ifdef RDS_TESTING + u8 group_type; +#endif + debug_rds("%s", __func__); +mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_RDS_data_get called when DS is invalid"); + return; + } + + if (RDS_Data_Lost > 1) + debug_rds("No_of_RDS_groups_Lost till now : %d", + RDS_Data_Lost); + fmRdsStatus(1, 0, &rds_data, &RdsFifoUsed); + /* RDSR bit and RDS Block data, so reading the RDS registers */ + do { + /* Writing into RDS_Block_Data_buffer */ + i = 0; + RDS_Block_Data_buffer[i++ + 4 * RDS_Buffer_Index_write] = + rds_data.rdsa; + RDS_Block_Data_buffer[i++ + 4 * RDS_Buffer_Index_write] = + rds_data.rdsb; + RDS_Block_Data_buffer[i++ + 4 * RDS_Buffer_Index_write] = + rds_data.rdsc; + RDS_Block_Data_buffer[i++ + 4 * RDS_Buffer_Index_write] = + rds_data.rdsd; + + /*Writing into RDS_Block_Error_buffer */ + i = 0; + + RDS_Block_Error_buffer[i++ + 4 * RDS_Buffer_Index_write] = + rds_data.blera; + RDS_Block_Error_buffer[i++ + 4 * RDS_Buffer_Index_write] = + rds_data.blerb; + RDS_Block_Error_buffer[i++ + 4 * RDS_Buffer_Index_write] = + rds_data.blerc; + RDS_Block_Error_buffer[i++ + 4 * RDS_Buffer_Index_write] = + rds_data.blerd; + fmRdsStatus(1, 0, &rds_data, &RdsFifoUsed); + } while (RdsFifoUsed != 0); + +#ifdef RDS_TESTING + if (RDS_Block_Error_buffer + [0 + 4 * RDS_Buffer_Index_write] < 3) { + debug_rds("PI Code is %d", + RDS_Block_Data_buffer[0 + 4 + * RDS_Buffer_Index_write]); + } + if (RDS_Block_Error_buffer + [1 + 4 * RDS_Buffer_Index_write] < 2) { + group_type = RDS_Block_Data_buffer[1 + 4 + * RDS_Buffer_Index_write] >> 11; + + if (group_type & 0x01) { + debug_rds("PI Code is %d", + RDS_Block_Data_buffer[2 + 4 + * RDS_Buffer_Index_write]); + } + if (group_type == GROUP_TYPE_2A + || group_type == GROUP_TYPE_2B) { + if (RDS_Block_Error_buffer + [2 + 4 * RDS_Buffer_Index_write] < 3) { + debug_rds("Update RT with RDSC"); + } else { + debug_rds("RDS_Block_Error_buffer" + " of Block C is greater than 3"); + } + } + } +#endif + RDS_Buffer_Index_write++; + + if (RDS_Buffer_Index_write >= RDS_BUFFER_LENGTH) + RDS_Buffer_Index_write = 0; + + debug_rds("RDS_Buffer_Index_write = %d", RDS_Buffer_Index_write); + mutex_unlock(&(Si47xx_dev->lock)); +} +#endif +/*VNVS:END*/ + +int Si47xx_dev_RDS_data_get(struct radio_data_t *data) +{ + int i, ret = 0; + struct tune_data_t tune_data; + struct rsq_data_t rsq_data; + + debug_rds("Si47xx_dev_RDS_data_get called"); + + mutex_lock(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + dev_err(Si47xx_dev->dev, "Si47xx_dev_RDS_data_get called when DS is invalid"); + mutex_unlock(&(Si47xx_dev->lock)); + return -1; + } +#ifdef RDS_INTERRUPT_ON_ALWAYS + debug_rds("RDS_Buffer_Index_read = %d", RDS_Buffer_Index_read); + + /*If No New RDS Data is available return error */ + if (RDS_Buffer_Index_read == RDS_Buffer_Index_write) { + debug_rds("No_New_RDS_Data_is_available"); + ret = fmTuneStatus(0, 1, &tune_data); + data->curr_channel = tune_data.freq; + fmRsqStatus(0, &rsq_data); + data->curr_rssi = rsq_data.rssi; + debug_rds("curr_channel: %u, curr_rssi:%u", + data->curr_channel, + (u32) data->curr_rssi); + mutex_unlock(&(Si47xx_dev->lock)); + return -1; + } + + ret = fmTuneStatus(0, 1, &tune_data); + data->curr_channel = tune_data.freq; + fmRsqStatus(0, &rsq_data); + data->curr_rssi = rsq_data.rssi; + debug_rds("curr_channel: %u, curr_rssi:%u", + data->curr_channel, (u32) data->curr_rssi); + + /* Reading from RDS_Block_Data_buffer */ + i = 0; + data->rdsa = RDS_Block_Data_buffer[i++ + 4 + * RDS_Buffer_Index_read]; + data->rdsb = RDS_Block_Data_buffer[i++ + 4 + * RDS_Buffer_Index_read]; + data->rdsc = RDS_Block_Data_buffer[i++ + 4 + * RDS_Buffer_Index_read]; + data->rdsd = RDS_Block_Data_buffer[i++ + 4 + * RDS_Buffer_Index_read]; + + /* Reading from RDS_Block_Error_buffer */ + i = 0; + data->blera = RDS_Block_Error_buffer[i++ + 4 + * RDS_Buffer_Index_read]; + data->blerb = RDS_Block_Error_buffer[i++ + 4 + * RDS_Buffer_Index_read]; + data->blerc = RDS_Block_Error_buffer[i++ + 4 + * RDS_Buffer_Index_read]; + data->blerd = RDS_Block_Error_buffer[i++ + 4 + * RDS_Buffer_Index_read]; + + /*Flushing the read data */ + memset(&RDS_Block_Data_buffer[0 + 4 * RDS_Buffer_Index_read], + 0, 8); + memset(&RDS_Block_Error_buffer[0 + 4 * RDS_Buffer_Index_read], + 0, 4); + + RDS_Buffer_Index_read++; + + if (RDS_Buffer_Index_read >= RDS_BUFFER_LENGTH) + RDS_Buffer_Index_read = 0; + + debug_rds("RDS_Buffer_Index_read = %d", RDS_Buffer_Index_read); +#endif + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} + +int Si47xx_dev_RDS_timeout_set(u32 time_out) +{ + int ret = 0; + u32 jiffy_count = 0; + + debug("Si47xx_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(&(Si47xx_dev->lock)); + + if (Si47xx_dev->valid == eFALSE) { + debug("Si47xx_dev_RDS_timeout_set called when DS is invalid"); + ret = -1; + } else { + Si47xx_dev->settings.timeout_RDS = jiffy_count; + } + + mutex_unlock(&(Si47xx_dev->lock)); + + return ret; +} diff --git a/drivers/samsung/fm_si47xx/Si47xx_dev.h b/drivers/samsung/fm_si47xx/Si47xx_dev.h new file mode 100644 index 0000000..5d32304 --- /dev/null +++ b/drivers/samsung/fm_si47xx/Si47xx_dev.h @@ -0,0 +1,246 @@ +/* + * Si47xx_dev.h -- Si47xx FM Radio driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _Si47xx_dev_H +#define _Si47xx_dev_H + +#include <linux/i2c.h> + +#include <linux/i2c/si47xx_common.h> + +#define NUM_SEEK_PRESETS 20 + +#define WAIT_OVER 0 +#define SEEK_WAITING 1 +#define NO_WAIT 2 +#define TUNE_WAITING 4 +#define RDS_WAITING 5 +#define SEEK_CANCEL 6 + +/*dev settings*/ +/*band*/ +#define BAND_87500_108000_kHz 1 +#define BAND_76000_108000_kHz 2 +#define BAND_76000_90000_kHz 3 + +/*channel spacing*/ +#define CHAN_SPACING_200_kHz 20 /*US*/ +#define CHAN_SPACING_100_kHz 10 /*Europe,Japan */ +#define CHAN_SPACING_50_kHz 5 +/*DE-emphasis Time Constant*/ +#define DE_TIME_CONSTANT_50 1 /*Europe,Japan,Australia */ +#define DE_TIME_CONSTANT_75 0 /*US*/ +struct dev_state_t { + int power_state; + int seek_state; +}; + +struct rssi_snr_t { + u8 curr_rssi; + u8 curr_rssi_th; + u8 curr_snr; +}; + +struct device_id { + u8 part_number; + u16 manufact_number; +}; + +struct chip_id { + u8 chip_version; + u8 device; + u8 firmware_version; +}; + +struct sys_config2 { + u16 rssi_th; + u8 fm_band; + u8 fm_chan_spac; + u8 fm_vol; +}; + +struct sys_config3 { + u8 smmute; + u8 smutea; + u8 volext; + u8 sksnr; + u8 skcnt; +}; + +struct status_rssi { + u8 rdsr; + u8 stc; + u8 sfbl; + u8 afcrl; + u8 rdss; + u8 blera; + u8 st; + u16 rssi; +}; + +struct radio_data_t { + u16 rdsa; + u16 rdsb; + u16 rdsc; + u16 rdsd; + u8 curr_rssi; + u32 curr_channel; + u8 blera; + u8 blerb; + u8 blerc; + u8 blerd; +}; + +struct channel_into_t { + u32 frequency; + u8 rsssi_val; +}; + +struct tune_data_t { + u8 stc; + u8 bltf; + u8 afcrl; + u8 valid; + u16 freq; + u8 rssi; + u8 asnr; + u16 antcap; +}; + +struct rsq_data_t { + u8 rsqints; + u8 smute; + u8 afcrl; + u8 valid; + u8 pilot; + u8 blend; + u8 rssi; + u8 snr; + u8 mult; + u8 freqoff; +}; + +struct dev_settings_t { + u16 band; + u32 bottom_of_band; + u16 channel_spacing; + u32 timeout_RDS; /****For storing the jiffy value****/ + u32 seek_preset[NUM_SEEK_PRESETS]; + u8 curr_snr; + u8 curr_rssi_th; + u8 curr_rssi; +}; + +struct Si47xx_device_t { + /*Any function which + - views/modifies the fields of this structure + - does i2c communication + should lock the mutex before doing so. + Recursive locking should not be done. + In this file all the exported functions will take care + of this. The static functions will not deal with the + mutex */ + struct mutex lock; + struct si47xx_platform_data *pdata; + struct i2c_client *client; + struct device *dev; + struct dev_state_t state; + struct dev_settings_t settings; + struct channel_into_t rssi_freq[50]; + + /* 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; + u8 vol_idx; +}; + +extern int Si47xx_dev_wait_flag; +extern wait_queue_head_t Si4709_waitq; + +#ifdef RDS_INTERRUPT_ON_ALWAYS +extern int Si47xx_RDS_flag; +extern int RDS_Data_Available; +extern int RDS_Data_Lost; +extern int RDS_Groups_Available_till_now; +extern struct workqueue_struct *Si47xx_wq; +extern struct work_struct Si47xx_work; +#endif + +/* Function prototypes */ + +/*extern functions*/ +/**********************************************/ +/* All the exported functions which view or modify the device + state/data, do i2c com will have to lock the mutex before + doing so +*/ +/**********************************************/ + +extern int Si47xx_dev_init(struct Si47xx_device_t *); +extern int Si47xx_dev_exit(void); + +extern int Si47xx_dev_suspend(void); +extern int Si47xx_dev_resume(void); + +extern int Si47xx_dev_powerup(void); +extern int Si47xx_dev_powerdown(void); + +extern int Si47xx_dev_band_set(int); +extern int Si47xx_dev_ch_spacing_set(int); + +extern int Si47xx_dev_chan_select(u32); +extern int Si47xx_dev_chan_get(u32 *); + +extern int Si47xx_dev_seek_full(u32 *); +extern int Si47xx_dev_seek_up(u32 *); +extern int Si47xx_dev_seek_down(u32 *); +extern int Si47xx_dev_seek_auto(u32 *); + +extern int Si47xx_dev_RSSI_seek_th_set(u8); +extern int Si47xx_dev_seek_SNR_th_set(u8); +extern int Si47xx_dev_seek_FM_ID_th_set(u8); +extern int Si47xx_dev_cur_RSSI_get(struct rssi_snr_t *); +extern int Si47xx_dev_volume_set(u8); +extern int Si47xx_dev_volume_get(u8 *); +extern int Si47xx_dev_DSMUTE_ON(void); +extern int Si47xx_dev_DSMUTE_OFF(void); +extern int Si47xx_dev_MUTE_ON(void); +extern int Si47xx_dev_MUTE_OFF(void); +extern int Si47xx_dev_MONO_SET(void); +extern int Si47xx_dev_STEREO_SET(void); +extern int Si47xx_dev_rstate_get(struct dev_state_t *); +extern int Si47xx_dev_RDS_data_get(struct radio_data_t *); +extern int Si47xx_dev_RDS_ENABLE(void); +extern int Si47xx_dev_RDS_DISABLE(void); +extern int Si47xx_dev_RDS_timeout_set(u32); +extern int Si47xx_dev_device_id(struct device_id *); +extern int Si47xx_dev_chip_id(struct chip_id *); +extern int Si47xx_dev_sys_config2(struct sys_config2 *); +extern int Si47xx_dev_sys_config3(struct sys_config3 *); +extern int Si47xx_dev_AFCRL_get(u8 *); +extern int Si47xx_dev_DE_set(u8); +extern int Si47xx_dev_status_rssi(struct status_rssi *status); +extern int Si47xx_dev_sys_config2_set(struct sys_config2 *sys_conf2); +extern int Si47xx_dev_sys_config3_set(struct sys_config3 *sys_conf3); +extern int Si47xx_dev_reset_rds_data(void); + +/***********************************************/ + +#ifdef RDS_INTERRUPT_ON_ALWAYS +extern void Si47xx_work_func(struct work_struct *); +#endif +#endif + + diff --git a/drivers/samsung/fm_si47xx/Si47xx_i2c_drv.c b/drivers/samsung/fm_si47xx/Si47xx_i2c_drv.c new file mode 100644 index 0000000..fa030bf --- /dev/null +++ b/drivers/samsung/fm_si47xx/Si47xx_i2c_drv.c @@ -0,0 +1,768 @@ +/* drivers/samsung/fm_si47xx/Si47xx_i2c_drv.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/miscdevice.h> +#include <linux/interrupt.h> +#include <linux/uaccess.h> +#include <linux/irq.h> +#include <asm/irq.h> +#include <linux/io.h> +#include <linux/wait.h> +#include <linux/stat.h> +#include <linux/ioctl.h> +#include <linux/delay.h> + +#include <plat/gpio-cfg.h> +#include <mach/gpio.h> + +#include "Si47xx_dev.h" +#include "Si47xx_ioctl.h" +#include <linux/i2c/si47xx_common.h> + + +/*******************************************************/ + +/*static functions*/ + +/*file operatons*/ +static int Si47xx_open(struct inode *, struct file *); +static int Si47xx_release(struct inode *, struct file *); +static long Si47xx_ioctl(struct file *, unsigned int, unsigned long); +static int Si47xx_suspend(struct i2c_client *, pm_message_t mesg); +static int Si47xx_resume(struct i2c_client *); + +/*I2C Setting*/ + +static struct i2c_driver Si47xx_i2c_driver; +static const struct i2c_device_id Si47xx_id[] = { + {"Si47xx", 0}, + {} +}; + +/* static void __iomem *gpio_mask_mem; */ +/**********************************************************/ + +static const struct file_operations Si47xx_fops = { + .owner = THIS_MODULE, + .open = Si47xx_open, + .unlocked_ioctl = Si47xx_ioctl, + .release = Si47xx_release, +}; + +static struct miscdevice Si47xx_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "fmradio", + .fops = &Si47xx_fops, +}; + +/***************************************************************/ + +static int Si47xx_open(struct inode *inode, struct file *filp) +{ + debug("Si47xx_open called\n"); + + return nonseekable_open(inode, filp); +} + +static int Si47xx_release(struct inode *inode, struct file *filp) +{ + debug("Si47xx_release called\n\n"); + + return 0; +} + +static long Si47xx_ioctl(struct file *filp, unsigned int ioctl_cmd, + unsigned long arg) +{ + long ret = 0; + void __user *argp = (void __user *)arg; + + debug("Si47xx ioctl 0x%x", ioctl_cmd); + + if (_IOC_TYPE(ioctl_cmd) != Si47xx_IOC_MAGIC) { + debug("Inappropriate ioctl 1 0x%x", ioctl_cmd); + return -ENOTTY; + } + + if (_IOC_NR(ioctl_cmd) > Si47xx_IOC_NR_MAX) { + debug("Inappropriate ioctl 2 0x%x", ioctl_cmd); + return -ENOTTY; + } + + switch (ioctl_cmd) { + case Si47xx_IOC_POWERUP: + debug("Si47xx_IOC_POWERUP called\n\n"); + + ret = (long)Si47xx_dev_powerup(); + if (ret < 0) + debug("Si47xx_IOC_POWERUP failed\n"); + break; + + case Si47xx_IOC_POWERDOWN: + debug("Si47xx_IOC_POWERDOWN called\n"); + + ret = (long)Si47xx_dev_powerdown(); + if (ret < 0) + debug("Si47xx_IOC_POWERDOWN failed\n"); + break; + + case Si47xx_IOC_BAND_SET: + { + int band; + debug("Si47xx_IOC_BAND_SET called\n\n"); + + if (copy_from_user((void *)&band, argp, sizeof(int))) + ret = -EFAULT; + else { + ret = (long)Si47xx_dev_band_set(band); + if (ret < 0) + debug("Si47xx_IOC_BAND_SET failed\n"); + } + } + break; + + case Si47xx_IOC_CHAN_SPACING_SET: + { + int ch_spacing; + debug("Si47xx_IOC_CHAN_SPACING_SET called\n"); + + if (copy_from_user + ((void *)&ch_spacing, argp, sizeof(int))) + ret = -EFAULT; + else { + ret = (long)Si47xx_dev_ch_spacing_set(ch_spacing); + if (ret < 0) + debug("Si47xx_IOC_CHAN_SPACING_SET " + "failed\n"); + } + } + break; + + case Si47xx_IOC_CHAN_SELECT: + { + u32 frequency; + debug("Si47xx_IOC_CHAN_SELECT called\n"); + + if (copy_from_user + ((void *)&frequency, argp, sizeof(u32))) + ret = -EFAULT; + else { + ret = (long)Si47xx_dev_chan_select(frequency); + if (ret < 0) + debug("Si47xx_IOC_CHAN_SELECT " + "failed\n"); + } + } + break; + + case Si47xx_IOC_CHAN_GET: + { + u32 frequency = 0; + debug("Si47xx_IOC_CHAN_GET called\n"); + + ret = (long)Si47xx_dev_chan_get(&frequency); + if (ret < 0) + debug("Si47xx_IOC_CHAN_GET failed\n"); + else if (copy_to_user + (argp, (void *)&frequency, sizeof(u32))) + ret = -EFAULT; + } + break; + + case Si47xx_IOC_SEEK_FULL: + { + u32 frequency = 0; + debug("Si47xx_IOC_SEEK_FULL called\n"); + + ret = (long)Si47xx_dev_seek_full(&frequency); + if (ret < 0) + debug("Si47xx_IOC_SEEK_FULL failed\n"); + else if (copy_to_user + (argp, (void *)&frequency, sizeof(u32))) + ret = -EFAULT; + } + break; + + case Si47xx_IOC_SEEK_UP: + { + u32 frequency = 0; + debug("Si47xx_IOC_SEEK_UP called\n"); + + ret = (long)Si47xx_dev_seek_up(&frequency); + if (ret < 0) + debug("Si47xx_IOC_SEEK_UP failed\n"); + else if (copy_to_user + (argp, (void *)&frequency, sizeof(u32))) + ret = -EFAULT; + } + break; + + case Si47xx_IOC_SEEK_DOWN: + { + u32 frequency = 0; + debug("Si47xx_IOC_SEEK_DOWN called\n"); + + ret = (long)Si47xx_dev_seek_down(&frequency); + if (ret < 0) + debug("Si47xx_IOC_SEEK_DOWN failed\n"); + else if (copy_to_user + (argp, (void *)&frequency, sizeof(u32))) + ret = -EFAULT; + } + break; + + case Si47xx_IOC_RSSI_SEEK_TH_SET: + { + u8 RSSI_seek_th; + debug("Si47xx_IOC_RSSI_SEEK_TH_SET called\n"); + + if (copy_from_user + ((void *)&RSSI_seek_th, argp, sizeof(u8))) + ret = -EFAULT; + else { + ret = (long)Si47xx_dev_RSSI_seek_th_set(RSSI_seek_th); + if (ret < 0) + debug("Si47xx_IOC_RSSI_SEEK_TH_SET " + "failed\n"); + } + } + break; + + case Si47xx_IOC_SEEK_SNR_SET: + { + u8 seek_SNR_th; + debug("Si47xx_IOC_SEEK_SNR_SET called\n"); + + if (copy_from_user + ((void *)&seek_SNR_th, argp, sizeof(u8))) + ret = -EFAULT; + else { + ret = (long)Si47xx_dev_seek_SNR_th_set(seek_SNR_th); + if (ret < 0) + debug("Si47xx_IOC_SEEK_SNR_SET " + "failed\n"); + } + } + break; + + case Si47xx_IOC_SEEK_CNT_SET: + { + u8 seek_FM_ID_th; + debug("Si47xx_IOC_SEEK_CNT_SET called\n"); + + if (copy_from_user + ((void *)&seek_FM_ID_th, argp, sizeof(u8))) + ret = -EFAULT; + else { + ret = + (long)Si47xx_dev_seek_FM_ID_th_set(seek_FM_ID_th); + if (ret < 0) + debug("Si47xx_IOC_SEEK_CNT_SET " + "failed\n"); + } + } + break; + + case Si47xx_IOC_CUR_RSSI_GET: + { + struct rssi_snr_t data; + debug("Si47xx_IOC_CUR_RSSI_GET called\n"); + + ret = (long)Si47xx_dev_cur_RSSI_get(&data); + if (ret < 0) + debug("Si47xx_IOC_CUR_RSSI_GET failed\n"); + else if (copy_to_user(argp, (void *)&data, + sizeof(data))) + ret = -EFAULT; + + debug("curr_rssi:%d\ncurr_rssi_th:%d\ncurr_snr:%d\n", + data.curr_rssi, data.curr_rssi_th, data.curr_snr); + } + break; + + case Si47xx_IOC_VOLUME_SET: + { + u8 volume; + if (copy_from_user((void *)&volume, argp, sizeof(u8))) + ret = -EFAULT; + else { + debug("Si47xx_IOC_VOLUME_SET called " + "vol %d\n", volume); + ret = (long)Si47xx_dev_volume_set(volume); + if (ret < 0) + debug("Si47xx_IOC_VOLUME_SET failed\n"); + } + } + break; + + case Si47xx_IOC_VOLUME_GET: + { + u8 volume; + debug("Si47xx_IOC_VOLUME_GET called\n"); + + ret = (long)Si47xx_dev_volume_get(&volume); + + if (ret < 0) + debug("Si47xx_IOC_VOLUME_GET failed\n"); + else if (copy_to_user + (argp, (void *)&volume, sizeof(u8))) + ret = -EFAULT; + } + break; + + case Si47xx_IOC_DSMUTE_ON: + debug("Si47xx_IOC_DSMUTE_ON called\n\n"); + + ret = (long)Si47xx_dev_DSMUTE_ON(); + if (ret < 0) + error("Si47xx_IOC_DSMUTE_ON failed\n"); + break; + + case Si47xx_IOC_DSMUTE_OFF: + debug("Si47xx_IOC_DSMUTE_OFF called\n\n"); + + ret = (long)Si47xx_dev_DSMUTE_OFF(); + if (ret < 0) + error("Si47xx_IOC_DSMUTE_OFF failed\n"); + break; + + case Si47xx_IOC_MUTE_ON: + debug("Si47xx_IOC_MUTE_ON called\n"); + + ret = (long)Si47xx_dev_MUTE_ON(); + if (ret < 0) + debug("Si47xx_IOC_MUTE_ON failed\n"); + break; + + case Si47xx_IOC_MUTE_OFF: + debug("Si47xx_IOC_MUTE_OFF called\n"); + + ret = (long)Si47xx_dev_MUTE_OFF(); + if (ret < 0) + debug("Si47xx_IOC_MUTE_OFF failed\n"); + break; + + case Si47xx_IOC_MONO_SET: + debug("Si47xx_IOC_MONO_SET called\n"); + + ret = (long)Si47xx_dev_MONO_SET(); + if (ret < 0) + debug("Si47xx_IOC_MONO_SET failed\n"); + break; + + case Si47xx_IOC_STEREO_SET: + debug("Si47xx_IOC_STEREO_SET called\n"); + + ret = (long)Si47xx_dev_STEREO_SET(); + if (ret < 0) + debug("Si47xx_IOC_STEREO_SET failed\n"); + break; + + case Si47xx_IOC_RSTATE_GET: + { + struct dev_state_t dev_state; + + debug("Si47xx_IOC_RSTATE_GET called\n"); + + ret = (long)Si47xx_dev_rstate_get(&dev_state); + if (ret < 0) + debug("Si47xx_IOC_RSTATE_GET failed\n"); + else if (copy_to_user(argp, (void *)&dev_state, + sizeof(dev_state))) + ret = -EFAULT; + } + break; + + case Si47xx_IOC_RDS_DATA_GET: + { + struct radio_data_t data; + debug("Si47xx_IOC_RDS_DATA_GET called\n"); + + ret = (long)Si47xx_dev_RDS_data_get(&data); + if (ret < 0) + debug(" Si47xx_IOC_RDS_DATA_GET failed\n"); + else if (copy_to_user(argp, (void *)&data, + sizeof(data))) + ret = -EFAULT; + } + break; + + case Si47xx_IOC_RDS_ENABLE: + debug("Si47xx_IOC_RDS_ENABLE called\n"); + + ret = (long)Si47xx_dev_RDS_ENABLE(); + if (ret < 0) + debug("Si47xx_IOC_RDS_ENABLE failed\n"); + break; + + case Si47xx_IOC_RDS_DISABLE: + debug("Si47xx_IOC_RDS_DISABLE called\n"); + + ret = (long)Si47xx_dev_RDS_DISABLE(); + if (ret < 0) + debug("Si47xx_IOC_RDS_DISABLE failed\n"); + break; + + case Si47xx_IOC_RDS_TIMEOUT_SET: + { + u32 time_out; + debug("Si47xx_IOC_RDS_TIMEOUT_SET called\n"); + + if (copy_from_user + ((void *)&time_out, argp, sizeof(u32))) + ret = -EFAULT; + else { + ret = (long)Si47xx_dev_RDS_timeout_set(time_out); + if (ret < 0) + debug("Si47xx_IOC_RDS_TIMEOUT_SET " + "failed\n"); + } + } + break; + + case Si47xx_IOC_SEEK_CANCEL: + debug("Si47xx_IOC_SEEK_CANCEL called\n"); + + if (Si47xx_dev_wait_flag == SEEK_WAITING) { + Si47xx_dev_wait_flag = SEEK_CANCEL; + wake_up_interruptible(&Si47xx_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 Si47xx_IOC_CHIP_ID_GET: + { + struct chip_id chp_id; + debug("Si47xx_IOC_CHIP_ID called\n"); + + ret = (long)Si47xx_dev_chip_id(&chp_id); + if (ret < 0) + debug("Si47xx_IOC_CHIP_ID failed\n"); + else if (copy_to_user(argp, (void *)&chp_id, + sizeof(chp_id))) + ret = -EFAULT; + } + break; + + case Si47xx_IOC_DEVICE_ID_GET: + { + struct device_id dev_id; + debug("Si47xx_IOC_DEVICE_ID called\n"); + + ret = (long)Si47xx_dev_device_id(&dev_id); + if (ret < 0) + debug("Si47xx_IOC_DEVICE_ID failed\n"); + else if (copy_to_user(argp, (void *)&dev_id, + sizeof(dev_id))) + ret = -EFAULT; + } + break; + + case Si47xx_IOC_SYS_CONFIG2_GET: + { + struct sys_config2 sys_conf2; + debug("Si47xx_IOC_SYS_CONFIG2 called\n"); + + ret = (long)Si47xx_dev_sys_config2(&sys_conf2); + if (ret < 0) + debug("Si47xx_IOC_SYS_CONFIG2 failed\n"); + else if (copy_to_user(argp, (void *)&sys_conf2, + sizeof(sys_conf2))) + ret = -EFAULT; + } + break; + + case Si47xx_IOC_SYS_CONFIG3_GET: + { + struct sys_config3 sys_conf3; + debug("Si47xx_IOC_SYS_CONFIG3 called\n"); + + ret = (long)Si47xx_dev_sys_config3(&sys_conf3); + if (ret < 0) + debug("Si47xx_IOC_SYS_CONFIG3 failed\n"); + else if (copy_to_user(argp, (void *)&sys_conf3, + sizeof(sys_conf3))) + ret = -EFAULT; + } + break; + + case Si47xx_IOC_POWER_CONFIG_GET: + { + debug("Si47xx_IOC_POWER_CONFIG called\n"); + ret = -EFAULT; + } + break; +/*VNVS:END*/ + +/*VNVS:START 18-NOV'09*/ + /*Reading AFCRL Bit */ + case Si47xx_IOC_AFCRL_GET: + { + u8 afc; + debug("Si47xx_IOC_AFCRL_GET called\n"); + + ret = (long)Si47xx_dev_AFCRL_get(&afc); + if (ret < 0) + debug("Si47xx_IOC_AFCRL_GET failed\n"); + else if (copy_to_user(argp, (void *)&afc, sizeof(u8))) + ret = -EFAULT; + } + break; + + /*Setting DE-emphasis Time Constant. + For DE=0,TC=50us(Europe,Japan,Australia) + and DE=1,TC=75us(USA) */ + case Si47xx_IOC_DE_SET: + { + u8 de_tc; + debug("Si47xx_IOC_DE_SET called\n"); + + if (copy_from_user((void *)&de_tc, argp, sizeof(u8))) + ret = -EFAULT; + else { + ret = (long)Si47xx_dev_DE_set(de_tc); + if (ret < 0) + debug("Si47xx_IOC_DE_SET failed\n"); + } + } + break; + + case Si47xx_IOC_STATUS_RSSI_GET: + { + struct status_rssi status; + debug("Si47xx_IOC_STATUS_RSSI_GET called\n"); + + ret = (long)Si47xx_dev_status_rssi(&status); + if (ret < 0) + debug("Si47xx_IOC_STATUS_RSSI_GET failed\n"); + else if (copy_to_user(argp, (void *)&status, + sizeof(status))) + ret = -EFAULT; + } + break; + + case Si47xx_IOC_SYS_CONFIG2_SET: + { + struct sys_config2 sys_conf2; + unsigned long n; + debug("Si47xx_IOC_SYS_CONFIG2_SET called\n"); + + n = copy_from_user((void *)&sys_conf2, argp, + sizeof(sys_conf2)); + if (n) { + debug("Si47xx_IOC_SYS_CONFIG2_SET() : " + "copy_from_user() has error!! " + "Failed to read [%lu] byes!", n); + ret = -EFAULT; + } else { + ret = (long)Si47xx_dev_sys_config2_set(&sys_conf2); + if (ret < 0) + debug("Si47xx_IOC_SYS_CONFIG2_SET" + "failed\n"); + } + } + break; + + case Si47xx_IOC_SYS_CONFIG3_SET: + { + struct sys_config3 sys_conf3; + unsigned long n; + + debug("Si47xx_IOC_SYS_CONFIG3_SET called\n"); + + n = copy_from_user((void *)&sys_conf3, argp, + sizeof(sys_conf3)); + if (n) { + debug("Si47xx_IOC_SYS_CONFIG3_SET() : " + "copy_from_user() has error!! " + "Failed to read [%lu] byes!", n); + ret = -EFAULT; + } else { + ret = (long)Si47xx_dev_sys_config3_set(&sys_conf3); + if (ret < 0) + debug("Si47xx_IOC_SYS_CONFIG3_SET " + "failed\n"); + } + } + break; + + /*Resetting the RDS Data Buffer */ + case Si47xx_IOC_RESET_RDS_DATA: + { + debug("Si47xx_IOC_RESET_RDS_DATA called\n"); + + ret = (long)Si47xx_dev_reset_rds_data(); + if (ret < 0) + error("Si47xx_IOC_RESET_RDS_DATA failed\n"); + } + break; +/*VNVS:END*/ + default: + debug(" ioctl default\n"); + ret = -ENOTTY; + break; + } + + return ret; +} + +static int __devinit Si47xx_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct Si47xx_device_t *Si47xx_dev; + struct si47xx_platform_data *pdata; + int err, ret = 0; + + debug("----- %s %d\n", __func__, __LINE__); + + Si47xx_dev = kzalloc(sizeof(struct Si47xx_device_t), GFP_KERNEL); + + if (!Si47xx_dev) { + err = -ENOMEM; + return err; + } + + Si47xx_dev->client = client; + i2c_set_clientdata(client, Si47xx_dev); + + Si47xx_dev->dev = &client->dev; + dev_set_drvdata(Si47xx_dev->dev, Si47xx_dev); + + Si47xx_dev->pdata = client->dev.platform_data; + pdata = Si47xx_dev->pdata; + + mutex_init(&Si47xx_dev->lock); + + ret = Si47xx_dev_init(Si47xx_dev); + if (ret < 0) + error("Si47xx_dev_init failed"); + + return ret; + +MISC_IRQ_DREG: + free_irq(client->irq, NULL); + mutex_destroy(&Si47xx_dev->lock); + kfree(Si47xx_dev); + return ret; + +} + +static int __devexit Si47xx_i2c_remove(struct i2c_client *client) +{ + struct Si47xx_device_t *Si47xx_dev = i2c_get_clientdata(client); + int ret = 0; + + free_irq(client->irq, NULL); + i2c_set_clientdata(client, NULL); + ret = Si47xx_dev_exit(); + mutex_destroy(&Si47xx_dev->lock); + kfree(Si47xx_dev); + return ret; +} + +static struct i2c_driver Si47xx_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "Si47xx", + }, + .id_table = Si47xx_id, + .probe = Si47xx_i2c_probe, + .remove = __devexit_p(Si47xx_i2c_remove), + .suspend = Si47xx_suspend, + .resume = Si47xx_resume, +}; + +static int Si47xx_suspend(struct i2c_client *client, pm_message_t mesg) +{ + int ret = 0; + + debug("Si47xx i2c driver Si47xx_suspend called"); + + if (strcmp(client->name, "Si47xx") != 0) { + ret = -1; + error("Si47xx_suspend: device not supported"); + } else { + ret = Si47xx_dev_suspend(); + if (ret < 0) + error("Si47xx_dev_disable failed"); + } + + return 0; +} + +static int Si47xx_resume(struct i2c_client *client) +{ + int ret = 0; + + if (strcmp(client->name, "Si47xx") != 0) { + ret = -1; + error("Si47xx_resume: device not supported"); + } else { + ret = Si47xx_dev_resume(); + if (ret < 0) + error("Si47xx_dev_enable failed"); + } + + return 0; +} + +static __init int Si47xx_i2c_drv_init(void) +{ + int ret = 0; + + debug("Si47xx i2c driver Si47xx_i2c_driver_init called"); + + /*misc device registration */ + ret = misc_register(&Si47xx_misc_device); + if (ret < 0) { + error("Si47xx_driver_init misc_register failed\n"); + goto MISC_DREG; + } + + ret = i2c_add_driver(&Si47xx_i2c_driver); + if (ret < 0) { + error("Si47xx i2c_add_driver failed"); + return ret; + } + + init_waitqueue_head(&Si47xx_waitq); + debug("Si47xx_driver_init successful\n"); + + return ret; +MISC_DREG: + misc_deregister(&Si47xx_misc_device); + return ret; + + +} + +void __exit Si47xx_i2c_drv_exit(void) +{ + debug("Si47xx i2c driver Si47xx_i2c_driver_exit called"); + + i2c_del_driver(&Si47xx_i2c_driver); + /*misc device deregistration */ + misc_deregister(&Si47xx_misc_device); +} + +module_init(Si47xx_i2c_drv_init); +module_exit(Si47xx_i2c_drv_exit); +MODULE_AUTHOR("ashton seo <ashton.seo@samsung.com>"); +MODULE_DESCRIPTION("Si47xx FM tuner driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/samsung/fm_si47xx/Si47xx_ioctl.h b/drivers/samsung/fm_si47xx/Si47xx_ioctl.h new file mode 100644 index 0000000..08f8238 --- /dev/null +++ b/drivers/samsung/fm_si47xx/Si47xx_ioctl.h @@ -0,0 +1,129 @@ +/* + * Si47xx_ioctl.h -- Si47xx FM Radio driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _Si47xx_IOCTL_H +#define _Si47xx_IOCTL_H + +#include <linux/types.h> +#include <linux/ioctl.h> + +#include "Si47xx_dev.h" + +/*****************IOCTLS******************/ +/*magic no*/ +#define Si47xx_IOC_MAGIC 0xFA +/*max seq no*/ +#define Si47xx_IOC_NR_MAX 40 + +/*commands*/ + +#define Si47xx_IOC_POWERUP _IO(Si47xx_IOC_MAGIC, 0) + +#define Si47xx_IOC_POWERDOWN _IO(Si47xx_IOC_MAGIC, 1) + +#define Si47xx_IOC_BAND_SET _IOW(Si47xx_IOC_MAGIC, 2, int) + +#define Si47xx_IOC_CHAN_SPACING_SET _IOW(Si47xx_IOC_MAGIC, 3, int) + +#define Si47xx_IOC_CHAN_SELECT _IOW(Si47xx_IOC_MAGIC, 4, u32) + +#define Si47xx_IOC_CHAN_GET _IOR(Si47xx_IOC_MAGIC, 5, u32) + +#define Si47xx_IOC_SEEK_UP _IOR(Si47xx_IOC_MAGIC, 6, u32) + +#define Si47xx_IOC_SEEK_DOWN _IOR(Si47xx_IOC_MAGIC, 7, u32) + +/*VNVS:28OCT'09---- Si47xx_IOC_SEEK_AUTO is disabled as of now*/ +/* #define Si47xx_IOC_SEEK_AUTO _IOR(Si47xx_IOC_MAGIC, 8, u32) */ + +#define Si47xx_IOC_RSSI_SEEK_TH_SET _IOW(Si47xx_IOC_MAGIC, 9, u8) + +#define Si47xx_IOC_SEEK_SNR_SET _IOW(Si47xx_IOC_MAGIC, 10, u8) + +#define Si47xx_IOC_SEEK_CNT_SET _IOW(Si47xx_IOC_MAGIC, 11, u8) + +#define Si47xx_IOC_CUR_RSSI_GET \ +_IOR(Si47xx_IOC_MAGIC, 12, struct rssi_snr_t) + +#define Si47xx_IOC_VOLEXT_ENB _IO(Si47xx_IOC_MAGIC, 13) + +#define Si47xx_IOC_VOLEXT_DISB _IO(Si47xx_IOC_MAGIC, 14) + +#define Si47xx_IOC_VOLUME_SET _IOW(Si47xx_IOC_MAGIC, 15, u8) + +#define Si47xx_IOC_VOLUME_GET _IOR(Si47xx_IOC_MAGIC, 16, u8) + +#define Si47xx_IOC_MUTE_ON _IO(Si47xx_IOC_MAGIC, 17) + +#define Si47xx_IOC_MUTE_OFF _IO(Si47xx_IOC_MAGIC, 18) + +#define Si47xx_IOC_MONO_SET _IO(Si47xx_IOC_MAGIC, 19) + +#define Si47xx_IOC_STEREO_SET _IO(Si47xx_IOC_MAGIC, 20) + +#define Si47xx_IOC_RSTATE_GET \ +_IOR(Si47xx_IOC_MAGIC, 21, struct dev_state_t) + +#define Si47xx_IOC_RDS_DATA_GET \ +_IOR(Si47xx_IOC_MAGIC, 22, struct radio_data_t) + +#define Si47xx_IOC_RDS_ENABLE _IO(Si47xx_IOC_MAGIC, 23) + +#define Si47xx_IOC_RDS_DISABLE _IO(Si47xx_IOC_MAGIC, 24) + +#define Si47xx_IOC_RDS_TIMEOUT_SET _IOW(Si47xx_IOC_MAGIC, 25, u32) + +#define Si47xx_IOC_SEEK_CANCEL _IO(Si47xx_IOC_MAGIC, 26) + +/*VNVS:START 13-OCT'09 : + Added IOCTLs for reading the device-id,chip-id,power configuration, + system configuration2 registers*/ +#define Si47xx_IOC_DEVICE_ID_GET \ +_IOR(Si47xx_IOC_MAGIC, 27, struct device_id) + +#define Si47xx_IOC_CHIP_ID_GET \ +_IOR(Si47xx_IOC_MAGIC, 28, struct chip_id) + +#define Si47xx_IOC_SYS_CONFIG2_GET \ +_IOR(Si47xx_IOC_MAGIC, 29, struct sys_config2) + +#define Si47xx_IOC_POWER_CONFIG_GET \ +_IO(Si47xx_IOC_MAGIC, 30) + +/* For reading AFCRL bit, to check for a valid channel */ +#define Si47xx_IOC_AFCRL_GET _IOR(Si47xx_IOC_MAGIC, 31, u8) + +/* Setting DE-emphasis Time Constant. +For DE=0,TC=50us(Europe,Japan,Australia) and DE=1,TC=75us(USA) */ +#define Si47xx_IOC_DE_SET _IOW(Si47xx_IOC_MAGIC, 32, u8) +/*VNVS:END*/ + +#define Si47xx_IOC_SYS_CONFIG3_GET \ +_IOR(Si47xx_IOC_MAGIC, 33, struct sys_config3) + +#define Si47xx_IOC_STATUS_RSSI_GET \ +_IOR(Si47xx_IOC_MAGIC, 34, struct status_rssi) + +#define Si47xx_IOC_SYS_CONFIG2_SET \ +_IOW(Si47xx_IOC_MAGIC, 35, struct sys_config2) + +#define Si47xx_IOC_SYS_CONFIG3_SET \ +_IOW(Si47xx_IOC_MAGIC, 36, struct sys_config3) + +#define Si47xx_IOC_DSMUTE_ON _IO(Si47xx_IOC_MAGIC, 37) + +#define Si47xx_IOC_DSMUTE_OFF _IO(Si47xx_IOC_MAGIC, 38) + +#define Si47xx_IOC_RESET_RDS_DATA _IO(Si47xx_IOC_MAGIC, 39) + +#define Si47xx_IOC_SEEK_FULL _IOR(Si47xx_IOC_MAGIC, 40, u32) + + +/*****************************************/ + +#endif diff --git a/drivers/samsung/fm_si47xx/commanddefs.h b/drivers/samsung/fm_si47xx/commanddefs.h new file mode 100644 index 0000000..55d5e16 --- /dev/null +++ b/drivers/samsung/fm_si47xx/commanddefs.h @@ -0,0 +1,199 @@ +/* + * commanddefs.h -- This file contains the command definitions for + * the Si47xx Parts. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _COMMAND_DEFS_H_ +#define _COMMAND_DEFS_H_ + +/*================================================================== +General Commands +==================================================================*/ + +/* STATUS bits - Used by all methods */ +#define STCINT 0x01 +#define ASQINT 0x02 +#define RDSINT 0x04 +#define RSQINT 0x08 +#define ERR 0x40 +#define CTS 0x80 + +/* POWER_UP */ +#define POWER_UP 0x01 +#define POWER_UP_IN_FUNC_FMRX 0x00 +#define POWER_UP_IN_FUNC_AMRX 0x01 +#define POWER_UP_IN_FUNC_FMTX 0x02 +#define POWER_UP_IN_FUNC_WBRX 0x03 +#define POWER_UP_IN_FUNC_QUERY 0x0F +#define POWER_UP_IN_PATCH 0x20 +#define POWER_UP_IN_GPO2OEN 0x40 +#define POWER_UP_IN_CTSIEN 0x80 +#define POWER_UP_IN_OPMODE_RX_ANALOG 0x05 +#define POWER_UP_IN_OPMODE_TX_ANALOG 0x50 + +/* GET_REV */ +#define GET_REV 0x10 + +/* POWER_DOWN */ +#define POWER_DOWN 0x11 + +/* SET_PROPERTY */ +#define SET_PROPERTY 0x12 + +/* GET_PROPERTY */ +#define GET_PROPERTY 0x13 + +/* GET_INT_STATUS */ +#define GET_INT_STATUS 0x14 + +/*================================================================== + FM Receive Commands +==================================================================*/ + +/* FM_TUNE_FREQ */ +#define FM_TUNE_FREQ 0x20 + +/* FM_SEEK_START */ +#define FM_SEEK_START 0x21 +#define FM_SEEK_START_IN_WRAP 0x04 +#define FM_SEEK_START_IN_SEEKUP 0x08 + +/* FM_TUNE_STATUS */ +#define FM_TUNE_STATUS 0x22 +#define FM_TUNE_STATUS_IN_INTACK 0x01 +#define FM_TUNE_STATUS_IN_CANCEL 0x02 +#define FM_TUNE_STATUS_OUT_VALID 0x01 +#define FM_TUNE_STATUS_OUT_AFCRL 0x02 +#define FM_TUNE_STATUS_OUT_BTLF 0x80 + +/* FM_RSQ_STATUS */ +#define FM_RSQ_STATUS 0x23 +#define FM_RSQ_STATUS_IN_INTACK 0x01 +#define FM_RSQ_STATUS_OUT_RSSILINT 0x01 +#define FM_RSQ_STATUS_OUT_RSSIHINT 0x02 +#define FM_RSQ_STATUS_OUT_ASNRLINT 0x04 +#define FM_RSQ_STATUS_OUT_ASNRHINT 0x08 +#define FM_RSQ_STATUS_OUT_BLENDINT 0x80 +#define FM_RSQ_STATUS_OUT_VALID 0x01 +#define FM_RSQ_STATUS_OUT_AFCRL 0x02 +#define FM_RSQ_STATUS_OUT_SMUTE 0x08 +#define FM_RSQ_STATUS_OUT_PILOT 0x80 +#define FM_RSQ_STATUS_OUT_STBLEND 0x7F + +/* FM_RDS_STATUS */ +#define FM_RDS_STATUS 0x24 +#define FM_RDS_STATUS_IN_INTACK 0x01 +#define FM_RDS_STATUS_IN_MTFIFO 0x02 +#define FM_RDS_STATUS_OUT_RECV 0x01 +#define FM_RDS_STATUS_OUT_SYNCLOST 0x02 +#define FM_RDS_STATUS_OUT_SYNCFOUND 0x04 +#define FM_RDS_STATUS_OUT_SYNC 0x01 +#define FM_RDS_STATUS_OUT_GRPLOST 0x04 +#define FM_RDS_STATUS_OUT_BLED 0x03 +#define FM_RDS_STATUS_OUT_BLEC 0x0C +#define FM_RDS_STATUS_OUT_BLEB 0x30 +#define FM_RDS_STATUS_OUT_BLEA 0xC0 +#define FM_RDS_STATUS_OUT_BLED_SHFT 0 +#define FM_RDS_STATUS_OUT_BLEC_SHFT 2 +#define FM_RDS_STATUS_OUT_BLEB_SHFT 4 +#define FM_RDS_STATUS_OUT_BLEA_SHFT 6 + +/*================================================================== + AM Receive Commands +==================================================================*/ + +/* AM_TUNE_FREQ */ +#define AM_TUNE_FREQ 0x40 + +/* AM_SEEK_START */ +#define AM_SEEK_START 0x41 +#define AM_SEEK_START_IN_WRAP 0x04 +#define AM_SEEK_START_IN_SEEKUP 0x08 + +/* AM_TUNE_STATUS */ +#define AM_TUNE_STATUS 0x42 +#define AM_TUNE_STATUS_IN_INTACK 0x01 +#define AM_TUNE_STATUS_IN_CANCEL 0x02 +#define AM_TUNE_STATUS_OUT_VALID 0x01 +#define AM_TUNE_STATUS_OUT_AFCRL 0x02 +#define AM_TUNE_STATUS_OUT_BTLF 0x80 + +/* AM_RSQ_STATUS */ +#define AM_RSQ_STATUS 0x23 +#define AM_RSQ_STATUS_IN_INTACK 0x01 +#define AM_RSQ_STATUS_OUT_RSSILINT 0x01 +#define AM_RSQ_STATUS_OUT_RSSIHINT 0x02 +#define AM_RSQ_STATUS_OUT_ASNRLINT 0x04 +#define AM_RSQ_STATUS_OUT_ASNRHINT 0x08 +#define AM_RSQ_STATUS_OUT_VALID 0x01 +#define AM_RSQ_STATUS_OUT_AFCRL 0x02 +#define AM_RSQ_STATUS_OUT_SMUTE 0x08 + +/*================================================================== + FM Transmit Commands +==================================================================*/ + +/* TX_TUNE_FREQ */ +#define TX_TUNE_FREQ 0x30 + +/* TX_TUNE_POWER */ +#define TX_TUNE_POWER 0x31 + +/* TX_TUNE_MEASURE */ +#define TX_TUNE_MEASURE 0x32 + +/* TX_TUNE_STATUS */ +#define TX_TUNE_STATUS 0x33 +#define TX_TUNE_STATUS_IN_INTACK 0x01 + +/* TX_ASQ_STATUS */ +#define TX_ASQ_STATUS 0x34 +#define TX_ASQ_STATUS_IN_INTACK 0x01 +#define TX_ASQ_STATUS_OUT_IALL 0x01 +#define TX_ASQ_STATUS_OUT_IALH 0x02 +#define TX_ASQ_STATUS_OUT_OVERMOD 0x04 + +/* TX_RDS_BUFF */ +#define TX_RDS_BUFF 0x35 +#define TX_RDS_BUFF_IN_INTACK 0x01 +#define TX_RDS_BUFF_IN_MTBUFF 0x02 +#define TX_RDS_BUFF_IN_LDBUFF 0x04 +#define TX_RDS_BUFF_IN_FIFO 0x80 + +/* TX_RDS_PS */ +#define TX_RDS_PS 0x36 + +/*================================================================== + WB Receive Commands +==================================================================*/ + +/* WB_TUNE_FREQ */ +#define WB_TUNE_FREQ 0x50 + +/* WB_TUNE_STATUS */ +#define WB_TUNE_STATUS 0x52 +#define WB_TUNE_STATUS_IN_INTACK 0x01 +#define WB_TUNE_STATUS_OUT_VALID 0x01 +#define WB_TUNE_STATUS_OUT_AFCRL 0x02 + +/* WB_RSQ_STATUS */ +#define WB_RSQ_STATUS 0x53 +#define WB_RSQ_STATUS_IN_INTACK 0x01 +#define WB_RSQ_STATUS_OUT_RSSILINT 0x01 +#define WB_RSQ_STATUS_OUT_RSSIHINT 0x02 +#define WB_RSQ_STATUS_OUT_ASNRLINT 0x04 +#define WB_RSQ_STATUS_OUT_ASNRHINT 0x08 +#define WB_RSQ_STATUS_OUT_VALID 0x01 +#define WB_RSQ_STATUS_OUT_AFCRL 0x02 + +/* WB_ASQ_STATUS */ +#define WB_ASQ_STATUS 0x55 +#define WB_ASQ_STATUS_IN_INTACK 0x01 +#define WB_ASQ_STATUS_OUT_ALERTONINT 0x01 +#define WB_ASQ_STATUS_OUT_ALERTOFFINT 0x02 +#define WB_ASQ_STATUS_OUT_ALERT 0x01 + +#endif diff --git a/drivers/samsung/fm_si47xx/propertydefs.h b/drivers/samsung/fm_si47xx/propertydefs.h new file mode 100644 index 0000000..e718b58 --- /dev/null +++ b/drivers/samsung/fm_si47xx/propertydefs.h @@ -0,0 +1,585 @@ +/* + * commanddefs.h -- This file contains the property definitions for + * the Si47xx Parts. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _PROPERTY_DEFS_H_ +#define _PROPERTY_DEFS_H_ + +/*================================================================== + General Properties +==================================================================*/ + +/* GPO_IEN */ +#define GPO_IEN 0x0001 +#define GPO_IEN_STCIEN_MASK 0x0001 +#define GPO_IEN_ASQIEN_MASK 0x0002 +#define GPO_IEN_RDSIEN_MASK 0x0004 +#define GPO_IEN_RSQIEN_MASK 0x0008 +#define GPO_IEN_ERRIEN_MASK 0x0040 +#define GPO_IEN_CTSIEN_MASK 0x0080 +#define GPO_IEN_STCREP_MASK 0x0100 +#define GPO_IEN_ASQREP_MASK 0x0200 +#define GPO_IEN_RDSREP_MASK 0x0400 +#define GPO_IEN_RSQREP_MASK 0x0800 +#define GPO_IEN_STCIEN_SHFT 0 +#define GPO_IEN_ASQIEN_SHFT 1 +#define GPO_IEN_RDSIEN_SHFT 2 +#define GPO_IEN_RSQIEN_SHFT 3 +#define GPO_IEN_ERRIEN_SHFT 6 +#define GPO_IEN_CTSIEN_SHFT 7 +#define GPO_IEN_STCREP_SHFT 8 +#define GPO_IEN_ASQREP_SHFT 9 +#define GPO_IEN_RDSREP_SHFT 10 +#define GPO_IEN_RSQREP_SHFT 11 + +/* DIGITAL_INPUT_FORMAT */ +#define DIGITAL_INPUT_FORMAT 0x0101 +#define DIGITAL_INPUT_FORMAT_ISIZE_MASK 0x0003 +#define DIGITAL_INPUT_FORMAT_IMONO_MASK 0x0004 +#define DIGITAL_INPUT_FORMAT_IMODE_MASK 0x0078 +#define DIGITAL_INPUT_FORMAT_IFALL_MASK 0x0080 +#define DIGITAL_INPUT_FORMAT_ISIZE_SHFT 0 +#define DIGITAL_INPUT_FORMAT_IMONO_SHFT 2 +#define DIGITAL_INPUT_FORMAT_IMODE_SHFT 3 +#define DIGITAL_INPUT_FORMAT_IFALL_SHFT 7 + +/* DIGITAL_INPUT_SAMPLE_RATE */ +#define DIGITAL_INPUT_SAMPLE_RATE 0x0103 + +/* DIGITAL_OUTPUT_FORMAT */ +#define DIGITAL_OUTPUT_FORMAT 0x0102 +#define DIGITAL_OUTPUT_FORMAT_OSIZE_MASK 0x0003 +#define DIGITAL_OUTPUT_FORMAT_OMONO_MASK 0x0004 +#define DIGITAL_OUTPUT_FORMAT_OMODE_MASK 0x0078 +#define DIGITAL_OUTPUT_FORMAT_OFALL_MASK 0x0080 +#define DIGITAL_OUTPUT_FORMAT_OSIZE_SHFT 0 +#define DIGITAL_OUTPUT_FORMAT_OMONO_SHFT 2 +#define DIGITAL_OUTPUT_FORMAT_OMODE_SHFT 3 +#define DIGITAL_OUTPUT_FORMAT_OFALL_SHFT 7 + +/* DIGITAL_OUTPUT_SAMPLE_RATE */ +#define DIGITAL_OUTPUT_SAMPLE_RATE 0x0104 + +/* REFCLK_FREQ */ +#define REFCLK_FREQ 0x0201 + +/* REFCLK_PRESCALE */ +#define REFCLK_PRESCALE 0x0202 +#define REFCLK_PRESCALE_MASK 0x0FFF +#define REFCLK_PRESCALE_SHFT 0 + +/*================================================================== + FM Receive Properties +==================================================================*/ + +/* FM_DEEMPHASIS */ +#define FM_DEEMPHASIS 0x1100 +#define FM_DEEMPHASIS_MASK 0x0003 +#define FM_DEEMPHASIS_SHFT 0 + +/* FM_BLEND_STEREO_THRESHOLD */ +#define FM_BLEND_STEREO_THRESHOLD 0x1105 +#define FM_BLEND_STEREO_THRESHOLD_MASK 0x007F +#define FM_BLEND_STEREO_THRESHOLD_SHFT 0 + +/* FM_BLEND_MONO_THRESHOLD */ +#define FM_BLEND_MONO_THRESHOLD 0x1106 +#define FM_BLEND_MONO_THRESHOLD_MASK 0x007F +#define FM_BLEND_MONO_THRESHOLD_SHFT 0 + + +/* FM_MAX_TUNE_ERROR */ +#define FM_MAX_TUNE_ERROR 0x1108 +#define FM_MAX_TUNE_ERROR_MASK 0x007F +#define FM_MAX_TUNE_ERROR_SHFT 0 + +/* FM_RSQ_INT_SOURCE */ +#define FM_RSQ_INT_SOURCE 0x1200 +#define FM_RSQ_INT_SOURCE_RSSILIEN_MASK 0x0001 +#define FM_RSQ_INT_SOURCE_RSSIHIEN_MASK 0x0002 +#define FM_RSQ_INT_SOURCE_ASNRLIEN_MASK 0x0004 +#define FM_RSQ_INT_SOURCE_ASNRHIEN_MASK 0x0008 +#define FM_RSQ_INT_SOURCE_BLENDIEN_MASK 0x0080 +#define FM_RSQ_INT_SOURCE_RSSILIEN_SHFT 0 +#define FM_RSQ_INT_SOURCE_RSSIHIEN_SHFT 1 +#define FM_RSQ_INT_SOURCE_ASNRLIEN_SHFT 2 +#define FM_RSQ_INT_SOURCE_ASNRHIEN_SHFT 3 +#define FM_RSQ_INT_SOURCE_BLENDIEN_SHFT 7 + +/* FM_RSQ_SNR_HI_THRESHOLD */ +#define FM_RSQ_SNR_HI_THRESHOLD 0x1201 +#define FM_RSQ_SNR_HI_THRESHOLD_MASK 0x007F +#define FM_RSQ_SNR_HI_THRESHOLD_SHFT 0 + +/* FM_RSQ_SNR_LO_THRESHOLD */ +#define FM_RSQ_SNR_LO_THRESHOLD 0x1202 +#define FM_RSQ_SNR_LO_THRESHOLD_MASK 0x007F +#define FM_RSQ_SNR_LO_THRESHOLD_SHFT 0 + +/* FM_RSQ_RSSI_HI_THRESHOLD */ +#define FM_RSQ_RSSI_HI_THRESHOLD 0x1203 +#define FM_RSQ_RSSI_HI_THRESHOLD_MASK 0x007F +#define FM_RSQ_RSSI_HI_THRESHOLD_SHFT 0 + +/* FM_RSQ_RSSI_LO_THRESHOLD */ +#define FM_RSQ_RSSI_LO_THRESHOLD 0x1204 +#define FM_RSQ_RSSI_LO_THRESHOLD_MASK 0x007F +#define FM_RSQ_RSSI_LO_THRESHOLD_SHFT 0 + +/* FM_RSQ_BLEND_THRESHOLD */ +#define FM_RSQ_BLEND_THRESHOLD 0x1207 +#define FM_RSQ_BLEND_THRESHOLD_BLEND_MASK 0x007F +#define FM_RSQ_BLEND_THRESHOLD_PILOT_MASK 0x0080 +#define FM_RSQ_BLEND_THRESHOLD_BLEND_SHFT 0 +#define FM_RSQ_BLEND_THRESHOLD_PILOT_SHFT 7 + +/* FM_SOFT_MUTE_RATE */ +#define FM_SOFT_MUTE_RATE 0x1300 +#define FM_SOFT_MUTE_RATE_MASK 0x00FF +#define FM_SOFT_MUTE_RATE_SHFT 0 + +/* FM_SOFT_MUTE_MAX_ATTENUATION */ +#define FM_SOFT_MUTE_MAX_ATTENUATION 0x1302 +#define FM_SOFT_MUTE_MAX_ATTENUATION_MASK 0x001F +#define FM_SOFT_MUTE_MAX_ATTENUATION_SHFT 0 + +/* FM_SOFT_MUTE_SNR_THRESHOLD */ +#define FM_SOFT_MUTE_SNR_THRESHOLD 0x1303 +#define FM_SOFT_MUTE_SNR_THRESHOLD_MASK 0x000F +#define FM_SOFT_MUTE_SNR_THRESHOLD_SHFT 0 + +/* FM_SEEK_BAND_BOTTOM */ +#define FM_SEEK_BAND_BOTTOM 0x1400 + +/* FM_SEEK_BAND_TOP */ +#define FM_SEEK_BAND_TOP 0x1401 + +/* FM_SEEK_FREQ_SPACING */ +#define FM_SEEK_FREQ_SPACING 0x1402 +#define FM_SEEK_FREQ_SPACING_MASK 0x001F +#define FM_SEEK_FREQ_SPACING_SHFT 0 + +/* FM_SEEK_TUNE_SNR_THRESHOLD */ +#define FM_SEEK_TUNE_SNR_THRESHOLD 0x1403 +#define FM_SEEK_TUNE_SNR_THRESHOLD_MASK 0x007F +#define FM_SEEK_TUNE_SNR_THRESHOLD_SHFT 0 + +/* FM_SEEK_TUNE_RSSI_THRESHOLD */ +#define FM_SEEK_TUNE_RSSI_THRESHOLD 0x1404 +#define FM_SEEK_TUNE_RSSI_THRESHOLD_MASK 0x007F +#define FM_SEEK_TUNE_RSSI_THRESHOLD_SHFT 0 + +/* FM_RDS_INTERRUPT_SOURCE */ +#define FM_RDS_INTERRUPT_SOURCE 0x1500 +#define FM_RDS_INTERRUPT_SOURCE_RECV_MASK 0x0001 +#define FM_RDS_INTERRUPT_SOURCE_SYNCLOST_MASK 0x0002 +#define FM_RDS_INTERRUPT_SOURCE_SYNCFOUND_MASK 0x0004 +#define FM_RDS_INTERRUPT_SOURCE_RECV_SHFT 0 +#define FM_RDS_INTERRUPT_SOURCE_SYNCLOST_SHFT 1 +#define FM_RDS_INTERRUPT_SOURCE_SYNCFOUND_SHFT 2 + +/* FM_RDS_INTERRUPT_FIFO_COUNT */ +#define FM_RDS_INTERRUPT_FIFO_COUNT 0x1501 +#define FM_RDS_INTERRUPT_FIFO_COUNT_MASK 0x00FF +#define FM_RDS_INTERRUPT_FIFO_COUNT_SHFT 0 + +/* FM_RDS_CONFIG */ +#define FM_RDS_CONFIG 0x1502 +#define FM_RDS_CONFIG_RDSEN_MASK 0x0001 +#define FM_RDS_CONFIG_BLETHD_MASK 0x0300 +#define FM_RDS_CONFIG_BLETHC_MASK 0x0C00 +#define FM_RDS_CONFIG_BLETHB_MASK 0x3000 +#define FM_RDS_CONFIG_BLETHA_MASK 0xC000 +#define FM_RDS_CONFIG_RDSEN_SHFT 0 +#define FM_RDS_CONFIG_BLETHD_SHFT 8 +#define FM_RDS_CONFIG_BLETHC_SHFT 10 +#define FM_RDS_CONFIG_BLETHB_SHFT 12 +#define FM_RDS_CONFIG_BLETHA_SHFT 14 + +/*================================================================== + FM Transmit Properties +==================================================================*/ + +/* TX_COMPONENT_ENABLE */ +#define TX_COMPONENT_ENABLE 0x2100 +#define TX_COMPONENT_ENABLE_PILOT_MASK 0x0001 +#define TX_COMPONENT_ENABLE_LMR_MASK 0x0002 +#define TX_COMPONENT_ENABLE_RDS_MASK 0x0004 +#define TX_COMPONENT_ENABLE_PILOT_SHFT 0 +#define TX_COMPONENT_ENABLE_LMR_SHFT 1 +#define TX_COMPONENT_ENABLE_RDS_SHFT 2 + +/* TX_AUDIO_DEVIATION */ +#define TX_AUDIO_DEVIATION 0x2101 + +/* TX_PILOT_DEVIATION */ +#define TX_PILOT_DEVIATION 0x2102 + +/* TX_RDS_DEVIATION */ +#define TX_RDS_DEVIATION 0x2103 + +/* TX_LINE_INPUT_LEVEL */ +#define TX_LINE_INPUT_LEVEL 0x2104 +#define TX_LINE_INPUT_LEVEL_LILEVEL_MASK 0x03FF +#define TX_LINE_INPUT_LEVEL_LIATTEN_MASK 0x3000 +#define TX_LINE_INPUT_LEVEL_LILEVEL_SHFT 0 +#define TX_LINE_INPUT_LEVEL_LIATTEN_SHFT 12 + +/* TX_LINE_INPUT_MUTE */ +#define TX_LINE_INPUT_MUTE 0x2105 +#define TX_LINE_INPUT_MUTE_RIMUTE_MASK 0x0001 +#define TX_LINE_INPUT_MUTE_LIMUTE_MASK 0x0002 +#define TX_LINE_INPUT_MUTE_RIMUTE_SHFT 0 +#define TX_LINE_INPUT_MUTE_LIMUTE_SHFT 1 + +/* TX_PREEMPHASIS */ +#define TX_PREEMPHASIS 0x2106 +#define TX_PREMPHASIS_MASK 0x0003 +#define TX_PREMPHASIS_SHFT 0 + +/* TX_PILOT_FREQUENCY */ +#define TX_PILOT_FREQUENCY 0x2107 + +/* TX_ACOMP_ENABLE */ +#define TX_ACOMP_ENABLE 0x2200 +#define TX_ACOMP_ENABLE_ACEN_MASK 0x0001 +#define TX_ACOMP_ENABLE_LIMITEN_MASK 0x0002 +#define TX_ACOMP_ENABLE_ACEN_SHFT 0 +#define TX_ACOMP_ENABLE_LIMITEN_SHFT 1 + +/* TX_ACOMP_THRESHOLD */ +#define TX_ACOMP_THRESHOLD 0x2201 + +/* TX_ACOMP_ATTACK_TIME */ +#define TX_ACOMP_ATTACK_TIME 0x2202 +#define TX_ACOMP_ATTACK_TIME_MASK 0x000F +#define TX_ACOMP_ATTACK_TIME_SHFT 0 + +/* TX_ACOMP_RELEASE_TIME */ +#define TX_ACOMP_RELEASE_TIME 0x2203 +#define TX_ACOMP_RELEASE_TIME_MASK 0x0007 +#define TX_ACOMP_RELEASE_TIME_SHFT 0 + +/* TX_ACOMP_GAIN */ +#define TX_ACOMP_GAIN 0x2204 +#define TX_ACOMP_GAIN_MASK 0x003F +#define TX_ACOMP_GAIN_SHFT 0 + +/* TX_LIMITER_RELEASE_TIME */ +#define TX_LIMITER_RELEASE_TIME 0x2205 + +/* TX_ASQ_INT_SELECT */ +#define TX_ASQ_INT_SELECT 0x2300 +#define TX_ASQ_INT_SELECT_IALLIEN_MASK 0x0001 +#define TX_ASQ_INT_SELECT_IALHIEN_MASK 0x0002 +#define TX_ASQ_INT_SELECT_OVERMODIEN_MASK 0x0004 +#define TX_ASQ_INT_SELECT_IALLIEN_SHFT 0 +#define TX_ASQ_INT_SELECT_IALHIEN_SHFT 1 +#define TX_ASQ_INT_SELECT_OVERMODIEN_SHFT 2 + +/* TX_ASQ_LEVEL_LOW */ +#define TX_ASQ_LEVEL_LOW 0x2301 +#define TX_ASQ_LEVEL_LOW_MASK 0x00FF +#define TX_ASQ_LEVEL_LOW_SHFT 0 + +/* TX_ASQ_DURATION_LOW */ +#define TX_ASQ_DURATION_LOW 0x2302 + +/* TX_ASQ_LEVEL_HIGH */ +#define TX_ASQ_LEVEL_HIGH 0x2303 +#define TX_ASQ_LEVEL_HIGH_MASK 0x00FF +#define TX_ASQ_LEVEL_HIGH_SHFT 0 + +/* TX_ASQ_DURATION_LOW */ +#define TX_ASQ_DURATION_HIGH 0x2304 + +/* TX_RDS_INT_SOURCE */ +#define TX_RDS_INT_SOURCE 0x2C00 +#define TX_RDS_INT_SOURCE_FIFOMT_MASK 0x0001 +#define TX_RDS_INT_SOURCE_CBUFWRAP_MASK 0x0002 +#define TX_RDS_INT_SOURCE_FIFOXMIT_MASK 0x0004 +#define TX_RDS_INT_SOURCE_CBUFXMIT_MASK 0x0008 +#define TX_RDS_INT_SOURCE_PSXMIT_MASK 0x0010 +#define TX_RDS_INT_SOURCE_FIFOMT_SHFT 0 +#define TX_RDS_INT_SOURCE_CBUFWRAP_SHFT 1 +#define TX_RDS_INT_SOURCE_FIFOXMIT_SHFT 2 +#define TX_RDS_INT_SOURCE_CBUFXMIT_SHFT 3 +#define TX_RDS_INT_SOURCE_PSXMIT_SHFT 4 + +/* TX_RDS_PI */ +#define TX_RDS_PI 0x2C01 + +/* TX_RDS_PS_MIX */ +#define TX_RDS_PS_MIX 0x2C02 +#define TX_RDS_PS_MIX_MASK 0x0007 +#define TX_RDS_PS_MIX_SHFT 0 + +/* TX_RDS_PS_MISC */ +#define TX_RDS_PS_MISC 0x2C03 +#define TX_RDS_PS_MISC_RDSMS_MASK 0x0008 +#define TX_RDS_PS_MISC_RDSTA_MASK 0x0010 +#define TX_RDS_PS_MISC_RDSPTY_MASK 0x03E0 +#define TX_RDS_PS_MISC_RDSTP_MASK 0x0400 +#define TX_RDS_PS_MISC_FORCEB_MASK 0x0800 +#define TX_RDS_PS_MISC_RDSD0_MASK 0x1000 +#define TX_RDS_PS_MISC_RDSD1_MASK 0x2000 +#define TX_RDS_PS_MISC_RDSD2_MASK 0x4000 +#define TX_RDS_PS_MISC_RDSD3_MASK 0x8000 +#define TX_RDS_PS_MISC_RDSMS_SHFT 3 +#define TX_RDS_PS_MISC_RDSTA_SHFT 4 +#define TX_RDS_PS_MISC_RDSPTY_SHFT 5 +#define TX_RDS_PS_MISC_RDSTP_SHFT 10 +#define TX_RDS_PS_MISC_FORCEB_SHFT 11 +#define TX_RDS_PS_MISC_RDSD0_SHFT 12 +#define TX_RDS_PS_MISC_RDSD1_SHFT 13 +#define TX_RDS_PS_MISC_RDSD2_SHFT 14 +#define TX_RDS_PS_MISC_RDSD3_SHFT 15 + +/* TX_RDS_PS_REPEAT_COUNT */ +#define TX_RDS_PS_REPEAT_COUNT 0x2C04 +#define TX_RDS_PS_REPEAT_COUNT_MASK 0x00FF +#define TX_RDS_PS_REPEAT_COUNT_SHFT 0 + +/* TX_RDS_PS_MESSAGE_COUNT */ +#define TX_RDS_PS_MESSAGE_COUNT 0x2C05 +#define TX_RDS_PS_MESSAGE_COUNT_MASK 0x000F +#define TX_RDS_PS_MESSAGE_COUNT_SHFT 0 + +/* TX_RDS_PS_AF */ +#define TX_RDS_PS_AF 0x2C06 + +/* TX_RDS_FIFO_SIZE */ +#define TX_RDS_FIFO_SIZE 0x2C07 +#define TX_RDS_FIFO_SIZE_MASK 0x00FF +#define TX_RDS_FIFO_SIZE_SHFT 0 + + +/*================================================================== + AM Receive Properties +==================================================================*/ + +/* AM_DEEMPHASIS */ +#define AM_DEEMPHASIS 0x3100 +#define AM_DEEMPHASIS_MASK 0x0001 +#define AM_DEEMPHASIS_SHFT 0 + +/* AM_CHANNEL_FILTER */ +#define AM_CHANNEL_FILTER 0x3102 +#define AM_CHANNEL_FILTER_MASK 0x0007 +#define AM_CHANNEL_FILTER_SHFT 0 + +/* AM_RSQ_INT_SOURCE */ +#define AM_RSQ_INT_SOURCE 0x3200 +#define AM_RSQ_INT_SOURCE_RSSILIEN_MASK 0x0001 +#define AM_RSQ_INT_SOURCE_RSSIHIEN_MASK 0x0002 +#define AM_RSQ_INT_SOURCE_ASNRLIEN_MASK 0x0004 +#define AM_RSQ_INT_SOURCE_ASNRHIEN_MASK 0x0008 +#define AM_RSQ_INT_SOURCE_RSSILIEN_SHFT 0 +#define AM_RSQ_INT_SOURCE_RSSIHIEN_SHFT 1 +#define AM_RSQ_INT_SOURCE_ASNRLIEN_SHFT 2 +#define AM_RSQ_INT_SOURCE_ASNRHIEN_SHFT 3 + +/* AM_RSQ_SNR_HI_THRESHOLD */ +#define AM_RSQ_SNR_HI_THRESHOLD 0x3201 +#define AM_RSQ_SNR_HI_THRESHOLD_MASK 0x007F +#define AM_RSQ_SNR_HI_THRESHOLD_SHFT 0 + +/* AM_RSQ_SNR_LO_THRESHOLD */ +#define AM_RSQ_SNR_LO_THRESHOLD 0x3202 +#define AM_RSQ_SNR_LO_THRESHOLD_MASK 0x007F +#define AM_RSQ_SNR_LO_THRESHOLD_SHFT 0 + +/* AM_RSQ_RSSI_HI_THRESHOLD */ +#define AM_RSQ_RSSI_HI_THRESHOLD 0x3203 +#define AM_RSQ_RSSI_HI_THRESHOLD_MASK 0x007F +#define AM_RSQ_RSSI_HI_THRESHOLD_SHFT 0 + +/* AM_RSQ_RSSI_LO_THRESHOLD */ +#define AM_RSQ_RSSI_LO_THRESHOLD 0x3204 +#define AM_RSQ_RSSI_LO_THRESHOLD_MASK 0x007F +#define AM_RSQ_RSSI_LO_THRESHOLD_SHFT 0 + +/* AM_SOFT_MUTE_RATE */ +#define AM_SOFT_MUTE_RATE 0x3300 + +/* AM_SOFT_MUTE_SLOPE */ +#define AM_SOFT_MUTE_SLOPE 0x3301 +#define AM_SOFT_MUTE_SLOPE_MASK 0x000F +#define AM_SOFT_MUTE_SLOPE_SHFT 0 + +/* AM_SOFT_MUTE_MAX_ATTENUATION */ +#define AM_SOFT_MUTE_MAX_ATTENUATION 0x3302 +#define AM_SOFT_MUTE_MAX_ATTENUATION_MASK 0x003F +#define AM_SOFT_MUTE_MAX_ATTENUATION_SHFT 0 + +/* AM_SOFT_MUTE_SNR_THRESHOLD */ +#define AM_SOFT_MUTE_SNR_THRESHOLD 0x3303 +#define AM_SOFT_MUTE_SNR_THRESHOLD_MASK 0x003F +#define AM_SOFT_MUTE_SNR_THRESHOLD_SHFT 0 + +/* AM_SEEK_BAND_BOTTOM */ +#define AM_SEEK_BAND_BOTTOM 0x3400 + +/* AM_SEEK_BAND_TOP */ +#define AM_SEEK_BAND_TOP 0x3401 + +/* AM_SEEK_FREQ_SPACING */ +#define AM_SEEK_FREQ_SPACING 0x3402 +#define AM_SEEK_FREQ_SPACING_MASK 0x000F +#define AM_SEEK_FREQ_SPACING_SHFT 0 + +/* AM_SEEK_TUNE_SNR_THRESHOLD */ +#define AM_SEEK_TUNE_SNR_THRESHOLD 0x3403 +#define AM_SEEK_TUNE_SNR_THRESHOLD_MASK 0x003F +#define AM_SEEK_TUNE_SNR_THRESHOLD_SHFT 0 + +/* AM_SEEK_TUNE_RSSI_THRESHOLD */ +#define AM_SEEK_TUNE_RSSI_THRESHOLD 0x3404 +#define AM_SEEK_TUNE_RSSI_THRESHOLD_MASK 0x003F +#define AM_SEEK_TUNE_RSSI_THRESHOLD_SHFT 0 + +/*================================================================== + General Receive Properties +==================================================================*/ + +/* RX_VOLUME */ +#define RX_VOLUME 0x4000 +#define RX_VOLUME_MASK 0x003F +#define RX_VOLUME_SHFT 0 + +/* RX_HARD_MUTE */ +#define RX_HARD_MUTE 0x4001 +#define RX_HARD_MUTE_RMUTE_MASK 0x0001 +#define RX_HARD_MUTE_LMUTE_MASK 0x0002 +#define RX_HARD_MUTE_RMUTE_SHFT 0 +#define RX_HARD_MUTE_LMUTE_SHFT 1 + +/*================================================================== + Bit Definitions for Properties +==================================================================*/ + +/* DIGITAL_MODE - used for input or output */ +#define DIGITAL_MODE_I2S 0x0 +#define DIGITAL_MODE_LEFT 0x6 +#define DIGITAL_MODE_MSB1ST 0xC +#define DIGITAL_MODE_MSB2ND 0x8 + +/* DIGITAL_SIZE - used for input or output */ +#define DIGITAL_SIZE_16 0x0 +#define DIGITAL_SIZE_20 0x1 +#define DIGITAL_SIZE_24 0x2 +#define DIGITAL_SIZE_8 0x3 + +/* FM_DEEMPH */ +#define FM_DEEMPH_75US 0x2 +#define FM_DEEMPH_50US 0x1 + +/* FM_RDS_BLETH - used for all block error thresholds */ +#define FM_RDS_BLETH_NO_ERRORS 0x0 +#define FM_RDS_BLETH_1OR2_ERRORS 0x1 +#define FM_RDS_BLETH_3TO5_ERRORS 0x2 +#define FM_RDS_BLETH_UNCORRECTABLE 0x3 + +/* TX_LINE_INPUT_LEVEL_LIATTEN */ +#define TX_LINE_INPUT_LEVEL_LIATTEN_396kOhm 0x0000 +#define TX_LINE_INPUT_LEVEL_LIATTEN_100kOhm 0x1000 +#define TX_LINE_INPUT_LEVEL_LIATTEN_74kOhm 0x2000 +#define TX_LINE_INPUT_LEVEL_LIATTEN_60kOhm 0x3000 + +/* TX_DEEMPHASIS */ +#define TX_PREEMPHASIS_75US 0x0 +#define TX_PREEMPHASIS_50US 0x1 +#define TX_PREEMPHASIS_DISABLED 0x2 + +/* TX_ACOMP_ATTACK_TIME */ +#define TX_ACOMP_ATTACK_TIME_0_5MS 0x0 +#define TX_ACOMP_ATTACK_TIME_1_0MS 0x1 +#define TX_ACOMP_ATTACK_TIME_1_5MS 0x2 +#define TX_ACOMP_ATTACK_TIME_2_0MS 0x3 +#define TX_ACOMP_ATTACK_TIME_2_5MS 0x4 +#define TX_ACOMP_ATTACK_TIME_3_0MS 0x5 +#define TX_ACOMP_ATTACK_TIME_3_5MS 0x6 +#define TX_ACOMP_ATTACK_TIME_4_0MS 0x7 +#define TX_ACOMP_ATTACK_TIME_4_5MS 0x8 +#define TX_ACOMP_ATTACK_TIME_5_0MS 0x9 + +/* TX_ACOMP_RELEASE_TIME */ +#define TX_ACOMP_RELEASE_TIME_100MS 0x0 +#define TX_ACOMP_RELEASE_TIME_200MS 0x1 +#define TX_ACOMP_RELEASE_TIME_350MS 0x2 +#define TX_ACOMP_RELEASE_TIME_525MS 0x3 +#define TX_ACOMP_RELEASE_TIME_1000MS 0x4 + +/* TX_RDS_PS_MIX */ +#define TX_RDS_PS_MIX_FIFO_EMPTY 0x0 +#define TX_RDS_PS_MIX_12_5_PCT 0x1 +#define TX_RDS_PS_MIX_25_PCT 0x2 +#define TX_RDS_PS_MIX_50_PCT 0x3 +#define TX_RDS_PS_MIX_75_PCT 0x4 +#define TX_RDS_PS_MIX_87_5_PCT 0x5 +#define TX_RDS_PS_MIX_100_PCT 0x6 + +/* TX_RDS_PS_MISC_PTY */ +#define TX_RDS_PS_MISC_PTY_NONE 0 +#define TX_RDS_PS_MISC_PTY_NEWS 1 +#define TX_RDS_PS_MISC_PTY_INFO 2 +#define TX_RDS_PS_MISC_PTY_SPORTS 3 +#define TX_RDS_PS_MISC_PTY_TALK 4 +#define TX_RDS_PS_MISC_PTY_ROCK 5 +#define TX_RDS_PS_MISC_PTY_CLROCK 6 +#define TX_RDS_PS_MISC_PTY_ADHITS 7 +#define TX_RDS_PS_MISC_PTY_SOFTROCK 8 +#define TX_RDS_PS_MISC_PTY_TOP40 9 +#define TX_RDS_PS_MISC_PTY_COUNTRY 10 +#define TX_RDS_PS_MISC_PTY_OLDIES 11 +#define TX_RDS_PS_MISC_PTY_SOFT 12 +#define TX_RDS_PS_MISC_PTY_NOST 13 +#define TX_RDS_PS_MISC_PTY_JAZZ 14 +#define TX_RDS_PS_MISC_PTY_CLASS 15 +#define TX_RDS_PS_MISC_PTY_RHYBLUES 16 +#define TX_RDS_PS_MISC_PTY_SOFTRB 17 +#define TX_RDS_PS_MISC_PTY_FGNLANG 18 +#define TX_RDS_PS_MISC_PTY_RMUSIC 19 +#define TX_RDS_PS_MISC_PTY_RTALK 20 +#define TX_RDS_PS_MISC_PTY_PERS 21 +#define TX_RDS_PS_MISC_PTY_PUBLIC 22 +#define TX_RDS_PS_MISC_PTY_COLLEGE 23 +#define TX_RDS_PS_MISC_PTY_UN24 24 +#define TX_RDS_PS_MISC_PTY_UN25 25 +#define TX_RDS_PS_MISC_PTY_UN26 26 +#define TX_RDS_PS_MISC_PTY_UN27 27 +#define TX_RDS_PS_MISC_PTY_UN28 28 +#define TX_RDS_PS_MISC_PTY_WTHR 29 +#define TX_RDS_PS_MISC_PTY_EMERTEST 30 +#define TX_RDS_PS_MISC_PTY_ALERT 31 + +/* AM_CHANNEL_FILTER_BW */ +#define AM_CHANNEL_FILTER_BW_6KHZ 0 +#define AM_CHANNEL_FILTER_BW_4KHZ 1 +#define AM_CHANNEL_FILTER_BW_3KHZ 2 +#define AM_CHANNEL_FILTER_BW_2KHZ 3 + + +/*================================================================== + WB Receive Properties +==================================================================*/ + + +/* WB_MAX_TUNE_ERROR */ +#define WB_MAX_TUNE_ERROR 0x5108 + +/* WB_VALID_SNR_THRESHOLD */ +#define WB_VALID_SNR_THRESHOLD 0x5403 +#define WB_VALID_SNR_THRESHOLD_MASK 0x007F +#define WB_VALID_SNR_THRESHOLD_SHFT 0 + +/* WB_VALID_RSSI_THRESHOLD */ +#define WB_VALID_RSSI_THRESHOLD 0x5404 +#define WB_VALID_RSSI_THRESHOLD_MASK 0x007F +#define WB_VALID_RSSI_THRESHOLD_SHFT 0 + +#endif |