162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * FM Driver for Connectivity chip of Texas Instruments. 462306a36Sopenharmony_ci * This sub-module of FM driver implements FM RX functionality. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2011 Texas Instruments 762306a36Sopenharmony_ci * Author: Raja Mani <raja_mani@ti.com> 862306a36Sopenharmony_ci * Author: Manjunatha Halli <manjunatha_halli@ti.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "fmdrv.h" 1262306a36Sopenharmony_ci#include "fmdrv_common.h" 1362306a36Sopenharmony_ci#include "fmdrv_rx.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_civoid fm_rx_reset_rds_cache(struct fmdev *fmdev) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci fmdev->rx.rds.flag = FM_RDS_DISABLE; 1862306a36Sopenharmony_ci fmdev->rx.rds.last_blk_idx = 0; 1962306a36Sopenharmony_ci fmdev->rx.rds.wr_idx = 0; 2062306a36Sopenharmony_ci fmdev->rx.rds.rd_idx = 0; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) 2362306a36Sopenharmony_ci fmdev->irq_info.mask |= FM_LEV_EVENT; 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_civoid fm_rx_reset_station_info(struct fmdev *fmdev) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci fmdev->rx.stat_info.picode = FM_NO_PI_CODE; 2962306a36Sopenharmony_ci fmdev->rx.stat_info.afcache_size = 0; 3062306a36Sopenharmony_ci fmdev->rx.stat_info.af_list_max = 0; 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ciint fm_rx_set_freq(struct fmdev *fmdev, u32 freq) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci unsigned long timeleft; 3662306a36Sopenharmony_ci u16 payload, curr_frq, intr_flag; 3762306a36Sopenharmony_ci u32 curr_frq_in_khz; 3862306a36Sopenharmony_ci u32 resp_len; 3962306a36Sopenharmony_ci int ret; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (freq < fmdev->rx.region.bot_freq || freq > fmdev->rx.region.top_freq) { 4262306a36Sopenharmony_ci fmerr("Invalid frequency %d\n", freq); 4362306a36Sopenharmony_ci return -EINVAL; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci /* Set audio enable */ 4762306a36Sopenharmony_ci payload = FM_RX_AUDIO_ENABLE_I2S_AND_ANALOG; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, AUDIO_ENABLE_SET, REG_WR, &payload, 5062306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 5162306a36Sopenharmony_ci if (ret < 0) 5262306a36Sopenharmony_ci return ret; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* Set hilo to automatic selection */ 5562306a36Sopenharmony_ci payload = FM_RX_IFFREQ_HILO_AUTOMATIC; 5662306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, HILO_SET, REG_WR, &payload, 5762306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 5862306a36Sopenharmony_ci if (ret < 0) 5962306a36Sopenharmony_ci return ret; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* Calculate frequency index and set*/ 6262306a36Sopenharmony_ci payload = (freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload, 6562306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 6662306a36Sopenharmony_ci if (ret < 0) 6762306a36Sopenharmony_ci return ret; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci /* Read flags - just to clear any pending interrupts if we had */ 7062306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL); 7162306a36Sopenharmony_ci if (ret < 0) 7262306a36Sopenharmony_ci return ret; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* Enable FR, BL interrupts */ 7562306a36Sopenharmony_ci intr_flag = fmdev->irq_info.mask; 7662306a36Sopenharmony_ci fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT); 7762306a36Sopenharmony_ci payload = fmdev->irq_info.mask; 7862306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, 7962306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 8062306a36Sopenharmony_ci if (ret < 0) 8162306a36Sopenharmony_ci return ret; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* Start tune */ 8462306a36Sopenharmony_ci payload = FM_TUNER_PRESET_MODE; 8562306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload, 8662306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 8762306a36Sopenharmony_ci if (ret < 0) 8862306a36Sopenharmony_ci goto exit; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci /* Wait for tune ended interrupt */ 9162306a36Sopenharmony_ci init_completion(&fmdev->maintask_comp); 9262306a36Sopenharmony_ci timeleft = wait_for_completion_timeout(&fmdev->maintask_comp, 9362306a36Sopenharmony_ci FM_DRV_TX_TIMEOUT); 9462306a36Sopenharmony_ci if (!timeleft) { 9562306a36Sopenharmony_ci fmerr("Timeout(%d sec),didn't get tune ended int\n", 9662306a36Sopenharmony_ci jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); 9762306a36Sopenharmony_ci ret = -ETIMEDOUT; 9862306a36Sopenharmony_ci goto exit; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* Read freq back to confirm */ 10262306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2, &curr_frq, &resp_len); 10362306a36Sopenharmony_ci if (ret < 0) 10462306a36Sopenharmony_ci goto exit; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci curr_frq = be16_to_cpu((__force __be16)curr_frq); 10762306a36Sopenharmony_ci curr_frq_in_khz = (fmdev->rx.region.bot_freq + ((u32)curr_frq * FM_FREQ_MUL)); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (curr_frq_in_khz != freq) { 11062306a36Sopenharmony_ci pr_info("Frequency is set to (%d) but requested freq is (%d)\n", 11162306a36Sopenharmony_ci curr_frq_in_khz, freq); 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* Update local cache */ 11562306a36Sopenharmony_ci fmdev->rx.freq = curr_frq_in_khz; 11662306a36Sopenharmony_ciexit: 11762306a36Sopenharmony_ci /* Re-enable default FM interrupts */ 11862306a36Sopenharmony_ci fmdev->irq_info.mask = intr_flag; 11962306a36Sopenharmony_ci payload = fmdev->irq_info.mask; 12062306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, 12162306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 12262306a36Sopenharmony_ci if (ret < 0) 12362306a36Sopenharmony_ci return ret; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* Reset RDS cache and current station pointers */ 12662306a36Sopenharmony_ci fm_rx_reset_rds_cache(fmdev); 12762306a36Sopenharmony_ci fm_rx_reset_station_info(fmdev); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci return ret; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic int fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci u16 payload; 13562306a36Sopenharmony_ci int ret; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (spacing > 0 && spacing <= 50000) 13862306a36Sopenharmony_ci spacing = FM_CHANNEL_SPACING_50KHZ; 13962306a36Sopenharmony_ci else if (spacing > 50000 && spacing <= 100000) 14062306a36Sopenharmony_ci spacing = FM_CHANNEL_SPACING_100KHZ; 14162306a36Sopenharmony_ci else 14262306a36Sopenharmony_ci spacing = FM_CHANNEL_SPACING_200KHZ; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* set channel spacing */ 14562306a36Sopenharmony_ci payload = spacing; 14662306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, CHANL_BW_SET, REG_WR, &payload, 14762306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 14862306a36Sopenharmony_ci if (ret < 0) 14962306a36Sopenharmony_ci return ret; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci fmdev->rx.region.chanl_space = spacing * FM_FREQ_MUL; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci return ret; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ciint fm_rx_seek(struct fmdev *fmdev, u32 seek_upward, 15762306a36Sopenharmony_ci u32 wrap_around, u32 spacing) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci u32 resp_len; 16062306a36Sopenharmony_ci u16 curr_frq, next_frq, last_frq; 16162306a36Sopenharmony_ci u16 payload, int_reason, intr_flag; 16262306a36Sopenharmony_ci u16 offset, space_idx; 16362306a36Sopenharmony_ci unsigned long timeleft; 16462306a36Sopenharmony_ci int ret; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* Set channel spacing */ 16762306a36Sopenharmony_ci ret = fm_rx_set_channel_spacing(fmdev, spacing); 16862306a36Sopenharmony_ci if (ret < 0) { 16962306a36Sopenharmony_ci fmerr("Failed to set channel spacing\n"); 17062306a36Sopenharmony_ci return ret; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* Read the current frequency from chip */ 17462306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 17562306a36Sopenharmony_ci sizeof(curr_frq), &curr_frq, &resp_len); 17662306a36Sopenharmony_ci if (ret < 0) 17762306a36Sopenharmony_ci return ret; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci curr_frq = be16_to_cpu((__force __be16)curr_frq); 18062306a36Sopenharmony_ci last_frq = (fmdev->rx.region.top_freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* Check the offset in order to be aligned to the channel spacing*/ 18362306a36Sopenharmony_ci space_idx = fmdev->rx.region.chanl_space / FM_FREQ_MUL; 18462306a36Sopenharmony_ci offset = curr_frq % space_idx; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci next_frq = seek_upward ? curr_frq + space_idx /* Seek Up */ : 18762306a36Sopenharmony_ci curr_frq - space_idx /* Seek Down */ ; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* 19062306a36Sopenharmony_ci * Add or subtract offset in order to stay aligned to the channel 19162306a36Sopenharmony_ci * spacing. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ci if ((short)next_frq < 0) 19462306a36Sopenharmony_ci next_frq = last_frq - offset; 19562306a36Sopenharmony_ci else if (next_frq > last_frq) 19662306a36Sopenharmony_ci next_frq = 0 + offset; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ciagain: 19962306a36Sopenharmony_ci /* Set calculated next frequency to perform seek */ 20062306a36Sopenharmony_ci payload = next_frq; 20162306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload, 20262306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 20362306a36Sopenharmony_ci if (ret < 0) 20462306a36Sopenharmony_ci return ret; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* Set search direction (0:Seek Down, 1:Seek Up) */ 20762306a36Sopenharmony_ci payload = (seek_upward ? FM_SEARCH_DIRECTION_UP : FM_SEARCH_DIRECTION_DOWN); 20862306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, SEARCH_DIR_SET, REG_WR, &payload, 20962306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 21062306a36Sopenharmony_ci if (ret < 0) 21162306a36Sopenharmony_ci return ret; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* Read flags - just to clear any pending interrupts if we had */ 21462306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL); 21562306a36Sopenharmony_ci if (ret < 0) 21662306a36Sopenharmony_ci return ret; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* Enable FR, BL interrupts */ 21962306a36Sopenharmony_ci intr_flag = fmdev->irq_info.mask; 22062306a36Sopenharmony_ci fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT); 22162306a36Sopenharmony_ci payload = fmdev->irq_info.mask; 22262306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, 22362306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 22462306a36Sopenharmony_ci if (ret < 0) 22562306a36Sopenharmony_ci return ret; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* Start seek */ 22862306a36Sopenharmony_ci payload = FM_TUNER_AUTONOMOUS_SEARCH_MODE; 22962306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload, 23062306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 23162306a36Sopenharmony_ci if (ret < 0) 23262306a36Sopenharmony_ci return ret; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* Wait for tune ended/band limit reached interrupt */ 23562306a36Sopenharmony_ci init_completion(&fmdev->maintask_comp); 23662306a36Sopenharmony_ci timeleft = wait_for_completion_timeout(&fmdev->maintask_comp, 23762306a36Sopenharmony_ci FM_DRV_RX_SEEK_TIMEOUT); 23862306a36Sopenharmony_ci if (!timeleft) { 23962306a36Sopenharmony_ci fmerr("Timeout(%d sec),didn't get tune ended int\n", 24062306a36Sopenharmony_ci jiffies_to_msecs(FM_DRV_RX_SEEK_TIMEOUT) / 1000); 24162306a36Sopenharmony_ci return -ENODATA; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci int_reason = fmdev->irq_info.flag & (FM_TUNE_COMPLETE | FM_BAND_LIMIT); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* Re-enable default FM interrupts */ 24762306a36Sopenharmony_ci fmdev->irq_info.mask = intr_flag; 24862306a36Sopenharmony_ci payload = fmdev->irq_info.mask; 24962306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, 25062306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 25162306a36Sopenharmony_ci if (ret < 0) 25262306a36Sopenharmony_ci return ret; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (int_reason & FM_BL_EVENT) { 25562306a36Sopenharmony_ci if (wrap_around == 0) { 25662306a36Sopenharmony_ci fmdev->rx.freq = seek_upward ? 25762306a36Sopenharmony_ci fmdev->rx.region.top_freq : 25862306a36Sopenharmony_ci fmdev->rx.region.bot_freq; 25962306a36Sopenharmony_ci } else { 26062306a36Sopenharmony_ci fmdev->rx.freq = seek_upward ? 26162306a36Sopenharmony_ci fmdev->rx.region.bot_freq : 26262306a36Sopenharmony_ci fmdev->rx.region.top_freq; 26362306a36Sopenharmony_ci /* Calculate frequency index to write */ 26462306a36Sopenharmony_ci next_frq = (fmdev->rx.freq - 26562306a36Sopenharmony_ci fmdev->rx.region.bot_freq) / FM_FREQ_MUL; 26662306a36Sopenharmony_ci goto again; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci } else { 26962306a36Sopenharmony_ci /* Read freq to know where operation tune operation stopped */ 27062306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2, 27162306a36Sopenharmony_ci &curr_frq, &resp_len); 27262306a36Sopenharmony_ci if (ret < 0) 27362306a36Sopenharmony_ci return ret; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci curr_frq = be16_to_cpu((__force __be16)curr_frq); 27662306a36Sopenharmony_ci fmdev->rx.freq = (fmdev->rx.region.bot_freq + 27762306a36Sopenharmony_ci ((u32)curr_frq * FM_FREQ_MUL)); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci /* Reset RDS cache and current station pointers */ 28162306a36Sopenharmony_ci fm_rx_reset_rds_cache(fmdev); 28262306a36Sopenharmony_ci fm_rx_reset_station_info(fmdev); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci return ret; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ciint fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci u16 payload; 29062306a36Sopenharmony_ci int ret; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (fmdev->curr_fmmode != FM_MODE_RX) 29362306a36Sopenharmony_ci return -EPERM; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (vol_to_set > FM_RX_VOLUME_MAX) { 29662306a36Sopenharmony_ci fmerr("Volume is not within(%d-%d) range\n", 29762306a36Sopenharmony_ci FM_RX_VOLUME_MIN, FM_RX_VOLUME_MAX); 29862306a36Sopenharmony_ci return -EINVAL; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci vol_to_set *= FM_RX_VOLUME_GAIN_STEP; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci payload = vol_to_set; 30362306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, VOLUME_SET, REG_WR, &payload, 30462306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 30562306a36Sopenharmony_ci if (ret < 0) 30662306a36Sopenharmony_ci return ret; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci fmdev->rx.volume = vol_to_set; 30962306a36Sopenharmony_ci return ret; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci/* Get volume */ 31362306a36Sopenharmony_ciint fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci if (fmdev->curr_fmmode != FM_MODE_RX) 31662306a36Sopenharmony_ci return -EPERM; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (curr_vol == NULL) { 31962306a36Sopenharmony_ci fmerr("Invalid memory\n"); 32062306a36Sopenharmony_ci return -ENOMEM; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci *curr_vol = fmdev->rx.volume / FM_RX_VOLUME_GAIN_STEP; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci return 0; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci/* To get current band's bottom and top frequency */ 32962306a36Sopenharmony_ciint fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci if (bot_freq != NULL) 33262306a36Sopenharmony_ci *bot_freq = fmdev->rx.region.bot_freq; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (top_freq != NULL) 33562306a36Sopenharmony_ci *top_freq = fmdev->rx.region.top_freq; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci return 0; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci/* Returns current band index (0-Europe/US; 1-Japan) */ 34162306a36Sopenharmony_civoid fm_rx_get_region(struct fmdev *fmdev, u8 *region) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci *region = fmdev->rx.region.fm_band; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci/* Sets band (0-Europe/US; 1-Japan) */ 34762306a36Sopenharmony_ciint fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci u16 payload; 35062306a36Sopenharmony_ci u32 new_frq = 0; 35162306a36Sopenharmony_ci int ret; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (region_to_set != FM_BAND_EUROPE_US && 35462306a36Sopenharmony_ci region_to_set != FM_BAND_JAPAN) { 35562306a36Sopenharmony_ci fmerr("Invalid band\n"); 35662306a36Sopenharmony_ci return -EINVAL; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (fmdev->rx.region.fm_band == region_to_set) { 36062306a36Sopenharmony_ci fmerr("Requested band is already configured\n"); 36162306a36Sopenharmony_ci return 0; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci /* Send cmd to set the band */ 36562306a36Sopenharmony_ci payload = (u16)region_to_set; 36662306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, BAND_SET, REG_WR, &payload, 36762306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 36862306a36Sopenharmony_ci if (ret < 0) 36962306a36Sopenharmony_ci return ret; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci fmc_update_region_info(fmdev, region_to_set); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* Check whether current RX frequency is within band boundary */ 37462306a36Sopenharmony_ci if (fmdev->rx.freq < fmdev->rx.region.bot_freq) 37562306a36Sopenharmony_ci new_frq = fmdev->rx.region.bot_freq; 37662306a36Sopenharmony_ci else if (fmdev->rx.freq > fmdev->rx.region.top_freq) 37762306a36Sopenharmony_ci new_frq = fmdev->rx.region.top_freq; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (new_frq) { 38062306a36Sopenharmony_ci fmdbg("Current freq is not within band limit boundary,switching to %d KHz\n", 38162306a36Sopenharmony_ci new_frq); 38262306a36Sopenharmony_ci /* Current RX frequency is not in range. So, update it */ 38362306a36Sopenharmony_ci ret = fm_rx_set_freq(fmdev, new_frq); 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci return ret; 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci/* Reads current mute mode (Mute Off/On/Attenuate)*/ 39062306a36Sopenharmony_ciint fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci if (fmdev->curr_fmmode != FM_MODE_RX) 39362306a36Sopenharmony_ci return -EPERM; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (curr_mute_mode == NULL) { 39662306a36Sopenharmony_ci fmerr("Invalid memory\n"); 39762306a36Sopenharmony_ci return -ENOMEM; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci *curr_mute_mode = fmdev->rx.mute_mode; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic int fm_config_rx_mute_reg(struct fmdev *fmdev) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci u16 payload, muteval; 40862306a36Sopenharmony_ci int ret; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci muteval = 0; 41162306a36Sopenharmony_ci switch (fmdev->rx.mute_mode) { 41262306a36Sopenharmony_ci case FM_MUTE_ON: 41362306a36Sopenharmony_ci muteval = FM_RX_AC_MUTE_MODE; 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci case FM_MUTE_OFF: 41762306a36Sopenharmony_ci muteval = FM_RX_UNMUTE_MODE; 41862306a36Sopenharmony_ci break; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci case FM_MUTE_ATTENUATE: 42162306a36Sopenharmony_ci muteval = FM_RX_SOFT_MUTE_FORCE_MODE; 42262306a36Sopenharmony_ci break; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci if (fmdev->rx.rf_depend_mute == FM_RX_RF_DEPENDENT_MUTE_ON) 42562306a36Sopenharmony_ci muteval |= FM_RX_RF_DEP_MODE; 42662306a36Sopenharmony_ci else 42762306a36Sopenharmony_ci muteval &= ~FM_RX_RF_DEP_MODE; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci payload = muteval; 43062306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, MUTE_STATUS_SET, REG_WR, &payload, 43162306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 43262306a36Sopenharmony_ci if (ret < 0) 43362306a36Sopenharmony_ci return ret; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci return 0; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci/* Configures mute mode (Mute Off/On/Attenuate) */ 43962306a36Sopenharmony_ciint fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci u8 org_state; 44262306a36Sopenharmony_ci int ret; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (fmdev->rx.mute_mode == mute_mode_toset) 44562306a36Sopenharmony_ci return 0; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci org_state = fmdev->rx.mute_mode; 44862306a36Sopenharmony_ci fmdev->rx.mute_mode = mute_mode_toset; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci ret = fm_config_rx_mute_reg(fmdev); 45162306a36Sopenharmony_ci if (ret < 0) { 45262306a36Sopenharmony_ci fmdev->rx.mute_mode = org_state; 45362306a36Sopenharmony_ci return ret; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci return 0; 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci/* Gets RF dependent soft mute mode enable/disable status */ 46062306a36Sopenharmony_ciint fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci if (fmdev->curr_fmmode != FM_MODE_RX) 46362306a36Sopenharmony_ci return -EPERM; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if (curr_mute_mode == NULL) { 46662306a36Sopenharmony_ci fmerr("Invalid memory\n"); 46762306a36Sopenharmony_ci return -ENOMEM; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci *curr_mute_mode = fmdev->rx.rf_depend_mute; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return 0; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci/* Sets RF dependent soft mute mode */ 47662306a36Sopenharmony_ciint fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci u8 org_state; 47962306a36Sopenharmony_ci int ret; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (fmdev->curr_fmmode != FM_MODE_RX) 48262306a36Sopenharmony_ci return -EPERM; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_ON && 48562306a36Sopenharmony_ci rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_OFF) { 48662306a36Sopenharmony_ci fmerr("Invalid RF dependent soft mute\n"); 48762306a36Sopenharmony_ci return -EINVAL; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci if (fmdev->rx.rf_depend_mute == rfdepend_mute) 49062306a36Sopenharmony_ci return 0; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci org_state = fmdev->rx.rf_depend_mute; 49362306a36Sopenharmony_ci fmdev->rx.rf_depend_mute = rfdepend_mute; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci ret = fm_config_rx_mute_reg(fmdev); 49662306a36Sopenharmony_ci if (ret < 0) { 49762306a36Sopenharmony_ci fmdev->rx.rf_depend_mute = org_state; 49862306a36Sopenharmony_ci return ret; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci return 0; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci/* Returns the signal strength level of current channel */ 50562306a36Sopenharmony_ciint fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci __be16 curr_rssi_lel; 50862306a36Sopenharmony_ci u32 resp_len; 50962306a36Sopenharmony_ci int ret; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (rssilvl == NULL) { 51262306a36Sopenharmony_ci fmerr("Invalid memory\n"); 51362306a36Sopenharmony_ci return -ENOMEM; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci /* Read current RSSI level */ 51662306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, RSSI_LVL_GET, REG_RD, NULL, 2, 51762306a36Sopenharmony_ci &curr_rssi_lel, &resp_len); 51862306a36Sopenharmony_ci if (ret < 0) 51962306a36Sopenharmony_ci return ret; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci *rssilvl = be16_to_cpu(curr_rssi_lel); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci return 0; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci/* 52762306a36Sopenharmony_ci * Sets the signal strength level that once reached 52862306a36Sopenharmony_ci * will stop the auto search process 52962306a36Sopenharmony_ci */ 53062306a36Sopenharmony_ciint fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci u16 payload; 53362306a36Sopenharmony_ci int ret; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN || 53662306a36Sopenharmony_ci rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) { 53762306a36Sopenharmony_ci fmerr("Invalid RSSI threshold level\n"); 53862306a36Sopenharmony_ci return -EINVAL; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci payload = (u16)rssi_lvl_toset; 54162306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, SEARCH_LVL_SET, REG_WR, &payload, 54262306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 54362306a36Sopenharmony_ci if (ret < 0) 54462306a36Sopenharmony_ci return ret; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci fmdev->rx.rssi_threshold = rssi_lvl_toset; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci return 0; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci/* Returns current RX RSSI threshold value */ 55262306a36Sopenharmony_ciint fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci if (fmdev->curr_fmmode != FM_MODE_RX) 55562306a36Sopenharmony_ci return -EPERM; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (curr_rssi_lvl == NULL) { 55862306a36Sopenharmony_ci fmerr("Invalid memory\n"); 55962306a36Sopenharmony_ci return -ENOMEM; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci *curr_rssi_lvl = fmdev->rx.rssi_threshold; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci return 0; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci/* Sets RX stereo/mono modes */ 56862306a36Sopenharmony_ciint fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci u16 payload; 57162306a36Sopenharmony_ci int ret; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) { 57462306a36Sopenharmony_ci fmerr("Invalid mode\n"); 57562306a36Sopenharmony_ci return -EINVAL; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci /* Set stereo/mono mode */ 57962306a36Sopenharmony_ci payload = (u16)mode; 58062306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_WR, &payload, 58162306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 58262306a36Sopenharmony_ci if (ret < 0) 58362306a36Sopenharmony_ci return ret; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci /* Set stereo blending mode */ 58662306a36Sopenharmony_ci payload = FM_STEREO_SOFT_BLEND; 58762306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, MOST_BLEND_SET, REG_WR, &payload, 58862306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 58962306a36Sopenharmony_ci if (ret < 0) 59062306a36Sopenharmony_ci return ret; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci return 0; 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci/* Gets current RX stereo/mono mode */ 59662306a36Sopenharmony_ciint fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci __be16 curr_mode; 59962306a36Sopenharmony_ci u32 resp_len; 60062306a36Sopenharmony_ci int ret; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (mode == NULL) { 60362306a36Sopenharmony_ci fmerr("Invalid memory\n"); 60462306a36Sopenharmony_ci return -ENOMEM; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_RD, NULL, 2, 60862306a36Sopenharmony_ci &curr_mode, &resp_len); 60962306a36Sopenharmony_ci if (ret < 0) 61062306a36Sopenharmony_ci return ret; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci *mode = be16_to_cpu(curr_mode); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci return 0; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci/* Choose RX de-emphasis filter mode (50us/75us) */ 61862306a36Sopenharmony_ciint fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci u16 payload; 62162306a36Sopenharmony_ci int ret; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (fmdev->curr_fmmode != FM_MODE_RX) 62462306a36Sopenharmony_ci return -EPERM; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci if (mode != FM_RX_EMPHASIS_FILTER_50_USEC && 62762306a36Sopenharmony_ci mode != FM_RX_EMPHASIS_FILTER_75_USEC) { 62862306a36Sopenharmony_ci fmerr("Invalid rx de-emphasis mode (%d)\n", mode); 62962306a36Sopenharmony_ci return -EINVAL; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci payload = mode; 63362306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, DEMPH_MODE_SET, REG_WR, &payload, 63462306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 63562306a36Sopenharmony_ci if (ret < 0) 63662306a36Sopenharmony_ci return ret; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci fmdev->rx.deemphasis_mode = mode; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci return 0; 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci/* Gets current RX de-emphasis filter mode */ 64462306a36Sopenharmony_ciint fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci if (fmdev->curr_fmmode != FM_MODE_RX) 64762306a36Sopenharmony_ci return -EPERM; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci if (curr_deemphasis_mode == NULL) { 65062306a36Sopenharmony_ci fmerr("Invalid memory\n"); 65162306a36Sopenharmony_ci return -ENOMEM; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci *curr_deemphasis_mode = fmdev->rx.deemphasis_mode; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci return 0; 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci/* Enable/Disable RX RDS */ 66062306a36Sopenharmony_ciint fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci u16 payload; 66362306a36Sopenharmony_ci int ret; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci if (rds_en_dis != FM_RDS_ENABLE && rds_en_dis != FM_RDS_DISABLE) { 66662306a36Sopenharmony_ci fmerr("Invalid rds option\n"); 66762306a36Sopenharmony_ci return -EINVAL; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (rds_en_dis == FM_RDS_ENABLE 67162306a36Sopenharmony_ci && fmdev->rx.rds.flag == FM_RDS_DISABLE) { 67262306a36Sopenharmony_ci /* Turn on RX RDS and RDS circuit */ 67362306a36Sopenharmony_ci payload = FM_RX_PWR_SET_FM_AND_RDS_BLK_ON; 67462306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload, 67562306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 67662306a36Sopenharmony_ci if (ret < 0) 67762306a36Sopenharmony_ci return ret; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* Clear and reset RDS FIFO */ 68062306a36Sopenharmony_ci payload = FM_RX_RDS_FLUSH_FIFO; 68162306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, RDS_CNTRL_SET, REG_WR, &payload, 68262306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 68362306a36Sopenharmony_ci if (ret < 0) 68462306a36Sopenharmony_ci return ret; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* Read flags - just to clear any pending interrupts. */ 68762306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, 68862306a36Sopenharmony_ci NULL, NULL); 68962306a36Sopenharmony_ci if (ret < 0) 69062306a36Sopenharmony_ci return ret; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* Set RDS FIFO threshold value */ 69362306a36Sopenharmony_ci payload = FM_RX_RDS_FIFO_THRESHOLD; 69462306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, RDS_MEM_SET, REG_WR, &payload, 69562306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 69662306a36Sopenharmony_ci if (ret < 0) 69762306a36Sopenharmony_ci return ret; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci /* Enable RDS interrupt */ 70062306a36Sopenharmony_ci fmdev->irq_info.mask |= FM_RDS_EVENT; 70162306a36Sopenharmony_ci payload = fmdev->irq_info.mask; 70262306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, 70362306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 70462306a36Sopenharmony_ci if (ret < 0) { 70562306a36Sopenharmony_ci fmdev->irq_info.mask &= ~FM_RDS_EVENT; 70662306a36Sopenharmony_ci return ret; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci /* Update our local flag */ 71062306a36Sopenharmony_ci fmdev->rx.rds.flag = FM_RDS_ENABLE; 71162306a36Sopenharmony_ci } else if (rds_en_dis == FM_RDS_DISABLE 71262306a36Sopenharmony_ci && fmdev->rx.rds.flag == FM_RDS_ENABLE) { 71362306a36Sopenharmony_ci /* Turn off RX RDS */ 71462306a36Sopenharmony_ci payload = FM_RX_PWR_SET_FM_ON_RDS_OFF; 71562306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload, 71662306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 71762306a36Sopenharmony_ci if (ret < 0) 71862306a36Sopenharmony_ci return ret; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci /* Reset RDS pointers */ 72162306a36Sopenharmony_ci fmdev->rx.rds.last_blk_idx = 0; 72262306a36Sopenharmony_ci fmdev->rx.rds.wr_idx = 0; 72362306a36Sopenharmony_ci fmdev->rx.rds.rd_idx = 0; 72462306a36Sopenharmony_ci fm_rx_reset_station_info(fmdev); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* Update RDS local cache */ 72762306a36Sopenharmony_ci fmdev->irq_info.mask &= ~(FM_RDS_EVENT); 72862306a36Sopenharmony_ci fmdev->rx.rds.flag = FM_RDS_DISABLE; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci return 0; 73262306a36Sopenharmony_ci} 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci/* Returns current RX RDS enable/disable status */ 73562306a36Sopenharmony_ciint fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci if (fmdev->curr_fmmode != FM_MODE_RX) 73862306a36Sopenharmony_ci return -EPERM; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (curr_rds_en_dis == NULL) { 74162306a36Sopenharmony_ci fmerr("Invalid memory\n"); 74262306a36Sopenharmony_ci return -ENOMEM; 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci *curr_rds_en_dis = fmdev->rx.rds.flag; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci return 0; 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci/* Sets RDS operation mode (RDS/RDBS) */ 75162306a36Sopenharmony_ciint fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci u16 payload; 75462306a36Sopenharmony_ci int ret; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if (fmdev->curr_fmmode != FM_MODE_RX) 75762306a36Sopenharmony_ci return -EPERM; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (rds_mode != FM_RDS_SYSTEM_RDS && rds_mode != FM_RDS_SYSTEM_RBDS) { 76062306a36Sopenharmony_ci fmerr("Invalid rds mode\n"); 76162306a36Sopenharmony_ci return -EINVAL; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci /* Set RDS operation mode */ 76462306a36Sopenharmony_ci payload = (u16)rds_mode; 76562306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, RDS_SYSTEM_SET, REG_WR, &payload, 76662306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 76762306a36Sopenharmony_ci if (ret < 0) 76862306a36Sopenharmony_ci return ret; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci fmdev->rx.rds_mode = rds_mode; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci return 0; 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci/* Configures Alternate Frequency switch mode */ 77662306a36Sopenharmony_ciint fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci u16 payload; 77962306a36Sopenharmony_ci int ret; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci if (fmdev->curr_fmmode != FM_MODE_RX) 78262306a36Sopenharmony_ci return -EPERM; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (af_mode != FM_RX_RDS_AF_SWITCH_MODE_ON && 78562306a36Sopenharmony_ci af_mode != FM_RX_RDS_AF_SWITCH_MODE_OFF) { 78662306a36Sopenharmony_ci fmerr("Invalid af mode\n"); 78762306a36Sopenharmony_ci return -EINVAL; 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci /* Enable/disable low RSSI interrupt based on af_mode */ 79062306a36Sopenharmony_ci if (af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) 79162306a36Sopenharmony_ci fmdev->irq_info.mask |= FM_LEV_EVENT; 79262306a36Sopenharmony_ci else 79362306a36Sopenharmony_ci fmdev->irq_info.mask &= ~FM_LEV_EVENT; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci payload = fmdev->irq_info.mask; 79662306a36Sopenharmony_ci ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, 79762306a36Sopenharmony_ci sizeof(payload), NULL, NULL); 79862306a36Sopenharmony_ci if (ret < 0) 79962306a36Sopenharmony_ci return ret; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci fmdev->rx.af_mode = af_mode; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci return 0; 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci/* Returns Alternate Frequency switch status */ 80762306a36Sopenharmony_ciint fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci if (fmdev->curr_fmmode != FM_MODE_RX) 81062306a36Sopenharmony_ci return -EPERM; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci if (af_mode == NULL) { 81362306a36Sopenharmony_ci fmerr("Invalid memory\n"); 81462306a36Sopenharmony_ci return -ENOMEM; 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci *af_mode = fmdev->rx.af_mode; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci return 0; 82062306a36Sopenharmony_ci} 821