summaryrefslogtreecommitdiff
path: root/drivers/misc/fm_2351/sr2351_fm_rf.c
diff options
context:
space:
mode:
authorYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
committerYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
commit8e4bff4cab0ddac6060645b0715210484d02ff40 (patch)
tree3a5c3024371a04692a3a6d9974d001cdff8ebf84 /drivers/misc/fm_2351/sr2351_fm_rf.c
Initial file dump from open source releaseHEADmaster
Diffstat (limited to 'drivers/misc/fm_2351/sr2351_fm_rf.c')
-rw-r--r--drivers/misc/fm_2351/sr2351_fm_rf.c822
1 files changed, 822 insertions, 0 deletions
diff --git a/drivers/misc/fm_2351/sr2351_fm_rf.c b/drivers/misc/fm_2351/sr2351_fm_rf.c
new file mode 100644
index 00000000..c7464568
--- /dev/null
+++ b/drivers/misc/fm_2351/sr2351_fm_rf.c
@@ -0,0 +1,822 @@
+#include <linux/miscdevice.h>
+#include <linux/sysfs.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/ioctl.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <asm/io.h>
+#ifdef CONFIG_ARCH_SCX20
+#include <linux/sprd_2351.h>
+#endif
+
+#include "sr2351_fm_ctrl.h"
+
+static u32 LOCAL_MIN_FM_FREQ = MIN_FM_FREQ;
+static u32 LOCAL_MAX_FM_FREQ = MAX_FM_FREQ;
+
+struct sprd_2351_interface *fm_rf_ops = NULL;
+
+struct shark_fm_info_t shark_fm_info = {
+ 1, /* int_happen;*/
+ 1, /* seek_success;*/
+ 0, /* freq_set;*/
+ 0, /* freq_seek;*/
+ 0, /* freq_offset;*/
+ 0, /* rssi;*/
+ 0, /* rf_rssi;*/
+ 0, /* seek_cnt;*/
+ 0, /* inpwr_sts;*/
+ 0, /* fm_sts;*/
+ 0, /* agc_sts*/
+ /*shark_fm_irq_handler, (*irq_handler)(u32);*/
+};
+
+typedef struct {
+ uint32_t ver;
+ uint8_t cap;
+}rom_callback_func_t;
+
+unsigned int get_shark_chip_id(void)
+{
+ unsigned int code_addr = 0;
+ unsigned int header_phy_addr = 0;
+ unsigned int header_addr = 0;
+ unsigned int header_offset = 0;
+ unsigned int chip_ver=0;
+
+ code_addr =(volatile unsigned int) ioremap((unsigned int)0xFFFF0000,0x4000);
+ header_phy_addr = (rom_callback_func_t *)(*((unsigned int*)(code_addr +0x20)));
+ header_offset=header_phy_addr-0xffff0000;
+ header_addr=header_offset+code_addr;
+ chip_ver=*(unsigned int *)(header_addr);
+
+ iounmap(code_addr);
+
+ return chip_ver;
+}
+
+static void read_fm_reg(u32 reg_addr, u32 *reg_data)
+{
+ *reg_data = sci_glb_read(reg_addr,-1UL);
+}
+
+static unsigned int write_fm_reg(u32 reg_addr, u32 val)
+{
+ sci_glb_write(reg_addr, val, -1UL);
+ return 0;
+}
+
+static void fm_register_set(void)
+{
+ write_fm_reg(FM_REG_FM_CTRL , 0x00001011);
+ write_fm_reg(FM_REG_FM_EN , 0x000032EE);
+ write_fm_reg(FM_REG_CHAN , (899-1)*2);
+ write_fm_reg(FM_REG_AGC_TBL_CLK, 0x00000000);
+#ifdef CONFIG_FM_SEEK_STEP_50KHZ
+ write_fm_reg(FM_REG_SEEK_LOOP , (LOCAL_MAX_FM_FREQ - LOCAL_MIN_FM_FREQ)/10));
+#else
+ write_fm_reg(FM_REG_SEEK_LOOP , (LOCAL_MAX_FM_FREQ - LOCAL_MIN_FM_FREQ));
+#endif
+ write_fm_reg(FM_REG_FMCTL_STI , 0x0);
+#ifdef CONFIG_FM_SEEK_STEP_50KHZ
+ write_fm_reg(FM_REG_BAND_LMT , ((((LOCAL_MAX_FM_FREQ/10) - 1) * 2)<<16) | (((LOCAL_MIN_FM_FREQ/10)-1)*2));
+#else
+ write_fm_reg(FM_REG_BAND_LMT , (((LOCAL_MAX_FM_FREQ - 1) * 2)<<16) | ((LOCAL_MIN_FM_FREQ-1)*2));
+#endif
+#ifdef CONFIG_FM_SEEK_STEP_50KHZ
+ write_fm_reg(FM_REG_BAND_SPACE , 0x00000001);
+#else
+ write_fm_reg(FM_REG_BAND_SPACE , 0x00000002);
+#endif
+ write_fm_reg(FM_REG_ADC_INFCTRL, 0);
+ write_fm_reg(FM_REG_SEEK_CH_TH , 2000);
+ write_fm_reg(FM_REG_AGC_TBL_RFRSSI0, 0x00020800);
+ write_fm_reg(FM_REG_AGC_TBL_RFRSSI1, (31 << 24) | (5 << 16) | (3000));
+ write_fm_reg(FM_REG_AGC_TBL_WBRSSI , 0x00F60C12);
+ write_fm_reg(FM_REG_AGC_IDX_TH , 0x00020407);
+ write_fm_reg(FM_REG_AGC_RSSI_TH , 0x00F600D8);
+ write_fm_reg(FM_REG_SEEK_ADPS , 0x0CD80000);
+ write_fm_reg(FM_REG_STER_PWR , 0x000001A6);
+ write_fm_reg(FM_REG_MONO_PWR , 0x019C0192);
+ write_fm_reg(FM_REG_AGC_CTRL , 0x09040120);
+ write_fm_reg(FM_REG_AGC_ITV_TH , 0x00FE00EE);
+ write_fm_reg(FM_REG_AGC_ADPS0 , 0xFDF70009);
+ write_fm_reg(FM_REG_AGC_ADPS1 , 0xFEF80003);
+ write_fm_reg(FM_REG_PDP_TH , 400);
+ write_fm_reg(FM_REG_PDP_DEV , 120);
+ write_fm_reg(FM_REG_ADP_ST_CONF , 0x200501BA);
+ write_fm_reg(FM_REG_ADP_LPF_CONF , 2);
+ write_fm_reg(FM_REG_DEPHA_SCAL , 5);
+ write_fm_reg(FM_REG_HW_MUTE , 0);
+ write_fm_reg(FM_REG_SW_MUTE , 0x01A601A1);
+ write_fm_reg(FM_REG_UPD_CTRL , 0x01013356);
+ write_fm_reg(FM_REG_AUD_BLD0 , 0x01AD01A1);
+ write_fm_reg(FM_REG_AUD_BLD1 , 0x81A901A5);
+ write_fm_reg(FM_REG_AGC_HYS , 0x00000202);
+ write_fm_reg(FM_REG_RF_CFG_DLY , 20000);
+ write_fm_reg(FM_REG_RF_INIT_GAIN, 0x0303);
+ write_fm_reg(FM_REG_AGC_BITS_TBL0 , 0x0000);
+ write_fm_reg(FM_REG_AGC_BITS_TBL1 , 0x0001);
+ write_fm_reg(FM_REG_AGC_BITS_TBL2 , 0x0301);
+ write_fm_reg(FM_REG_AGC_BITS_TBL3 , 0x0302);
+ write_fm_reg(FM_REG_AGC_BITS_TBL4 , 0x0303);
+ write_fm_reg(FM_REG_AGC_BITS_TBL5 , 0x0313);
+ write_fm_reg(FM_REG_AGC_BITS_TBL6 , 0x0323);
+ write_fm_reg(FM_REG_AGC_BITS_TBL7 , 0x0333);
+ write_fm_reg(FM_REG_AGC_BITS_TBL8 , 0x0335);
+ write_fm_reg(FM_REG_AGC_BITS_TBL9 , 0x0000);
+ write_fm_reg(FM_REG_AGC_BITS_TBL10 , 0x0001);
+ write_fm_reg(FM_REG_AGC_BITS_TBL11 , 0x0301);
+ write_fm_reg(FM_REG_AGC_BITS_TBL12 , 0x0302);
+ write_fm_reg(FM_REG_AGC_BITS_TBL13 , 0x0303);
+ write_fm_reg(FM_REG_AGC_BITS_TBL14 , 0x0313);
+ write_fm_reg(FM_REG_AGC_BITS_TBL15 , 0x0323);
+ write_fm_reg(FM_REG_AGC_BITS_TBL16 , 0x0333);
+ write_fm_reg(FM_REG_AGC_BITS_TBL17 , 0x0335);
+ write_fm_reg(FM_REG_AGC_VAL_TBL0 , 7);
+ write_fm_reg(FM_REG_AGC_VAL_TBL1 , 21);
+ write_fm_reg(FM_REG_AGC_VAL_TBL2 , 29);
+ write_fm_reg(FM_REG_AGC_VAL_TBL3 , 35);
+ write_fm_reg(FM_REG_AGC_VAL_TBL4 , 41);
+ write_fm_reg(FM_REG_AGC_VAL_TBL5 , 47);
+ write_fm_reg(FM_REG_AGC_VAL_TBL6 , 53);
+ write_fm_reg(FM_REG_AGC_VAL_TBL7 , 59);
+ write_fm_reg(FM_REG_AGC_VAL_TBL8 , 71);
+ write_fm_reg(FM_REG_AGC_BOND_TBL0 , -120UL);
+ write_fm_reg(FM_REG_AGC_BOND_TBL1 , -89UL);
+ write_fm_reg(FM_REG_AGC_BOND_TBL2 , -83UL);
+ write_fm_reg(FM_REG_AGC_BOND_TBL3 , -77UL);
+ write_fm_reg(FM_REG_AGC_BOND_TBL4 , -41UL);
+ write_fm_reg(FM_REG_AGC_BOND_TBL5 , -35UL);
+ write_fm_reg(FM_REG_AGC_BOND_TBL6 , -29UL);
+ write_fm_reg(FM_REG_AGC_BOND_TBL7 , -21UL);
+ write_fm_reg(FM_REG_AGC_BOND_TBL8 , -13UL);
+ write_fm_reg(FM_REG_AGC_BOND_TBL9 , 10);
+ write_fm_reg(FM_REG_SPUR_FREQ0 , 0x0000081e);
+}
+
+void shark_fm_seek_up(void)
+{
+#ifdef CONFIG_FM_SEEK_STEP_50KHZ
+ write_fm_reg(FM_REG_CHAN, shark_fm_info.freq_seek+1);
+#else
+ write_fm_reg(FM_REG_CHAN, shark_fm_info.freq_seek+2);
+#endif
+ sci_glb_set(FM_REG_FM_CTRL, BIT_19);
+}
+
+void shark_fm_seek_down(void)
+{
+#ifdef CONFIG_FM_SEEK_STEP_50KHZ
+ write_fm_reg(FM_REG_CHAN, shark_fm_info.freq_seek-1);
+#else
+ write_fm_reg(FM_REG_CHAN, shark_fm_info.freq_seek-2);
+#endif
+ sci_glb_clr(FM_REG_FM_CTRL, BIT_19);
+}
+
+
+
+irqreturn_t fm_interrupt(int irq, void *dev_id)
+{
+ SR2351_PRINT("interrupt bingo~~~~~~~~~~~~~\n");
+
+ return IRQ_HANDLED;
+}
+
+
+void sr2351_fm_config_xtl(void)
+{
+ sci_glb_set(SHARK_APB_EB0_SET, BIT_20);
+ sci_glb_set(SHARK_PMU_SLEEP_CTRL, BIT_8);
+}
+
+
+int sr2351_fm_en(void)
+{
+#if defined(CONFIG_ARCH_SCX30G)
+
+ //sci_glb_clr(SHARK_PMU_APB_PD_AP_SYS_CFG,BIT_24);
+ sci_glb_clr(SHARK_PIN_U0TXD,BIT_0|BIT_1);
+ sci_glb_set(SHARK_PIN_U0TXD,BIT_0);
+ sci_glb_clr(SHARK_PIN_U0RXD,BIT_0|BIT_1);
+ sci_glb_set(SHARK_PIN_U0RXD,BIT_0);
+ sci_glb_clr(SHARK_PIN_U0CTS,BIT_0|BIT_1);
+ sci_glb_set(SHARK_PIN_U0CTS,BIT_0);
+
+#endif
+ sci_glb_set(FM_REG_FM_EN, BIT_31);
+
+ return 0;
+}
+
+
+int sr2351_fm_dis(void)
+{
+#if defined(CONFIG_ARCH_SCX30G)
+
+ //sci_glb_set(SHARK_PMU_APB_PD_AP_SYS_CFG,BIT_24);
+
+ sci_glb_clr(SHARK_PIN_U0TXD,BIT_0|BIT_1);
+ sci_glb_set(SHARK_PIN_U0TXD,BIT_1);
+ sci_glb_clr(SHARK_PIN_U0RXD,BIT_0|BIT_1);
+ sci_glb_set(SHARK_PIN_U0RXD,BIT_1);
+ sci_glb_clr(SHARK_PIN_U0CTS,BIT_0|BIT_1);
+ sci_glb_set(SHARK_PIN_U0CTS,BIT_1);
+#endif
+ sci_glb_clr(FM_REG_FM_EN, BIT_31);
+
+ return 0;
+}
+
+int sr2351_fm_get_status(int *status)
+{
+ u32 reg_data = 0;
+ read_fm_reg(FM_REG_FM_EN, &reg_data);
+ *status = reg_data >> 31;
+ return 0;
+}
+
+void sr2351_fm_enter_sleep(void)
+{
+ unsigned int chip_ver=0;
+
+ #ifdef CONFIG_ARCH_SCX30G
+ sci_glb_clr(SHARK_PMU_APB_MEM_PD_CFG0,BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0);
+ #endif
+
+ if(fm_rf_ops != NULL)
+ {
+ #if defined(CONFIG_ARCH_SCX15) || defined(CONFIG_ARCH_SCX30G)
+
+ /*Disable the RSSI AGC*/
+ sci_glb_clr(FM_REG_FM_EN, BIT_2 | BIT_3);
+ udelay(5);
+
+ /*Switch the mspi clock*/
+ #if defined(CONFIG_ARCH_SCX30G)
+ printk("2351 fm enter sleep switch clock\n");
+ sci_glb_clr(SHARK_MSPI_CLK_SWITCH, BIT_0);
+ #elif defined(CONFIG_ARCH_SCX15)
+ sci_glb_set(SHARK_MSPI_CLK_SWITCH, BIT_0 | BIT_1);
+ #endif
+
+ /*Enable the RSSI AGC*/
+ sci_glb_set(FM_REG_FM_EN, BIT_2 | BIT_3);
+
+ #elif defined(CONFIG_ARCH_SCX35)
+
+ chip_ver = get_shark_chip_id();
+ //TROUT_PRINT("chip_ver in trout_fm_enter_sleep : %d\r\n", chip_ver);
+ /*
+ * BD version is the latest version for shark chip .
+ * In this version, hardware fix the FM sleep bug about the Sensitivity.
+ * So we need modify the sleep action based on the shark chip version.
+ * The chip id of BD/BC version is 1 ,and the one of the old version is 0,
+ * such as BA/BB
+ */
+ if(chip_ver == 0)
+ {
+ sci_glb_clr(FM_REG_FM_EN,BIT_2|BIT_3);
+
+ } else if (SHARK_CHIP_BD == chip_ver) {
+ /*Disable the RSSI AGC*/
+ sci_glb_clr(FM_REG_FM_EN, BIT_2 | BIT_3);
+ udelay(5);
+
+ /*Switch the mspi clock*/
+ sci_glb_set(SHARK_MSPI_CLK_SWITCH, BIT_0 | BIT_1);
+
+ /*Enable the RSSI AGC*/
+ sci_glb_set(FM_REG_FM_EN, BIT_2 | BIT_3);
+ }
+
+
+ #endif
+
+ fm_rf_ops->write_reg(FM_SR2351_RX_GAIN, 0x0313);
+ }
+}
+
+void sr2351_fm_exit_sleep(void)
+{
+ unsigned int chip_ver=0;
+
+ if(fm_rf_ops != NULL)
+ {
+ #if defined(CONFIG_ARCH_SCX15) || defined(CONFIG_ARCH_SCX30G)
+ /*Disable the RSSI AGC*/
+ sci_glb_clr(FM_REG_FM_EN, BIT_2 | BIT_3);
+ udelay(5);
+
+ /*Switch the mspi clock*/
+ #if defined(CONFIG_ARCH_SCX30G)
+ printk("2351 fm exit sleep switch clock\n");
+ sci_glb_set(SHARK_MSPI_CLK_SWITCH, BIT_0);
+ #elif defined(CONFIG_ARCH_SCX15)
+ sci_glb_clr(SHARK_MSPI_CLK_SWITCH, BIT_0 | BIT_1);
+ #endif
+
+ /*Enable the RSSI AGC*/
+ sci_glb_set(FM_REG_FM_EN, BIT_2 | BIT_3);
+
+ #elif defined(CONFIG_ARCH_SCX35)
+
+ chip_ver = get_shark_chip_id();
+ //TROUT_PRINT("chip_ver in trout_fm_exit_sleep : %d\r\n", chip_ver);
+ /*
+ * BD version is the latest version for shark chip .
+ * In this version, hardware fix the FM sleep bug about the Sensitivity.
+ * So we need modify the sleep action based on the shark chip version.
+ * The chip id of BD/BC version is 1 ,and the one of the old version is 0,
+ * such as BA/BB
+ */
+ if(chip_ver == 0)
+ {
+ sci_glb_set(FM_REG_FM_EN, BIT_2|BIT_3);
+
+ } else if (SHARK_CHIP_BD == chip_ver) {
+ /*Disable the RSSI AGC*/
+ sci_glb_clr(FM_REG_FM_EN, BIT_2 | BIT_3);
+ udelay(5);
+
+ /*Switch the mspi clock*/
+ sci_glb_clr(SHARK_MSPI_CLK_SWITCH, BIT_0 | BIT_1);
+
+ /*Enable the RSSI AGC*/
+ sci_glb_set(FM_REG_FM_EN, BIT_2 | BIT_3);
+ }
+
+ #endif
+ }
+
+ #ifdef CONFIG_ARCH_SCX30G
+ sci_glb_set(SHARK_PMU_APB_MEM_PD_CFG0,BIT_5|BIT_3|BIT_1);
+ #endif
+}
+
+void sr2351_fm_mute(void)
+{
+ sci_glb_set(FM_REG_HW_MUTE, BIT_0);
+}
+
+void sr2351_fm_unmute(void)
+{
+ sci_glb_clr(FM_REG_HW_MUTE, BIT_0);
+}
+
+
+
+void shark_fm_int_en(void)
+{
+ shark_fm_info.int_happen = 1;
+ write_fm_reg(FM_REG_INT_EN, 0x01);/*enable fm int*/
+
+ enable_irq(INT_NUM_FM_test);
+}
+
+void shark_fm_int_dis(void)
+{
+ shark_fm_info.int_happen = 1;
+ write_fm_reg(FM_REG_INT_EN, 0x0); /*disable fm int*/
+
+}
+
+void shark_fm_int_clr(void)
+{
+ write_fm_reg(FM_REG_INT_CLR, 0x1);
+}
+
+int enable_shark_fm(void)
+{
+ u32 reg_data = 0;
+ read_fm_reg(SHARK_APB_EB0, &reg_data);
+ if (!(reg_data & BIT_1)) {
+ sci_glb_set(SHARK_APB_EB0, BIT_1);
+
+ /*reset fm*/
+ sci_glb_set(SHARK_APB_RST0, BIT_1);
+ msleep(20);
+ sci_glb_clr(SHARK_APB_RST0, BIT_1);
+ }
+
+ return 0;
+}
+
+int shark_write_regs(u32 reg_addr, u32 reg_cnt, u32 *reg_data)
+{
+ u32 i = 0;
+
+ for (i = 0; i < reg_cnt; i++) {
+ if (write_fm_reg(reg_addr+i*4, reg_data[i]) == -1)
+ return -1;
+ }
+ return 0;
+}
+
+int shark_write_reg_cfg(struct shark_reg_cfg_t *reg_cfg, u32 cfg_cnt)
+{
+ u32 i;
+ for (i = 0; i < cfg_cnt; i++) {
+ if (write_fm_reg(reg_cfg[i].reg_addr, reg_cfg[i].reg_data) == -1)
+ return -1;
+ }
+ return 0;
+}
+
+int shark_fm_reg_cfg(void)
+{
+ u32 reg_data;
+ u32 fm_reg_agc_db_tbl[FM_REG_AGC_DB_TBL_CNT] = {
+ 15848, 12589, 10000, 7943, 6309,
+ 5011, 3981, 3162, 2511, 1995,
+ 1584, 1258, 1000, 794, 630,
+ 501, 398, 316, 251, 199,
+ 158, 125, 100, 79, 63,
+ 50, 39, 31, 25, 19,
+ 15, 12, 10, 7, 6,
+ 5, 3, 3, 2, 1,
+ 1
+ };
+#if 0
+ if (shark_write_reg_cfg(fm_reg_init_des, \
+ ARRAY_SIZE(fm_reg_init_des)) == -1) {
+ /*return FALSE;*/
+ }
+#else
+ fm_register_set();
+#endif
+ if (write_fm_reg(FM_REG_AGC_TBL_CLK, 0x00000001) == -1)
+ return -1;
+ while (1) {
+ msleep(20);
+ read_fm_reg(FM_REG_AGC_TBL_CLK, &reg_data);
+ if (reg_data>>17)
+ break;
+ }
+ if (shark_write_regs(FM_REG_AGC_DB_TBL_BEGIN, FM_REG_AGC_DB_TBL_CNT, \
+ fm_reg_agc_db_tbl) == -1)
+ return -1;
+ msleep(100);
+ if (write_fm_reg(FM_REG_AGC_TBL_CLK, 0x00000000) == -1)
+ ;/*return FALSE;*/
+ return 0;
+}
+
+int shark_fm_cfg_rf_reg(void)
+{
+ fm_rf_ops->write_reg(FM_SR2351_DCOC_CAL_TIMER, 0x0FFF);
+ fm_rf_ops->write_reg(FM_SR2351_RC_TUNER, 0xFFFF);
+ fm_rf_ops->write_reg(FM_SR2351_RX_ADC_CLK, 0x001F);
+ fm_rf_ops->write_reg(FM_SR2351_RX_ADC_CLK, 0x009F);
+ fm_rf_ops->write_reg(FM_SR2351_ADC_CLK, 0x0201);
+ fm_rf_ops->write_reg(FM_SR2351_OVERLOAD_DET, 0x8022);
+
+ fm_rf_ops->write_reg(FM_SR2351_ADC_CLK, 0x0601);
+ fm_rf_ops->write_reg(FM_SR2351_RX_GAIN, 0x0335);
+ fm_rf_ops->write_reg(FM_SR2351_MODE, 0x0011);
+ fm_rf_ops->write_reg(FM_SR2351_FREQ, 0x07A6);
+ fm_rf_ops->write_reg(FM_SR2351_RX_GAIN, 0x0335);
+
+ msleep(20);
+
+ return 0;
+}
+
+int sr2351_fm_init(void)
+{
+#ifdef CONFIG_ARCH_SCX20
+ rf2351_vddwpa_ctrl_power_enable(1);
+#endif
+ sprd_get_rf2351_ops(&fm_rf_ops);
+ fm_rf_ops->mspi_enable();
+
+ sr2351_fm_config_xtl();
+
+ if (enable_shark_fm() != 0)
+ return -1;
+ msleep(20);
+
+ shark_fm_int_en();
+
+ if (shark_fm_reg_cfg() == -1)
+ return -1;
+ if (shark_fm_cfg_rf_reg() == -1)
+ return -1;
+
+ write_fm_reg(FM_REG_RF_CTL, ((0x404<<16)|(0x0402)));
+ write_fm_reg(FM_REG_RF_CTL1, ((0x0466<<16)|(0x0043)));
+
+ shark_fm_info.freq_seek = 860*2;
+ /*result = request_irq(INT_NUM_FM_test,
+ fm_interrupt, IRQF_DISABLED, "sr2351_FM", NULL);*/
+ return 0;
+}
+
+void __sr2351_fm_get_status(void)
+{
+ read_fm_reg(FM_REG_SEEK_CNT, &shark_fm_info.seek_cnt);
+ read_fm_reg(FM_REG_CHAN_FREQ_STS, &shark_fm_info.freq_seek);
+ read_fm_reg(FM_REG_FREQ_OFF_STS, &shark_fm_info.freq_offset);
+ read_fm_reg(FM_REG_RF_RSSI_STS, &shark_fm_info.rf_rssi);
+ read_fm_reg(FM_REG_RSSI_STS, &shark_fm_info.rssi);
+ read_fm_reg(FM_REG_INPWR_STS, &shark_fm_info.inpwr_sts);
+ read_fm_reg(FM_REG_WBRSSI_STS, &shark_fm_info.fm_sts);
+ read_fm_reg(FM_REG_AGC_TBL_STS, &shark_fm_info.agc_sts);
+
+}
+
+void __sr2351_fm_show_status(void)
+{
+ SR2351_PRINT("FM_REG_SEEK_CNT : %08x (%d)\r\n", \
+ shark_fm_info.seek_cnt, shark_fm_info.seek_cnt);
+#ifdef CONFIG_FM_SEEK_STEP_50KHZ
+ SR2351_PRINT("FM_REG_CHAN_FREQ_STS: %08x (%d)\r\n", \
+ shark_fm_info.freq_seek, shark_fm_info.freq_seek*5 + 10);
+#else
+ SR2351_PRINT("FM_REG_CHAN_FREQ_STS: %08x (%d)\r\n", \
+ shark_fm_info.freq_seek, ((shark_fm_info.freq_seek >> 1) + 1));
+#endif
+ SR2351_PRINT("FM_REG_FREQ_OFF_STS : %08x (%d)\r\n", \
+ shark_fm_info.freq_offset, shark_fm_info.freq_offset);
+ SR2351_PRINT("FM_REG_RF_RSSI_STS : %08x\r\n", \
+ shark_fm_info.rf_rssi);
+ SR2351_PRINT("FM_REG_INPWR_STS : %08x\r\n", \
+ shark_fm_info.inpwr_sts);
+ SR2351_PRINT("FM_REG_WBRSSI_STS : %08x\r\n", \
+ shark_fm_info.fm_sts);
+ SR2351_PRINT("FM_REG_RSSI_STS : %08x\r\n", \
+ shark_fm_info.rssi);
+ SR2351_PRINT("FM_REG_AGC_TBL_STS : %08x\r\n", \
+ shark_fm_info.agc_sts);
+
+ SR2351_PRINT("fm work:%d, fm iq:%04x\r\n", \
+ (shark_fm_info.fm_sts >> 20) & 1, \
+ (shark_fm_info.fm_sts >> 16) & 0xf);
+ SR2351_PRINT("pilot detect:%d, stero:%d, seek fail:%d, rssi:%08x\r\n", \
+ (shark_fm_info.rssi >> 18) & 0x3, \
+ (shark_fm_info.rssi >> 17) & 0x1, \
+ (shark_fm_info.rssi >> 16) & 0x1, shark_fm_info.rssi & 0xff);
+}
+
+int sr2351_fm_deinit(void)
+{
+ fm_rf_ops->write_reg(FM_SR2351_MODE, 0x0000);
+ fm_rf_ops->write_reg(FM_SR2351_ADC_CLK, 0x201);
+
+ sci_glb_clr(SHARK_PMU_SLEEP_CTRL, BIT_8);
+
+ fm_rf_ops->mspi_disable();
+ sprd_put_rf2351_ops(&fm_rf_ops);
+#ifdef CONFIG_ARCH_SCX20
+ rf2351_vddwpa_ctrl_power_enable(0);
+#endif
+
+ return 0;
+}
+
+int shark_fm_wait_int(int time_out)
+{
+ int ret = 0;
+ ulong jiffies_comp = 0;
+ u8 is_timeout = 1;
+ u32 seek_succes = 0;
+ unsigned int start_msecond = 0;
+ unsigned int end_msecond = 0;
+
+ jiffies_comp = jiffies;
+ start_msecond = jiffies_to_msecs(jiffies);
+ SR2351_PRINT("start_msecond: %u\n", start_msecond);
+ do {
+ msleep(20);
+ read_fm_reg(FM_REG_INT_STS, &seek_succes);
+
+ is_timeout = time_after(jiffies,
+ jiffies_comp +
+ msecs_to_jiffies(time_out));
+
+ if (is_timeout && (seek_succes==0))
+ {
+ SR2351_PRINT("FM search timeout.");
+ sr2351_fm_dis();
+ ret = SR2351_SEEK_TIMEOUT;
+ }
+
+ if (seek_succes)
+ {
+ SR2351_PRINT("FM found frequency.");
+ break;
+ }
+ } while (seek_succes == 0 && is_timeout == 0);
+
+ end_msecond = jiffies_to_msecs(jiffies);
+ SR2351_PRINT("end_msecond: %u\n", end_msecond);
+ SR2351_PRINT("used time: %ums\n", end_msecond - start_msecond);
+
+ __sr2351_fm_get_status();
+ __sr2351_fm_show_status();
+
+ SR2351_PRINT("\n");
+ return ret;
+}
+
+int sr2351_fm_set_tune(u32 freq)
+{
+ u32 reg_data;
+ sr2351_fm_dis();
+ shark_fm_int_dis();
+ shark_fm_int_clr();
+ /*FM_ADC_Tuning_Value_overwrite(chan);*/
+ write_fm_reg(FM_REG_FMCTL_STI, FM_CTL_STI_MODE_TUNE); /* tune mode*/
+#ifdef CONFIG_FM_SEEK_STEP_50KHZ
+ write_fm_reg(FM_REG_CHAN, ((freq-10)/5) & 0xffff);
+#else
+ write_fm_reg(FM_REG_CHAN, ((freq-1)*2) & 0xffff);
+#endif
+ shark_fm_int_en();
+ sr2351_fm_en();
+
+ read_fm_reg(FM_REG_CHAN, &reg_data);
+ SR2351_PRINT("chan reg_data is %d\n", reg_data);
+
+ shark_fm_wait_int(3000);
+
+ /*dump_fm_regs();*/
+
+ shark_fm_int_clr();
+ return 0;
+}
+
+int sr2351_fm_seek(u32 frequency, u32 seek_dir, u32 time_out, u32 *freq_found)
+{
+ int ret = 0;
+
+ SR2351_PRINT("FM seek, freq(%i) dir(%i) timeout(%i).",frequency, seek_dir, time_out);
+
+ if (frequency < LOCAL_MIN_FM_FREQ || frequency > LOCAL_MAX_FM_FREQ)
+ {
+ SR2351_PRINT("out of freq range: %i", frequency);
+ frequency = LOCAL_MIN_FM_FREQ;
+ }
+
+#ifdef CONFIG_FM_SEEK_STEP_50KHZ
+ shark_fm_info.freq_seek = ((frequency-10)/5);
+#else
+ shark_fm_info.freq_seek = ((frequency-1)*2);
+#endif
+
+ seek_dir ^= 0x1;
+ sr2351_fm_dis();
+ shark_fm_int_clr();
+
+ if (seek_dir == 0)
+ shark_fm_seek_up();
+ else
+ shark_fm_seek_down();
+
+ /*Handel False station,change the spuer value when stark seek*/
+ write_fm_reg(FM_REG_SPUR_RM_CTL, FM_SPUR_RM_CTL_SET_VALUE);
+ write_fm_reg(FM_REG_SPUR_DC_RM_CTL, FM_SPUR_DC_RM_CTL_SET_VALUE);
+ write_fm_reg(FM_REG_FMCTL_STI, FM_CTL_STI_MODE_SEEK); /* seek mode*/
+
+ shark_fm_int_en();
+ sr2351_fm_en();
+ ret = shark_fm_wait_int(time_out);
+ if (ret == SR2351_SEEK_TIMEOUT)
+ {
+#ifdef CONFIG_FM_SEEK_STEP_50KHZ
+ if (seek_dir == 0){
+ if ( LOCAL_MIN_FM_FREQ == (shark_fm_info.freq_seek*5 + 10)){
+ shark_fm_info.freq_seek = (LOCAL_MAX_FM_FREQ -10 ) /5;
+ }
+ else{
+ shark_fm_info.freq_seek -= 1;
+ }
+ }
+ else{
+ if ( LOCAL_MAX_FM_FREQ == shark_fm_info.freq_seek*5 + 10){
+ shark_fm_info.freq_seek = (LOCAL_MIN_FM_FREQ -10 ) /5;
+ }
+ else{
+ shark_fm_info.freq_seek += 1;
+ }
+ }
+ SR2351_PRINT("seek failed!");
+ SR2351_PRINT("freq=%d",shark_fm_info.freq_seek*5 + 10);
+
+#else
+ if (seek_dir == 0)
+ {
+ if ( LOCAL_MIN_FM_FREQ == ((shark_fm_info.freq_seek >> 1) + 1))
+ {
+ shark_fm_info.freq_seek = (LOCAL_MAX_FM_FREQ -1 ) * 2;
+ }
+ else
+ {
+ shark_fm_info.freq_seek -= 2;
+ }
+ }
+ else
+ {
+ if ( LOCAL_MAX_FM_FREQ == ((shark_fm_info.freq_seek >> 1) + 1))
+ {
+ shark_fm_info.freq_seek = (LOCAL_MIN_FM_FREQ -1 ) * 2;
+ }
+ else
+ {
+ shark_fm_info.freq_seek += 2;
+ }
+ }
+ SR2351_PRINT("seek time out!");
+ SR2351_PRINT("freq=%d",((shark_fm_info.freq_seek >> 1) + 1));
+#endif
+ }
+
+ /*dump_fm_regs();*/
+#ifdef CONFIG_FM_SEEK_STEP_50KHZ
+ *freq_found = shark_fm_info.freq_seek*5 + 10;
+#else
+ *freq_found = (shark_fm_info.freq_seek >> 1) + 1;
+#endif
+
+ shark_fm_int_clr();
+
+ /*Handel False station spuer,restore the default value when stop seek*/
+ write_fm_reg(FM_REG_SPUR_RM_CTL, FM_SPUR_RM_CTL_DEFAULT_VALUE);
+ write_fm_reg(FM_REG_SPUR_DC_RM_CTL, FM_SPUR_DC_RM_CTL_DEFAULT_VALUE);
+
+ return ret;
+}
+
+int sr2351_fm_get_frequency(u32 *freq)
+{
+#ifdef CONFIG_FM_SEEK_STEP_50KHZ
+ *freq = shark_fm_info.freq_seek*5 + 10;
+#else
+ *freq = ((shark_fm_info.freq_seek >> 1) + 1);
+#endif
+ return 0;
+}
+
+int sr2351_fm_stop_seek(void)
+{
+ u32 reg_value = 0x0;
+
+ SR2351_PRINT("FM stop seek.");
+
+ /* clear seek enable bit of seek register. */
+ read_fm_reg(FM_REG_FMCTL_STI, &reg_value);
+ if (reg_value & FM_CTL_STI_MODE_SEEK)
+ {
+ reg_value |= FM_CTL_STI_MODE_NORMAL;
+ write_fm_reg(FM_REG_FMCTL_STI, reg_value);
+ }
+
+ return 0;
+}
+
+int sr2351_fm_get_rssi(u32 *rssi)
+{
+ u32 reg_data;
+
+ read_fm_reg(FM_REG_INPWR_STS, &reg_data);
+ *rssi = reg_data;
+ SR2351_PRINT("rssi value in sr2351_fm_get_rssi() is %08x\r\n",*rssi);
+
+ return 0;
+}
+
+int sr2351_fm_set_band(u32 min_fm_freq,u32 max_fm_freq)
+{
+ LOCAL_MIN_FM_FREQ = min_fm_freq;
+ LOCAL_MAX_FM_FREQ = max_fm_freq;
+
+ return 0;
+}
+
+int sr2351_fm_check_status(u8 *fm_status)
+{
+ u32 reg_data = 0;
+ read_fm_reg(FM_REG_FM_EN, &reg_data);
+ if(0X1 == (reg_data >> 31))
+ {
+ *fm_status = 0x00;
+
+ }else if(0X0 == (reg_data >> 31))
+ {
+
+ *fm_status = 0x01;
+
+ }else
+ {
+ *fm_status = 0x02;
+ }
+ return 0;
+}
+