diff options
| author | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
| commit | 8e4bff4cab0ddac6060645b0715210484d02ff40 (patch) | |
| tree | 3a5c3024371a04692a3a6d9974d001cdff8ebf84 /drivers/misc/fm_2351 | |
Diffstat (limited to 'drivers/misc/fm_2351')
| -rw-r--r-- | drivers/misc/fm_2351/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/misc/fm_2351/Makefile | 4 | ||||
| -rw-r--r-- | drivers/misc/fm_2351/sr2351_fm_ctrl.c | 473 | ||||
| -rw-r--r-- | drivers/misc/fm_2351/sr2351_fm_ctrl.h | 274 | ||||
| -rw-r--r-- | drivers/misc/fm_2351/sr2351_fm_rf.c | 822 |
5 files changed, 1584 insertions, 0 deletions
diff --git a/drivers/misc/fm_2351/Kconfig b/drivers/misc/fm_2351/Kconfig new file mode 100644 index 00000000..6b926be8 --- /dev/null +++ b/drivers/misc/fm_2351/Kconfig @@ -0,0 +1,11 @@ +config SR2351_FM + tristate "SPRD 2351 FM Support" + ---help--- + Say Y to enable built-in wireless MAC controller in the + Spreadtrum SC88xx based System-on-Chip devices. + +config FM_SEEK_STEP_50KHZ + tristate "Trout FM Seek Step 50KHz Support " + default n + help + If you say yes here you can support Step 50KHz for Trout FM.
\ No newline at end of file diff --git a/drivers/misc/fm_2351/Makefile b/drivers/misc/fm_2351/Makefile new file mode 100644 index 00000000..0bd4a888 --- /dev/null +++ b/drivers/misc/fm_2351/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_SR2351_FM) := trout_fm.o +trout_fm-y := sr2351_fm_ctrl.o \ + sr2351_fm_rf.o + diff --git a/drivers/misc/fm_2351/sr2351_fm_ctrl.c b/drivers/misc/fm_2351/sr2351_fm_ctrl.c new file mode 100644 index 00000000..d98c5f03 --- /dev/null +++ b/drivers/misc/fm_2351/sr2351_fm_ctrl.c @@ -0,0 +1,473 @@ +#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/module.h> +#include <linux/platform_device.h> +#include <asm/io.h> +#include "sr2351_fm_ctrl.h" + +#ifdef CONFIG_OF +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#endif + +#define SR2351_FM_VERSION "v0.9" +static u32 g_volume = 0; + +int sr2351_fm_set_volume(u32 iarg) +{ + SR2351_PRINT("FM set volume : %i.", iarg); + + g_volume = iarg; + if(0 == iarg) + { + sr2351_fm_mute(); + } + else + { + sr2351_fm_unmute(); + } + + return 0; +} + +u32 sr2351_fm_get_volume(void) +{ + SR2351_PRINT("FM get volume."); + return g_volume; +} + + + +int sr2351_fm_open(struct inode *inode, struct file *filep) +{ + int ret = -EINVAL; + int status; + + SR2351_PRINT("start open shark fm module..."); +/* + if (get_suspend_state() != PM_SUSPEND_ON) + { + SR2351_PRINT("The system is suspending!"); + return -2; + } +*/ +/* + ret = nonseekable_open(inode, filep); + if (ret < 0) { + SR2351_PRINT("open misc device failed."); + return ret; + } +*/ + + ret = sr2351_fm_init(); + if (ret < 0) { + SR2351_PRINT("sr2351_fm_init failed!"); + return ret; + } + + ret = sr2351_fm_get_status(&status); + if (ret < 0) { + SR2351_PRINT("sr2351_read_fm_en failed!"); + return ret; + } + if (status) { + SR2351_PRINT("sr2351 fm have been opened."); + } else { + ret = sr2351_fm_en(); + if (ret < 0) { + SR2351_PRINT("sr2351_fm_en failed!"); + return ret; + } + } + + SR2351_PRINT("Open shark fm module success."); + + return 0; +} + +long sr2351_fm_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + long ret = 0; + u32 iarg = 0; + u32 buf[4] = { 0 }; + + SR2351_PRINT("FM IOCTL: 0x%x.", cmd); + + switch (cmd) { + case FM_IOCTL_ENABLE: + if (copy_from_user(&iarg, argp, sizeof(iarg)) || iarg > 1) + ret = -EFAULT; + + if (iarg == 1) + ret = sr2351_fm_en(); + else + ret = sr2351_fm_dis(); + + break; + + case FM_IOCTL_GET_ENABLE: + ret = sr2351_fm_get_status(&iarg); + if (copy_to_user(argp, &iarg, sizeof(iarg))) + ret = -EFAULT; + + break; + + case FM_IOCTL_SET_TUNE: + if (copy_from_user(&iarg, argp, sizeof(iarg))) + return -EFAULT; + sr2351_fm_mute(); + ret = sr2351_fm_set_tune(iarg); + sr2351_fm_unmute(); + break; + + case FM_IOCTL_GET_FREQ: + ret = sr2351_fm_get_frequency(&iarg); + if (copy_to_user(argp, &iarg, sizeof(iarg))) + ret = -EFAULT; + break; + + case FM_IOCTL_SEARCH: + if (copy_from_user(buf, argp, sizeof(buf))) + ret = -EFAULT; + sr2351_fm_mute(); + ret = sr2351_fm_seek(buf[0], /* start frequency */ + buf[1], /* seek direction */ + buf[2], /* time out */ + &buf[3]); /* frequency found */ + + if (copy_to_user(argp, buf, sizeof(buf))) + ret = -EFAULT; + + break; + + case FM_IOCTL_STOP_SEARCH: + ret = sr2351_fm_stop_seek(); + break; + + case FM_IOCTL_MUTE: + break; + + case FM_IOCTL_SET_VOLUME: + if (copy_from_user(&iarg, argp, sizeof(iarg))) + ret = -EFAULT; + + ret = sr2351_fm_set_volume(iarg); + break; + + case FM_IOCTL_GET_VOLUME: + iarg = sr2351_fm_get_volume(); + if (copy_to_user(argp, &iarg, sizeof(iarg))) + ret = -EFAULT; + + break; + + case FM_IOCTL_CONFIG: + if (copy_from_user(&iarg, argp, sizeof(iarg))) + ret = -EFAULT; + + SR2351_PRINT("\n\nFM FM_IOCTL_CONFIG set %d\n\n", iarg); + + break; + + case FM_IOCTL_GET_RSSI: + ret = sr2351_fm_get_rssi(&iarg); + if(copy_to_user(argp,&iarg,sizeof(iarg))) + ret = -EFAULT; + break; + + case FM_IOCTL_SET_BAND: + if (copy_from_user(buf, argp, sizeof(buf))) + ret = -EFAULT; + ret = sr2351_fm_set_band(buf[0],//min freq + buf[1]);//max freq + break; + + case FM_IOCTL_CHECK_STATUS: + ret = sr2351_fm_check_status(&iarg); + if(copy_to_user(argp,&iarg,sizeof(iarg))) + ret = -EFAULT; + break; + + default: + SR2351_PRINT("Unknown FM IOCTL!"); + return -EINVAL; + } + + return ret; +} + +int sr2351_fm_release(struct inode *inode, struct file *filep) +{ + SR2351_PRINT("sr2351_fm_misc_release"); + + sr2351_fm_deinit(); + + return 0; +} + +const struct file_operations sr2351_fm_misc_fops = { + .owner = THIS_MODULE, + .open = sr2351_fm_open, + .unlocked_ioctl = sr2351_fm_ioctl, + .release = sr2351_fm_release, +}; + +struct miscdevice sr2351_fm_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = SR2351_FM_DEV_NAME, + .fops = &sr2351_fm_misc_fops, +}; + +#ifdef CONFIG_OF +static struct sr2351_fm_addr +{ + unsigned long fm_base; + unsigned long apb_base; + unsigned long pmu_base; + unsigned long aonckg_base; + unsigned long pin_base; +}sr2351_fm_base; + +unsigned long rf2351_fm_get_fm_base(void) +{ + return sr2351_fm_base.fm_base; +} +unsigned long rf2351_fm_get_apb_base(void) +{ + return sr2351_fm_base.apb_base; +} + +unsigned long rf2351_fm_get_pmu_base(void) +{ + return sr2351_fm_base.pmu_base; +} + +unsigned long rf2351_fm_get_aonckg_base(void) +{ + return sr2351_fm_base.aonckg_base; +} + +unsigned long rf2351_fm_get_pin_base(void) +{ + return sr2351_fm_base.pin_base; +} + +static int sr2351_fm_parse_dts(struct device_node *np) +{ + int ret; + struct resource res; + + //np = of_find_node_by_name(NULL, "sprd_fm"); + if (NULL == np) + { + SR2351_PRINT("Can't get the sprd_fm node!\n"); + return -ENODEV; + } + SR2351_PRINT(" find the fm_sr2351 node!\n"); + + ret = of_address_to_resource(np, 0, &res); + if (ret < 0) + { + SR2351_PRINT("Can't get the fm reg base!\n"); + return -EIO; + } + sr2351_fm_base.fm_base = (unsigned long)ioremap_nocache(res.start, resource_size(&res)); + if(!sr2351_fm_base.fm_base) + { + BUG(); + } + SR2351_PRINT("fm reg base is 0x%x\n", sr2351_fm_base.fm_base); + + ret = of_address_to_resource(np, 1, &res); + if (ret < 0) + { + SR2351_PRINT("Can't get the apb reg base!\n"); + return -EIO; + } + sr2351_fm_base.apb_base = (unsigned long)ioremap_nocache(res.start, resource_size(&res)); + if(!sr2351_fm_base.apb_base) + { + BUG(); + } + SR2351_PRINT("apb reg base is 0x%x\n", sr2351_fm_base.apb_base); + + ret = of_address_to_resource(np, 2, &res); + if (ret < 0) + { + SR2351_PRINT("Can't get the pmu reg base!\n"); + return -EIO; + } + sr2351_fm_base.pmu_base = (unsigned long)ioremap_nocache(res.start, resource_size(&res)); + if(!sr2351_fm_base.pmu_base) + { + BUG(); + } + SR2351_PRINT("pmu reg base is 0x%x\n", sr2351_fm_base.pmu_base); + + ret = of_address_to_resource(np, 3, &res); + if (ret < 0) + { + SR2351_PRINT("Can't get the aonckg reg base!\n"); + return -EIO; + } + sr2351_fm_base.aonckg_base = (unsigned long)ioremap_nocache(res.start, resource_size(&res)); + if(!sr2351_fm_base.aonckg_base) + { + BUG(); + } + SR2351_PRINT("pmu reg base is 0x%x\n", sr2351_fm_base.aonckg_base); + + ret = of_address_to_resource(np, 4, &res); + if (ret < 0) + { + SR2351_PRINT("Can't get the pin reg base!\n"); + return -EIO; + } + sr2351_fm_base.pin_base = (unsigned long)ioremap_nocache(res.start, resource_size(&res)); + if(!sr2351_fm_base.pin_base) + { + BUG(); + } + SR2351_PRINT("pin reg base is 0x%x\n", sr2351_fm_base.pin_base); + + + return 0; +} + +static const struct of_device_id of_match_table_fm[] = { + { .compatible = "sprd,sprd_fm", }, + { }, +}; +MODULE_DEVICE_TABLE(of, of_match_table_fm); +#endif + +static int sr2351_fm_probe(struct platform_device *pdev) +{ + int ret = -EINVAL; + char *ver_str = SR2351_FM_VERSION; + +#ifdef CONFIG_OF + struct device_node *np; + np = pdev->dev.of_node; + + ret = sr2351_fm_parse_dts(np); + if (ret < 0) + { + SR2351_PRINT("sr2351_fm_parse_dts failed!"); + return ret; + } +#endif + + SR2351_PRINT("**********************************************"); + SR2351_PRINT(" SR2351 FM driver "); + SR2351_PRINT(" Version: %s", ver_str); + SR2351_PRINT(" Build date: %s %s", __DATE__, __TIME__); + SR2351_PRINT("**********************************************"); + + ret = misc_register(&sr2351_fm_misc_device); + if (ret < 0) + { + SR2351_PRINT("misc_register failed!"); + return ret; + } + + SR2351_PRINT("sr2351_fm_init success.\n"); + + return 0; +} + +static int sr2351_fm_remove(struct platform_device *pdev) +{ + + SR2351_PRINT("exit_fm_driver!\n"); + misc_deregister(&sr2351_fm_misc_device); + + return 0; +} + +#ifdef CONFIG_PM +static int sr2351_fm_suspend(struct platform_device *dev, pm_message_t state) +{ + sr2351_fm_enter_sleep(); + return 0; +} + +static int sr2351_fm_resume(struct platform_device *dev) +{ + sr2351_fm_exit_sleep(); + return 0; +} +#else +#define sr2351_fmt_suspend NULL +#define sr2351_fm_resume NULL +#endif + + +static struct platform_driver sr2351_fm_driver = { + .driver = { + .name = "sprd_fm", + .owner = THIS_MODULE, + #ifdef CONFIG_OF + .of_match_table = of_match_ptr(of_match_table_fm) , + #endif + }, + .probe = sr2351_fm_probe, + .remove = sr2351_fm_remove, + .suspend = sr2351_fm_suspend, + .resume = sr2351_fm_resume, +}; + +#ifndef CONFIG_OF +struct platform_device sr2351_fm_device = { + .name = "sprd_fm", + .id = -1, +}; +#endif + +int __init init_fm_driver(void) +{ + int ret; +#ifndef CONFIG_OF + ret = platform_device_register(&sr2351_fm_device); + if (ret) + { + SR2351_PRINT("sr2351_fm: platform_device_register failed: %d\n", ret); + return ret; + } +#endif + ret = platform_driver_register(&sr2351_fm_driver); + if (ret) + { + #ifndef CONFIG_OF + platform_device_unregister(&sr2351_fm_device); + #endif + SR2351_PRINT("sr2351_fm: probe failed: %d\n", ret); + } + SR2351_PRINT("sr2351_fm: probe sucess: %d\n", ret); + + return ret; +} + +void __exit exit_fm_driver(void) +{ + platform_driver_unregister(&sr2351_fm_driver); +} + +module_init(init_fm_driver); +module_exit(exit_fm_driver); + +MODULE_DESCRIPTION("SR2351 FM radio driver"); +MODULE_AUTHOR("Spreadtrum Inc."); +MODULE_LICENSE("GPL"); +MODULE_VERSION(SR2351_FM_VERSION); + diff --git a/drivers/misc/fm_2351/sr2351_fm_ctrl.h b/drivers/misc/fm_2351/sr2351_fm_ctrl.h new file mode 100644 index 00000000..40587790 --- /dev/null +++ b/drivers/misc/fm_2351/sr2351_fm_ctrl.h @@ -0,0 +1,274 @@ +#ifndef SR2351_FM_CTRL_H__ +#define SR2351_FM_CTRL_H_ + +#include <soc/sprd/hardware.h> +#include <linux/sprd_2351.h> +#include <soc/sprd/sci_glb_regs.h> +#include <soc/sprd/sci.h> + +#define SR2351_FM_DEV_NAME "Trout_FM" + + +extern int sr2351_fm_en(void); +extern int sr2351_fm_dis(void); +extern int sr2351_fm_get_status(int *status); +extern int sr2351_fm_get_frequency(u32 *); +extern void sr2351_fm_enter_sleep(void); +extern void sr2351_fm_exit_sleep(void); +extern void sr2351_fm_mute(void); +extern void sr2351_fm_unmute(void); +extern int sr2351_fm_init(void); +extern int sr2351_fm_deinit(void); +extern int sr2351_fm_set_tune(u32 freq); +extern int sr2351_fm_seek(u32 frequency, u32 seek_dir, u32 time_out, u32 *freq_found); +extern int sr2351_fm_stop_seek(void); +extern int sr2351_fm_get_rssi(u32 *); +extern int sr2351_fm_set_band(u32 min_fm_freq,u32 max_fm_freq); +extern int sr2351_fm_check_status(u8 *fm_status); + + +/*FM Module Start*/ +/* seek direction */ +#define SR2351_SEEK_DIR_UP 0 +#define SR2351_SEEK_DIR_DOWN 1 +#define SR2351_SEEK_TIMEOUT 1 + +/** The following define the IOCTL command values via the ioctl macros */ +#define FM_IOCTL_BASE 'R' +#define FM_IOCTL_ENABLE _IOW(FM_IOCTL_BASE, 0, int) +#define FM_IOCTL_GET_ENABLE _IOW(FM_IOCTL_BASE, 1, int) +#define FM_IOCTL_SET_TUNE _IOW(FM_IOCTL_BASE, 2, int) +#define FM_IOCTL_GET_FREQ _IOW(FM_IOCTL_BASE, 3, int) +#define FM_IOCTL_SEARCH _IOW(FM_IOCTL_BASE, 4, int[4]) +#define FM_IOCTL_STOP_SEARCH _IOW(FM_IOCTL_BASE, 5, int) +#define FM_IOCTL_MUTE _IOW(FM_IOCTL_BASE, 6, int) +#define FM_IOCTL_SET_VOLUME _IOW(FM_IOCTL_BASE, 7, int) +#define FM_IOCTL_GET_VOLUME _IOW(FM_IOCTL_BASE, 8, int) +#define FM_IOCTL_CONFIG _IOW(FM_IOCTL_BASE, 9, int) +#define FM_IOCTL_GET_RSSI _IOW(FM_IOCTL_BASE, 10, int) +#define FM_IOCTL_SET_BAND _IOW(FM_IOCTL_BASE, 11, int[2]) +#define FM_IOCTL_CHECK_STATUS _IOW(FM_IOCTL_BASE, 12,int) + + + +#ifdef CONFIG_FM_SEEK_STEP_50KHZ +#define MAX_FM_FREQ 10800 +#define MIN_FM_FREQ 8750 +#else +#define MAX_FM_FREQ 1080 +#define MIN_FM_FREQ 875 +#endif + +#define FM_CTL_STI_MODE_NORMAL 0x0 +#define FM_CTL_STI_MODE_SEEK 0x1 +#define FM_CTL_STI_MODE_TUNE 0x2 + +#ifndef CONFIG_OF +#define SHARK_FM_REG_BASE SPRD_FM_BASE +#define SHARK_APB_BASE_ADDR SPRD_AONAPB_BASE +#define SHARK_PMU_BASE_ADDR SPRD_PMU_BASE +#define SHARK_AON_CLK_BASE_ADDR SPRD_AONCKG_BASE +#define SHARK_PIN_BASE SPRD_PIN_BASE +#else +extern unsigned long rf2351_fm_get_fm_base(void); +extern unsigned long rf2351_fm_get_apb_base(void); +extern unsigned long rf2351_fm_get_pmu_base(void); +extern unsigned long rf2351_fm_get_aonckg_base(void); +extern unsigned long rf2351_fm_get_pin_base(void); + +#define SHARK_FM_REG_BASE rf2351_fm_get_fm_base() +#define SHARK_APB_BASE_ADDR rf2351_fm_get_apb_base() +#define SHARK_PMU_BASE_ADDR rf2351_fm_get_pmu_base() +#define SHARK_AON_CLK_BASE_ADDR rf2351_fm_get_aonckg_base() +#define SHARK_PIN_BASE rf2351_fm_get_pin_base() +#endif + +#define FM_REG_FM_CTRL (SHARK_FM_REG_BASE + 0x0000) +#define FM_REG_FM_EN (SHARK_FM_REG_BASE + 0x0004) +#define FM_REG_RF_INIT_GAIN (SHARK_FM_REG_BASE + 0x0008) +#define FM_REG_CHAN (SHARK_FM_REG_BASE + 0x000C) +#define FM_REG_AGC_TBL_CLK (SHARK_FM_REG_BASE + 0x0010) +#define FM_REG_SEEK_LOOP (SHARK_FM_REG_BASE + 0x0014) +#define FM_REG_FMCTL_STI (SHARK_FM_REG_BASE + 0x0018) +#define FM_REG_BAND_LMT (SHARK_FM_REG_BASE + 0x001C) +#define FM_REG_BAND_SPACE (SHARK_FM_REG_BASE + 0x0020) +#define FM_REG_RF_CTL (SHARK_FM_REG_BASE + 0x0024) +#define FM_REG_RF_CTL1 (SHARK_FM_REG_BASE + 0x0028) +#define FM_REG_INT_EN (SHARK_FM_REG_BASE + 0x0030) +#define FM_REG_INT_CLR (SHARK_FM_REG_BASE + 0x0034) +#define FM_REG_INT_STS (SHARK_FM_REG_BASE + 0x0038) +#define FM_REG_ADC_INFCTRL (SHARK_FM_REG_BASE + 0x003C) +#define FM_REG_SEEK_CH_TH (SHARK_FM_REG_BASE + 0x0040) +#define FM_REG_AGC_TBL_RFRSSI0 (SHARK_FM_REG_BASE + 0x0044) +#define FM_REG_AGC_TBL_RFRSSI1 (SHARK_FM_REG_BASE + 0x0048) +#define FM_REG_AGC_TBL_WBRSSI (SHARK_FM_REG_BASE + 0x004C) +#define FM_REG_AGC_IDX_TH (SHARK_FM_REG_BASE + 0x0050) +#define FM_REG_AGC_RSSI_TH (SHARK_FM_REG_BASE + 0x0054) +#define FM_REG_SEEK_ADPS (SHARK_FM_REG_BASE + 0x0058) +#define FM_REG_STER_PWR (SHARK_FM_REG_BASE + 0x005C) +#define FM_REG_AGC_CTRL (SHARK_FM_REG_BASE + 0x0060) +#define FM_REG_AGC_ITV_TH (SHARK_FM_REG_BASE + 0x0064) +#define FM_REG_AGC_ADPS0 (SHARK_FM_REG_BASE + 0x0068) +#define FM_REG_AGC_ADPS1 (SHARK_FM_REG_BASE + 0x006C) +#define FM_REG_PDP_TH (SHARK_FM_REG_BASE + 0x0070) +#define FM_REG_PDP_DEV (SHARK_FM_REG_BASE + 0x0074) +#define FM_REG_ADP_ST_CONF (SHARK_FM_REG_BASE + 0x0078) +#define FM_REG_ADP_LPF_CONF (SHARK_FM_REG_BASE + 0x007C) +#define FM_REG_DEPHA_SCAL (SHARK_FM_REG_BASE + 0x0080) +#define FM_REG_HW_MUTE (SHARK_FM_REG_BASE + 0x0084) +#define FM_REG_SW_MUTE (SHARK_FM_REG_BASE + 0x0088) +#define FM_REG_UPD_CTRL (SHARK_FM_REG_BASE + 0x008C) +#define FM_REG_AUD_BLD0 (SHARK_FM_REG_BASE + 0x0090) +#define FM_REG_AUD_BLD1 (SHARK_FM_REG_BASE + 0x0094) +#define FM_REG_AGC_HYS (SHARK_FM_REG_BASE + 0x0098) +#define FM_REG_MONO_PWR (SHARK_FM_REG_BASE + 0x009C) +#define FM_REG_RF_CFG_DLY (SHARK_FM_REG_BASE + 0x00A0) +#define FM_REG_AGC_TBL_STS (SHARK_FM_REG_BASE + 0x00A4) +#define FM_REG_ADP_BIT_SFT (SHARK_FM_REG_BASE + 0x00A8) +#define FM_REG_SEEK_CNT (SHARK_FM_REG_BASE + 0x00AC) +#define FM_REG_RSSI_STS (SHARK_FM_REG_BASE + 0x00B0) +#define FM_REG_CHAN_FREQ_STS (SHARK_FM_REG_BASE + 0x00B8) +#define FM_REG_FREQ_OFF_STS (SHARK_FM_REG_BASE + 0x00BC) +#define FM_REG_INPWR_STS (SHARK_FM_REG_BASE + 0x00C0) +#define FM_REG_RF_RSSI_STS (SHARK_FM_REG_BASE + 0x00C4) +#define FM_REG_NO_LPF_STS (SHARK_FM_REG_BASE + 0x00C8) +#define FM_REG_SMUTE_STS (SHARK_FM_REG_BASE + 0x00CC) +#define FM_REG_WBRSSI_STS (SHARK_FM_REG_BASE + 0x00D0) +#define FM_REG_AGC_BITS_TBL0 (SHARK_FM_REG_BASE + 0x0100) +#define FM_REG_AGC_BITS_TBL1 (SHARK_FM_REG_BASE + 0x0104) +#define FM_REG_AGC_BITS_TBL2 (SHARK_FM_REG_BASE + 0x0108) +#define FM_REG_AGC_BITS_TBL3 (SHARK_FM_REG_BASE + 0x010C) +#define FM_REG_AGC_BITS_TBL4 (SHARK_FM_REG_BASE + 0x0110) +#define FM_REG_AGC_BITS_TBL5 (SHARK_FM_REG_BASE + 0x0114) +#define FM_REG_AGC_BITS_TBL6 (SHARK_FM_REG_BASE + 0x0118) +#define FM_REG_AGC_BITS_TBL7 (SHARK_FM_REG_BASE + 0x011C) +#define FM_REG_AGC_BITS_TBL8 (SHARK_FM_REG_BASE + 0x0120) +#define FM_REG_AGC_BITS_TBL9 (SHARK_FM_REG_BASE + 0x0124) +#define FM_REG_AGC_BITS_TBL10 (SHARK_FM_REG_BASE + 0x0128) +#define FM_REG_AGC_BITS_TBL11 (SHARK_FM_REG_BASE + 0x012C) +#define FM_REG_AGC_BITS_TBL12 (SHARK_FM_REG_BASE + 0x0130) +#define FM_REG_AGC_BITS_TBL13 (SHARK_FM_REG_BASE + 0x0134) +#define FM_REG_AGC_BITS_TBL14 (SHARK_FM_REG_BASE + 0x0138) +#define FM_REG_AGC_BITS_TBL15 (SHARK_FM_REG_BASE + 0x013C) +#define FM_REG_AGC_BITS_TBL16 (SHARK_FM_REG_BASE + 0x0140) +#define FM_REG_AGC_BITS_TBL17 (SHARK_FM_REG_BASE + 0x0144) +#define FM_REG_AGC_VAL_TBL0 (SHARK_FM_REG_BASE + 0x0200) +#define FM_REG_AGC_VAL_TBL1 (SHARK_FM_REG_BASE + 0x0204) +#define FM_REG_AGC_VAL_TBL2 (SHARK_FM_REG_BASE + 0x0208) +#define FM_REG_AGC_VAL_TBL3 (SHARK_FM_REG_BASE + 0x020C) +#define FM_REG_AGC_VAL_TBL4 (SHARK_FM_REG_BASE + 0x0210) +#define FM_REG_AGC_VAL_TBL5 (SHARK_FM_REG_BASE + 0x0214) +#define FM_REG_AGC_VAL_TBL6 (SHARK_FM_REG_BASE + 0x0218) +#define FM_REG_AGC_VAL_TBL7 (SHARK_FM_REG_BASE + 0x021C) +#define FM_REG_AGC_VAL_TBL8 (SHARK_FM_REG_BASE + 0x0220) +#define FM_REG_AGC_VAL_TBL9 (SHARK_FM_REG_BASE + 0x0224) +#define FM_REG_AGC_VAL_TBL10 (SHARK_FM_REG_BASE + 0x0228) +#define FM_REG_AGC_VAL_TBL11 (SHARK_FM_REG_BASE + 0x022C) +#define FM_REG_AGC_VAL_TBL12 (SHARK_FM_REG_BASE + 0x0230) +#define FM_REG_AGC_VAL_TBL13 (SHARK_FM_REG_BASE + 0x0234) +#define FM_REG_AGC_VAL_TBL14 (SHARK_FM_REG_BASE + 0x0238) +#define FM_REG_AGC_VAL_TBL15 (SHARK_FM_REG_BASE + 0x023C) +#define FM_REG_AGC_VAL_TBL16 (SHARK_FM_REG_BASE + 0x0240) +#define FM_REG_AGC_VAL_TBL17 (SHARK_FM_REG_BASE + 0x0244) +#define FM_REG_AGC_BOND_TBL0 (SHARK_FM_REG_BASE + 0x0300) +#define FM_REG_AGC_BOND_TBL1 (SHARK_FM_REG_BASE + 0x0304) +#define FM_REG_AGC_BOND_TBL2 (SHARK_FM_REG_BASE + 0x0308) +#define FM_REG_AGC_BOND_TBL3 (SHARK_FM_REG_BASE + 0x030C) +#define FM_REG_AGC_BOND_TBL4 (SHARK_FM_REG_BASE + 0x0310) +#define FM_REG_AGC_BOND_TBL5 (SHARK_FM_REG_BASE + 0x0314) +#define FM_REG_AGC_BOND_TBL6 (SHARK_FM_REG_BASE + 0x0318) +#define FM_REG_AGC_BOND_TBL7 (SHARK_FM_REG_BASE + 0x031C) +#define FM_REG_AGC_BOND_TBL8 (SHARK_FM_REG_BASE + 0x0320) +#define FM_REG_AGC_BOND_TBL9 (SHARK_FM_REG_BASE + 0x0324) + +#define FM_REG_SPUR_FREQ0 (SHARK_FM_REG_BASE + 0x340) /* new reg*/ +#define FM_REG_SPUR_FREQ1 (SHARK_FM_REG_BASE + 0X344) /* new reg*/ + +#define FM_REG_SPUR_RM_CTL (SHARK_FM_REG_BASE + 0X348) +#define FM_SPUR_RM_CTL_DEFAULT_VALUE (0X88FFFF) +#define FM_SPUR_RM_CTL_SET_VALUE (0X551F1F) +#define FM_REG_SPUR_DC_RM_CTL (SHARK_FM_REG_BASE + 0X34C) +#define FM_SPUR_DC_RM_CTL_DEFAULT_VALUE (0X10FFFF) +#define FM_SPUR_DC_RM_CTL_SET_VALUE (0XA03FF) + + +#define FM_REG_AGC_DB_TBL_BEGIN (SHARK_FM_REG_BASE + 0x0500) +#define FM_REG_AGC_DB_TBL_END (SHARK_FM_REG_BASE + 0x05A0) +#define FM_REG_AGC_DB_TBL_CNT \ + ((0x5a0-0x500)/4 + 1) + +#define FM_REG_SPI_CTL (SHARK_FM_REG_BASE + 0x0810) +#define FM_REG_SPI_WD0 (SHARK_FM_REG_BASE + 0x0814) +#define FM_REG_SPI_WD1 (SHARK_FM_REG_BASE + 0x0818) +#define FM_REG_SPI_RD (SHARK_FM_REG_BASE + 0x081C) +#define FM_REG_SPI_FIFO_STS (SHARK_FM_REG_BASE + 0x0820) + +#define SHARK_APB_EB0 REG_AON_APB_APB_EB0 +#define SHARK_APB_EB1 REG_AON_APB_APB_EB1 +#define SHARK_APB_RST0 REG_AON_APB_APB_RST0 +#define SHARK_APB_EB0_SET (REG_AON_APB_APB_EB0+0x1000) + +#define SHARK_PMU_SLEEP_CTRL REG_PMU_APB_SLEEP_CTRL + +#define SHARK_PMU_APB_MEM_PD_CFG0 REG_PMU_APB_MEM_PD_CFG0 + +#if defined(CONFIG_ARCH_SCX30G) +#define SHARK_MSPI_CLK_SWITCH (SHARK_AON_CLK_BASE_ADDR + 0x0054) +#elif defined(CONFIG_ARCH_SCX15) || defined(CONFIG_ARCH_SCX35) +#define SHARK_MSPI_CLK_SWITCH (SHARK_AON_CLK_BASE_ADDR + 0x0050) +#endif + +#define SHARK_PMU_APB_PD_AP_SYS_CFG REG_PMU_APB_PD_AP_SYS_CFG + +#define INT_NUM_FM_test 27 + +#define SHARK_CHIP_BD 1 + +#define SHARK_PIN_U0TXD (SHARK_PIN_BASE + 0x0048) +#define SHARK_PIN_U0RXD (SHARK_PIN_BASE + 0x004c) +#define SHARK_PIN_U0CTS (SHARK_PIN_BASE + 0x0050) + + +struct shark_fm_info_t { + int int_happen; + int seek_success; + u32 freq_set; + u32 freq_seek; + u32 freq_offset; + u32 rssi; + u32 rf_rssi; + u32 seek_cnt; + u32 inpwr_sts; + u32 fm_sts; + u32 agc_sts; + /*void (*irq_handler)(u32);*/ +}; + + +struct shark_reg_cfg_t { + unsigned int reg_addr; + unsigned int reg_data; +}; + +/*FM Module End*/ + +/*2351 RF Start*/ + +#define FM_SR2351_ADC_CLK 0x06F +#define FM_SR2351_DCOC_CAL_TIMER 0x471 +#define FM_SR2351_RC_TUNER 0x477 +#define FM_SR2351_RX_ADC_CLK 0x478 +#define FM_SR2351_OVERLOAD_DET 0x431 +#define FM_SR2351_RX_GAIN 0x404 +#define FM_SR2351_MODE 0x400 +#define FM_SR2351_FREQ 0x402 + +/*2351 RF End*/ + +#define SR2351_PRINT(format, arg...) \ + do { \ + printk("sr2351_fm %s-%d -- "format"\n", \ + __func__, __LINE__, ## arg); \ + } while (0) + +#endif 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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_data); + if(0X1 == (reg_data >> 31)) + { + *fm_status = 0x00; + + }else if(0X0 == (reg_data >> 31)) + { + + *fm_status = 0x01; + + }else + { + *fm_status = 0x02; + } + return 0; +} + |
