1*59da522aSManjunatha Halli /* 2*59da522aSManjunatha Halli * FM Driver for Connectivity chip of Texas Instruments. 3*59da522aSManjunatha Halli * This sub-module of FM driver implements FM RX functionality. 4*59da522aSManjunatha Halli * 5*59da522aSManjunatha Halli * Copyright (C) 2011 Texas Instruments 6*59da522aSManjunatha Halli * Author: Raja Mani <raja_mani@ti.com> 7*59da522aSManjunatha Halli * Author: Manjunatha Halli <manjunatha_halli@ti.com> 8*59da522aSManjunatha Halli * 9*59da522aSManjunatha Halli * This program is free software; you can redistribute it and/or modify 10*59da522aSManjunatha Halli * it under the terms of the GNU General Public License version 2 as 11*59da522aSManjunatha Halli * published by the Free Software Foundation. 12*59da522aSManjunatha Halli * 13*59da522aSManjunatha Halli * This program is distributed in the hope that it will be useful, 14*59da522aSManjunatha Halli * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*59da522aSManjunatha Halli * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*59da522aSManjunatha Halli * GNU General Public License for more details. 17*59da522aSManjunatha Halli * 18*59da522aSManjunatha Halli * You should have received a copy of the GNU General Public License 19*59da522aSManjunatha Halli * along with this program; if not, write to the Free Software 20*59da522aSManjunatha Halli * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21*59da522aSManjunatha Halli * 22*59da522aSManjunatha Halli */ 23*59da522aSManjunatha Halli 24*59da522aSManjunatha Halli #include "fmdrv.h" 25*59da522aSManjunatha Halli #include "fmdrv_common.h" 26*59da522aSManjunatha Halli #include "fmdrv_rx.h" 27*59da522aSManjunatha Halli 28*59da522aSManjunatha Halli void fm_rx_reset_rds_cache(struct fmdev *fmdev) 29*59da522aSManjunatha Halli { 30*59da522aSManjunatha Halli fmdev->rx.rds.flag = FM_RDS_DISABLE; 31*59da522aSManjunatha Halli fmdev->rx.rds.last_blk_idx = 0; 32*59da522aSManjunatha Halli fmdev->rx.rds.wr_idx = 0; 33*59da522aSManjunatha Halli fmdev->rx.rds.rd_idx = 0; 34*59da522aSManjunatha Halli 35*59da522aSManjunatha Halli if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) 36*59da522aSManjunatha Halli fmdev->irq_info.mask |= FM_LEV_EVENT; 37*59da522aSManjunatha Halli } 38*59da522aSManjunatha Halli 39*59da522aSManjunatha Halli void fm_rx_reset_station_info(struct fmdev *fmdev) 40*59da522aSManjunatha Halli { 41*59da522aSManjunatha Halli fmdev->rx.stat_info.picode = FM_NO_PI_CODE; 42*59da522aSManjunatha Halli fmdev->rx.stat_info.afcache_size = 0; 43*59da522aSManjunatha Halli fmdev->rx.stat_info.af_list_max = 0; 44*59da522aSManjunatha Halli } 45*59da522aSManjunatha Halli 46*59da522aSManjunatha Halli u32 fm_rx_set_freq(struct fmdev *fmdev, u32 freq) 47*59da522aSManjunatha Halli { 48*59da522aSManjunatha Halli unsigned long timeleft; 49*59da522aSManjunatha Halli u16 payload, curr_frq, intr_flag; 50*59da522aSManjunatha Halli u32 curr_frq_in_khz; 51*59da522aSManjunatha Halli u32 ret, resp_len; 52*59da522aSManjunatha Halli 53*59da522aSManjunatha Halli if (freq < fmdev->rx.region.bot_freq || freq > fmdev->rx.region.top_freq) { 54*59da522aSManjunatha Halli fmerr("Invalid frequency %d\n", freq); 55*59da522aSManjunatha Halli return -EINVAL; 56*59da522aSManjunatha Halli } 57*59da522aSManjunatha Halli 58*59da522aSManjunatha Halli /* Set audio enable */ 59*59da522aSManjunatha Halli payload = FM_RX_AUDIO_ENABLE_I2S_AND_ANALOG; 60*59da522aSManjunatha Halli 61*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, AUDIO_ENABLE_SET, REG_WR, &payload, 62*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 63*59da522aSManjunatha Halli if (ret < 0) 64*59da522aSManjunatha Halli return ret; 65*59da522aSManjunatha Halli 66*59da522aSManjunatha Halli /* Set hilo to automatic selection */ 67*59da522aSManjunatha Halli payload = FM_RX_IFFREQ_HILO_AUTOMATIC; 68*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, HILO_SET, REG_WR, &payload, 69*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 70*59da522aSManjunatha Halli if (ret < 0) 71*59da522aSManjunatha Halli return ret; 72*59da522aSManjunatha Halli 73*59da522aSManjunatha Halli /* Calculate frequency index and set*/ 74*59da522aSManjunatha Halli payload = (freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL; 75*59da522aSManjunatha Halli 76*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload, 77*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 78*59da522aSManjunatha Halli if (ret < 0) 79*59da522aSManjunatha Halli return ret; 80*59da522aSManjunatha Halli 81*59da522aSManjunatha Halli /* Read flags - just to clear any pending interrupts if we had */ 82*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL); 83*59da522aSManjunatha Halli if (ret < 0) 84*59da522aSManjunatha Halli return ret; 85*59da522aSManjunatha Halli 86*59da522aSManjunatha Halli /* Enable FR, BL interrupts */ 87*59da522aSManjunatha Halli intr_flag = fmdev->irq_info.mask; 88*59da522aSManjunatha Halli fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT); 89*59da522aSManjunatha Halli payload = fmdev->irq_info.mask; 90*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, 91*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 92*59da522aSManjunatha Halli if (ret < 0) 93*59da522aSManjunatha Halli return ret; 94*59da522aSManjunatha Halli 95*59da522aSManjunatha Halli /* Start tune */ 96*59da522aSManjunatha Halli payload = FM_TUNER_PRESET_MODE; 97*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload, 98*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 99*59da522aSManjunatha Halli if (ret < 0) 100*59da522aSManjunatha Halli goto exit; 101*59da522aSManjunatha Halli 102*59da522aSManjunatha Halli /* Wait for tune ended interrupt */ 103*59da522aSManjunatha Halli init_completion(&fmdev->maintask_comp); 104*59da522aSManjunatha Halli timeleft = wait_for_completion_timeout(&fmdev->maintask_comp, 105*59da522aSManjunatha Halli FM_DRV_TX_TIMEOUT); 106*59da522aSManjunatha Halli if (!timeleft) { 107*59da522aSManjunatha Halli fmerr("Timeout(%d sec),didn't get tune ended int\n", 108*59da522aSManjunatha Halli jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); 109*59da522aSManjunatha Halli ret = -ETIMEDOUT; 110*59da522aSManjunatha Halli goto exit; 111*59da522aSManjunatha Halli } 112*59da522aSManjunatha Halli 113*59da522aSManjunatha Halli /* Read freq back to confirm */ 114*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2, &curr_frq, &resp_len); 115*59da522aSManjunatha Halli if (ret < 0) 116*59da522aSManjunatha Halli goto exit; 117*59da522aSManjunatha Halli 118*59da522aSManjunatha Halli curr_frq = be16_to_cpu(curr_frq); 119*59da522aSManjunatha Halli curr_frq_in_khz = (fmdev->rx.region.bot_freq + ((u32)curr_frq * FM_FREQ_MUL)); 120*59da522aSManjunatha Halli 121*59da522aSManjunatha Halli if (curr_frq_in_khz != freq) { 122*59da522aSManjunatha Halli pr_info("Frequency is set to (%d) but " 123*59da522aSManjunatha Halli "requested freq is (%d)\n", curr_frq_in_khz, freq); 124*59da522aSManjunatha Halli } 125*59da522aSManjunatha Halli 126*59da522aSManjunatha Halli /* Update local cache */ 127*59da522aSManjunatha Halli fmdev->rx.freq = curr_frq_in_khz; 128*59da522aSManjunatha Halli exit: 129*59da522aSManjunatha Halli /* Re-enable default FM interrupts */ 130*59da522aSManjunatha Halli fmdev->irq_info.mask = intr_flag; 131*59da522aSManjunatha Halli payload = fmdev->irq_info.mask; 132*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, 133*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 134*59da522aSManjunatha Halli if (ret < 0) 135*59da522aSManjunatha Halli return ret; 136*59da522aSManjunatha Halli 137*59da522aSManjunatha Halli /* Reset RDS cache and current station pointers */ 138*59da522aSManjunatha Halli fm_rx_reset_rds_cache(fmdev); 139*59da522aSManjunatha Halli fm_rx_reset_station_info(fmdev); 140*59da522aSManjunatha Halli 141*59da522aSManjunatha Halli return ret; 142*59da522aSManjunatha Halli } 143*59da522aSManjunatha Halli 144*59da522aSManjunatha Halli static u32 fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing) 145*59da522aSManjunatha Halli { 146*59da522aSManjunatha Halli u16 payload; 147*59da522aSManjunatha Halli u32 ret; 148*59da522aSManjunatha Halli 149*59da522aSManjunatha Halli if (spacing > 0 && spacing <= 50000) 150*59da522aSManjunatha Halli spacing = FM_CHANNEL_SPACING_50KHZ; 151*59da522aSManjunatha Halli else if (spacing > 50000 && spacing <= 100000) 152*59da522aSManjunatha Halli spacing = FM_CHANNEL_SPACING_100KHZ; 153*59da522aSManjunatha Halli else 154*59da522aSManjunatha Halli spacing = FM_CHANNEL_SPACING_200KHZ; 155*59da522aSManjunatha Halli 156*59da522aSManjunatha Halli /* set channel spacing */ 157*59da522aSManjunatha Halli payload = spacing; 158*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, CHANL_BW_SET, REG_WR, &payload, 159*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 160*59da522aSManjunatha Halli if (ret < 0) 161*59da522aSManjunatha Halli return ret; 162*59da522aSManjunatha Halli 163*59da522aSManjunatha Halli fmdev->rx.region.chanl_space = spacing * FM_FREQ_MUL; 164*59da522aSManjunatha Halli 165*59da522aSManjunatha Halli return ret; 166*59da522aSManjunatha Halli } 167*59da522aSManjunatha Halli 168*59da522aSManjunatha Halli u32 fm_rx_seek(struct fmdev *fmdev, u32 seek_upward, 169*59da522aSManjunatha Halli u32 wrap_around, u32 spacing) 170*59da522aSManjunatha Halli { 171*59da522aSManjunatha Halli u32 resp_len; 172*59da522aSManjunatha Halli u16 curr_frq, next_frq, last_frq; 173*59da522aSManjunatha Halli u16 payload, int_reason, intr_flag; 174*59da522aSManjunatha Halli u16 offset, space_idx; 175*59da522aSManjunatha Halli unsigned long timeleft; 176*59da522aSManjunatha Halli u32 ret; 177*59da522aSManjunatha Halli 178*59da522aSManjunatha Halli /* Set channel spacing */ 179*59da522aSManjunatha Halli ret = fm_rx_set_channel_spacing(fmdev, spacing); 180*59da522aSManjunatha Halli if (ret < 0) { 181*59da522aSManjunatha Halli fmerr("Failed to set channel spacing\n"); 182*59da522aSManjunatha Halli return ret; 183*59da522aSManjunatha Halli } 184*59da522aSManjunatha Halli 185*59da522aSManjunatha Halli /* Read the current frequency from chip */ 186*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 187*59da522aSManjunatha Halli sizeof(curr_frq), &curr_frq, &resp_len); 188*59da522aSManjunatha Halli if (ret < 0) 189*59da522aSManjunatha Halli return ret; 190*59da522aSManjunatha Halli 191*59da522aSManjunatha Halli curr_frq = be16_to_cpu(curr_frq); 192*59da522aSManjunatha Halli last_frq = (fmdev->rx.region.top_freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL; 193*59da522aSManjunatha Halli 194*59da522aSManjunatha Halli /* Check the offset in order to be aligned to the channel spacing*/ 195*59da522aSManjunatha Halli space_idx = fmdev->rx.region.chanl_space / FM_FREQ_MUL; 196*59da522aSManjunatha Halli offset = curr_frq % space_idx; 197*59da522aSManjunatha Halli 198*59da522aSManjunatha Halli next_frq = seek_upward ? curr_frq + space_idx /* Seek Up */ : 199*59da522aSManjunatha Halli curr_frq - space_idx /* Seek Down */ ; 200*59da522aSManjunatha Halli 201*59da522aSManjunatha Halli /* 202*59da522aSManjunatha Halli * Add or subtract offset in order to stay aligned to the channel 203*59da522aSManjunatha Halli * spacing. 204*59da522aSManjunatha Halli */ 205*59da522aSManjunatha Halli if ((short)next_frq < 0) 206*59da522aSManjunatha Halli next_frq = last_frq - offset; 207*59da522aSManjunatha Halli else if (next_frq > last_frq) 208*59da522aSManjunatha Halli next_frq = 0 + offset; 209*59da522aSManjunatha Halli 210*59da522aSManjunatha Halli again: 211*59da522aSManjunatha Halli /* Set calculated next frequency to perform seek */ 212*59da522aSManjunatha Halli payload = next_frq; 213*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload, 214*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 215*59da522aSManjunatha Halli if (ret < 0) 216*59da522aSManjunatha Halli return ret; 217*59da522aSManjunatha Halli 218*59da522aSManjunatha Halli /* Set search direction (0:Seek Down, 1:Seek Up) */ 219*59da522aSManjunatha Halli payload = (seek_upward ? FM_SEARCH_DIRECTION_UP : FM_SEARCH_DIRECTION_DOWN); 220*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, SEARCH_DIR_SET, REG_WR, &payload, 221*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 222*59da522aSManjunatha Halli if (ret < 0) 223*59da522aSManjunatha Halli return ret; 224*59da522aSManjunatha Halli 225*59da522aSManjunatha Halli /* Read flags - just to clear any pending interrupts if we had */ 226*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL); 227*59da522aSManjunatha Halli if (ret < 0) 228*59da522aSManjunatha Halli return ret; 229*59da522aSManjunatha Halli 230*59da522aSManjunatha Halli /* Enable FR, BL interrupts */ 231*59da522aSManjunatha Halli intr_flag = fmdev->irq_info.mask; 232*59da522aSManjunatha Halli fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT); 233*59da522aSManjunatha Halli payload = fmdev->irq_info.mask; 234*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, 235*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 236*59da522aSManjunatha Halli if (ret < 0) 237*59da522aSManjunatha Halli return ret; 238*59da522aSManjunatha Halli 239*59da522aSManjunatha Halli /* Start seek */ 240*59da522aSManjunatha Halli payload = FM_TUNER_AUTONOMOUS_SEARCH_MODE; 241*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload, 242*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 243*59da522aSManjunatha Halli if (ret < 0) 244*59da522aSManjunatha Halli return ret; 245*59da522aSManjunatha Halli 246*59da522aSManjunatha Halli /* Wait for tune ended/band limit reached interrupt */ 247*59da522aSManjunatha Halli init_completion(&fmdev->maintask_comp); 248*59da522aSManjunatha Halli timeleft = wait_for_completion_timeout(&fmdev->maintask_comp, 249*59da522aSManjunatha Halli FM_DRV_RX_SEEK_TIMEOUT); 250*59da522aSManjunatha Halli if (!timeleft) { 251*59da522aSManjunatha Halli fmerr("Timeout(%d sec),didn't get tune ended int\n", 252*59da522aSManjunatha Halli jiffies_to_msecs(FM_DRV_RX_SEEK_TIMEOUT) / 1000); 253*59da522aSManjunatha Halli return -ETIMEDOUT; 254*59da522aSManjunatha Halli } 255*59da522aSManjunatha Halli 256*59da522aSManjunatha Halli int_reason = fmdev->irq_info.flag & (FM_TUNE_COMPLETE | FM_BAND_LIMIT); 257*59da522aSManjunatha Halli 258*59da522aSManjunatha Halli /* Re-enable default FM interrupts */ 259*59da522aSManjunatha Halli fmdev->irq_info.mask = intr_flag; 260*59da522aSManjunatha Halli payload = fmdev->irq_info.mask; 261*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, 262*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 263*59da522aSManjunatha Halli if (ret < 0) 264*59da522aSManjunatha Halli return ret; 265*59da522aSManjunatha Halli 266*59da522aSManjunatha Halli if (int_reason & FM_BL_EVENT) { 267*59da522aSManjunatha Halli if (wrap_around == 0) { 268*59da522aSManjunatha Halli fmdev->rx.freq = seek_upward ? 269*59da522aSManjunatha Halli fmdev->rx.region.top_freq : 270*59da522aSManjunatha Halli fmdev->rx.region.bot_freq; 271*59da522aSManjunatha Halli } else { 272*59da522aSManjunatha Halli fmdev->rx.freq = seek_upward ? 273*59da522aSManjunatha Halli fmdev->rx.region.bot_freq : 274*59da522aSManjunatha Halli fmdev->rx.region.top_freq; 275*59da522aSManjunatha Halli /* Calculate frequency index to write */ 276*59da522aSManjunatha Halli next_frq = (fmdev->rx.freq - 277*59da522aSManjunatha Halli fmdev->rx.region.bot_freq) / FM_FREQ_MUL; 278*59da522aSManjunatha Halli goto again; 279*59da522aSManjunatha Halli } 280*59da522aSManjunatha Halli } else { 281*59da522aSManjunatha Halli /* Read freq to know where operation tune operation stopped */ 282*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2, 283*59da522aSManjunatha Halli &curr_frq, &resp_len); 284*59da522aSManjunatha Halli if (ret < 0) 285*59da522aSManjunatha Halli return ret; 286*59da522aSManjunatha Halli 287*59da522aSManjunatha Halli curr_frq = be16_to_cpu(curr_frq); 288*59da522aSManjunatha Halli fmdev->rx.freq = (fmdev->rx.region.bot_freq + 289*59da522aSManjunatha Halli ((u32)curr_frq * FM_FREQ_MUL)); 290*59da522aSManjunatha Halli 291*59da522aSManjunatha Halli } 292*59da522aSManjunatha Halli /* Reset RDS cache and current station pointers */ 293*59da522aSManjunatha Halli fm_rx_reset_rds_cache(fmdev); 294*59da522aSManjunatha Halli fm_rx_reset_station_info(fmdev); 295*59da522aSManjunatha Halli 296*59da522aSManjunatha Halli return ret; 297*59da522aSManjunatha Halli } 298*59da522aSManjunatha Halli 299*59da522aSManjunatha Halli u32 fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set) 300*59da522aSManjunatha Halli { 301*59da522aSManjunatha Halli u16 payload; 302*59da522aSManjunatha Halli u32 ret; 303*59da522aSManjunatha Halli 304*59da522aSManjunatha Halli if (fmdev->curr_fmmode != FM_MODE_RX) 305*59da522aSManjunatha Halli return -EPERM; 306*59da522aSManjunatha Halli 307*59da522aSManjunatha Halli if (vol_to_set < FM_RX_VOLUME_MIN || vol_to_set > FM_RX_VOLUME_MAX) { 308*59da522aSManjunatha Halli fmerr("Volume is not within(%d-%d) range\n", 309*59da522aSManjunatha Halli FM_RX_VOLUME_MIN, FM_RX_VOLUME_MAX); 310*59da522aSManjunatha Halli return -EINVAL; 311*59da522aSManjunatha Halli } 312*59da522aSManjunatha Halli vol_to_set *= FM_RX_VOLUME_GAIN_STEP; 313*59da522aSManjunatha Halli 314*59da522aSManjunatha Halli payload = vol_to_set; 315*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, VOLUME_SET, REG_WR, &payload, 316*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 317*59da522aSManjunatha Halli if (ret < 0) 318*59da522aSManjunatha Halli return ret; 319*59da522aSManjunatha Halli 320*59da522aSManjunatha Halli fmdev->rx.volume = vol_to_set; 321*59da522aSManjunatha Halli return ret; 322*59da522aSManjunatha Halli } 323*59da522aSManjunatha Halli 324*59da522aSManjunatha Halli /* Get volume */ 325*59da522aSManjunatha Halli u32 fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol) 326*59da522aSManjunatha Halli { 327*59da522aSManjunatha Halli if (fmdev->curr_fmmode != FM_MODE_RX) 328*59da522aSManjunatha Halli return -EPERM; 329*59da522aSManjunatha Halli 330*59da522aSManjunatha Halli if (curr_vol == NULL) { 331*59da522aSManjunatha Halli fmerr("Invalid memory\n"); 332*59da522aSManjunatha Halli return -ENOMEM; 333*59da522aSManjunatha Halli } 334*59da522aSManjunatha Halli 335*59da522aSManjunatha Halli *curr_vol = fmdev->rx.volume / FM_RX_VOLUME_GAIN_STEP; 336*59da522aSManjunatha Halli 337*59da522aSManjunatha Halli return 0; 338*59da522aSManjunatha Halli } 339*59da522aSManjunatha Halli 340*59da522aSManjunatha Halli /* To get current band's bottom and top frequency */ 341*59da522aSManjunatha Halli u32 fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq) 342*59da522aSManjunatha Halli { 343*59da522aSManjunatha Halli if (bot_freq != NULL) 344*59da522aSManjunatha Halli *bot_freq = fmdev->rx.region.bot_freq; 345*59da522aSManjunatha Halli 346*59da522aSManjunatha Halli if (top_freq != NULL) 347*59da522aSManjunatha Halli *top_freq = fmdev->rx.region.top_freq; 348*59da522aSManjunatha Halli 349*59da522aSManjunatha Halli return 0; 350*59da522aSManjunatha Halli } 351*59da522aSManjunatha Halli 352*59da522aSManjunatha Halli /* Returns current band index (0-Europe/US; 1-Japan) */ 353*59da522aSManjunatha Halli void fm_rx_get_region(struct fmdev *fmdev, u8 *region) 354*59da522aSManjunatha Halli { 355*59da522aSManjunatha Halli *region = fmdev->rx.region.fm_band; 356*59da522aSManjunatha Halli } 357*59da522aSManjunatha Halli 358*59da522aSManjunatha Halli /* Sets band (0-Europe/US; 1-Japan) */ 359*59da522aSManjunatha Halli u32 fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set) 360*59da522aSManjunatha Halli { 361*59da522aSManjunatha Halli u16 payload; 362*59da522aSManjunatha Halli u32 new_frq = 0; 363*59da522aSManjunatha Halli u32 ret; 364*59da522aSManjunatha Halli 365*59da522aSManjunatha Halli if (region_to_set != FM_BAND_EUROPE_US && 366*59da522aSManjunatha Halli region_to_set != FM_BAND_JAPAN) { 367*59da522aSManjunatha Halli fmerr("Invalid band\n"); 368*59da522aSManjunatha Halli return -EINVAL; 369*59da522aSManjunatha Halli } 370*59da522aSManjunatha Halli 371*59da522aSManjunatha Halli if (fmdev->rx.region.fm_band == region_to_set) { 372*59da522aSManjunatha Halli fmerr("Requested band is already configured\n"); 373*59da522aSManjunatha Halli return 0; 374*59da522aSManjunatha Halli } 375*59da522aSManjunatha Halli 376*59da522aSManjunatha Halli /* Send cmd to set the band */ 377*59da522aSManjunatha Halli payload = (u16)region_to_set; 378*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, BAND_SET, REG_WR, &payload, 379*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 380*59da522aSManjunatha Halli if (ret < 0) 381*59da522aSManjunatha Halli return ret; 382*59da522aSManjunatha Halli 383*59da522aSManjunatha Halli fmc_update_region_info(fmdev, region_to_set); 384*59da522aSManjunatha Halli 385*59da522aSManjunatha Halli /* Check whether current RX frequency is within band boundary */ 386*59da522aSManjunatha Halli if (fmdev->rx.freq < fmdev->rx.region.bot_freq) 387*59da522aSManjunatha Halli new_frq = fmdev->rx.region.bot_freq; 388*59da522aSManjunatha Halli else if (fmdev->rx.freq > fmdev->rx.region.top_freq) 389*59da522aSManjunatha Halli new_frq = fmdev->rx.region.top_freq; 390*59da522aSManjunatha Halli 391*59da522aSManjunatha Halli if (new_frq) { 392*59da522aSManjunatha Halli fmdbg("Current freq is not within band limit boundary," 393*59da522aSManjunatha Halli "switching to %d KHz\n", new_frq); 394*59da522aSManjunatha Halli /* Current RX frequency is not in range. So, update it */ 395*59da522aSManjunatha Halli ret = fm_rx_set_freq(fmdev, new_frq); 396*59da522aSManjunatha Halli } 397*59da522aSManjunatha Halli 398*59da522aSManjunatha Halli return ret; 399*59da522aSManjunatha Halli } 400*59da522aSManjunatha Halli 401*59da522aSManjunatha Halli /* Reads current mute mode (Mute Off/On/Attenuate)*/ 402*59da522aSManjunatha Halli u32 fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode) 403*59da522aSManjunatha Halli { 404*59da522aSManjunatha Halli if (fmdev->curr_fmmode != FM_MODE_RX) 405*59da522aSManjunatha Halli return -EPERM; 406*59da522aSManjunatha Halli 407*59da522aSManjunatha Halli if (curr_mute_mode == NULL) { 408*59da522aSManjunatha Halli fmerr("Invalid memory\n"); 409*59da522aSManjunatha Halli return -ENOMEM; 410*59da522aSManjunatha Halli } 411*59da522aSManjunatha Halli 412*59da522aSManjunatha Halli *curr_mute_mode = fmdev->rx.mute_mode; 413*59da522aSManjunatha Halli 414*59da522aSManjunatha Halli return 0; 415*59da522aSManjunatha Halli } 416*59da522aSManjunatha Halli 417*59da522aSManjunatha Halli static u32 fm_config_rx_mute_reg(struct fmdev *fmdev) 418*59da522aSManjunatha Halli { 419*59da522aSManjunatha Halli u16 payload, muteval; 420*59da522aSManjunatha Halli u32 ret; 421*59da522aSManjunatha Halli 422*59da522aSManjunatha Halli muteval = 0; 423*59da522aSManjunatha Halli switch (fmdev->rx.mute_mode) { 424*59da522aSManjunatha Halli case FM_MUTE_ON: 425*59da522aSManjunatha Halli muteval = FM_RX_AC_MUTE_MODE; 426*59da522aSManjunatha Halli break; 427*59da522aSManjunatha Halli 428*59da522aSManjunatha Halli case FM_MUTE_OFF: 429*59da522aSManjunatha Halli muteval = FM_RX_UNMUTE_MODE; 430*59da522aSManjunatha Halli break; 431*59da522aSManjunatha Halli 432*59da522aSManjunatha Halli case FM_MUTE_ATTENUATE: 433*59da522aSManjunatha Halli muteval = FM_RX_SOFT_MUTE_FORCE_MODE; 434*59da522aSManjunatha Halli break; 435*59da522aSManjunatha Halli } 436*59da522aSManjunatha Halli if (fmdev->rx.rf_depend_mute == FM_RX_RF_DEPENDENT_MUTE_ON) 437*59da522aSManjunatha Halli muteval |= FM_RX_RF_DEP_MODE; 438*59da522aSManjunatha Halli else 439*59da522aSManjunatha Halli muteval &= ~FM_RX_RF_DEP_MODE; 440*59da522aSManjunatha Halli 441*59da522aSManjunatha Halli payload = muteval; 442*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, MUTE_STATUS_SET, REG_WR, &payload, 443*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 444*59da522aSManjunatha Halli if (ret < 0) 445*59da522aSManjunatha Halli return ret; 446*59da522aSManjunatha Halli 447*59da522aSManjunatha Halli return 0; 448*59da522aSManjunatha Halli } 449*59da522aSManjunatha Halli 450*59da522aSManjunatha Halli /* Configures mute mode (Mute Off/On/Attenuate) */ 451*59da522aSManjunatha Halli u32 fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) 452*59da522aSManjunatha Halli { 453*59da522aSManjunatha Halli u8 org_state; 454*59da522aSManjunatha Halli u32 ret; 455*59da522aSManjunatha Halli 456*59da522aSManjunatha Halli if (fmdev->rx.mute_mode == mute_mode_toset) 457*59da522aSManjunatha Halli return 0; 458*59da522aSManjunatha Halli 459*59da522aSManjunatha Halli org_state = fmdev->rx.mute_mode; 460*59da522aSManjunatha Halli fmdev->rx.mute_mode = mute_mode_toset; 461*59da522aSManjunatha Halli 462*59da522aSManjunatha Halli ret = fm_config_rx_mute_reg(fmdev); 463*59da522aSManjunatha Halli if (ret < 0) { 464*59da522aSManjunatha Halli fmdev->rx.mute_mode = org_state; 465*59da522aSManjunatha Halli return ret; 466*59da522aSManjunatha Halli } 467*59da522aSManjunatha Halli 468*59da522aSManjunatha Halli return 0; 469*59da522aSManjunatha Halli } 470*59da522aSManjunatha Halli 471*59da522aSManjunatha Halli /* Gets RF dependent soft mute mode enable/disable status */ 472*59da522aSManjunatha Halli u32 fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode) 473*59da522aSManjunatha Halli { 474*59da522aSManjunatha Halli if (fmdev->curr_fmmode != FM_MODE_RX) 475*59da522aSManjunatha Halli return -EPERM; 476*59da522aSManjunatha Halli 477*59da522aSManjunatha Halli if (curr_mute_mode == NULL) { 478*59da522aSManjunatha Halli fmerr("Invalid memory\n"); 479*59da522aSManjunatha Halli return -ENOMEM; 480*59da522aSManjunatha Halli } 481*59da522aSManjunatha Halli 482*59da522aSManjunatha Halli *curr_mute_mode = fmdev->rx.rf_depend_mute; 483*59da522aSManjunatha Halli 484*59da522aSManjunatha Halli return 0; 485*59da522aSManjunatha Halli } 486*59da522aSManjunatha Halli 487*59da522aSManjunatha Halli /* Sets RF dependent soft mute mode */ 488*59da522aSManjunatha Halli u32 fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute) 489*59da522aSManjunatha Halli { 490*59da522aSManjunatha Halli u8 org_state; 491*59da522aSManjunatha Halli u32 ret; 492*59da522aSManjunatha Halli 493*59da522aSManjunatha Halli if (fmdev->curr_fmmode != FM_MODE_RX) 494*59da522aSManjunatha Halli return -EPERM; 495*59da522aSManjunatha Halli 496*59da522aSManjunatha Halli if (rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_ON && 497*59da522aSManjunatha Halli rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_OFF) { 498*59da522aSManjunatha Halli fmerr("Invalid RF dependent soft mute\n"); 499*59da522aSManjunatha Halli return -EINVAL; 500*59da522aSManjunatha Halli } 501*59da522aSManjunatha Halli if (fmdev->rx.rf_depend_mute == rfdepend_mute) 502*59da522aSManjunatha Halli return 0; 503*59da522aSManjunatha Halli 504*59da522aSManjunatha Halli org_state = fmdev->rx.rf_depend_mute; 505*59da522aSManjunatha Halli fmdev->rx.rf_depend_mute = rfdepend_mute; 506*59da522aSManjunatha Halli 507*59da522aSManjunatha Halli ret = fm_config_rx_mute_reg(fmdev); 508*59da522aSManjunatha Halli if (ret < 0) { 509*59da522aSManjunatha Halli fmdev->rx.rf_depend_mute = org_state; 510*59da522aSManjunatha Halli return ret; 511*59da522aSManjunatha Halli } 512*59da522aSManjunatha Halli 513*59da522aSManjunatha Halli return 0; 514*59da522aSManjunatha Halli } 515*59da522aSManjunatha Halli 516*59da522aSManjunatha Halli /* Returns the signal strength level of current channel */ 517*59da522aSManjunatha Halli u32 fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl) 518*59da522aSManjunatha Halli { 519*59da522aSManjunatha Halli u16 curr_rssi_lel; 520*59da522aSManjunatha Halli u32 resp_len; 521*59da522aSManjunatha Halli u32 ret; 522*59da522aSManjunatha Halli 523*59da522aSManjunatha Halli if (rssilvl == NULL) { 524*59da522aSManjunatha Halli fmerr("Invalid memory\n"); 525*59da522aSManjunatha Halli return -ENOMEM; 526*59da522aSManjunatha Halli } 527*59da522aSManjunatha Halli /* Read current RSSI level */ 528*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, RSSI_LVL_GET, REG_RD, NULL, 2, 529*59da522aSManjunatha Halli &curr_rssi_lel, &resp_len); 530*59da522aSManjunatha Halli if (ret < 0) 531*59da522aSManjunatha Halli return ret; 532*59da522aSManjunatha Halli 533*59da522aSManjunatha Halli *rssilvl = be16_to_cpu(curr_rssi_lel); 534*59da522aSManjunatha Halli 535*59da522aSManjunatha Halli return 0; 536*59da522aSManjunatha Halli } 537*59da522aSManjunatha Halli 538*59da522aSManjunatha Halli /* 539*59da522aSManjunatha Halli * Sets the signal strength level that once reached 540*59da522aSManjunatha Halli * will stop the auto search process 541*59da522aSManjunatha Halli */ 542*59da522aSManjunatha Halli u32 fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset) 543*59da522aSManjunatha Halli { 544*59da522aSManjunatha Halli u16 payload; 545*59da522aSManjunatha Halli u32 ret; 546*59da522aSManjunatha Halli 547*59da522aSManjunatha Halli if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN || 548*59da522aSManjunatha Halli rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) { 549*59da522aSManjunatha Halli fmerr("Invalid RSSI threshold level\n"); 550*59da522aSManjunatha Halli return -EINVAL; 551*59da522aSManjunatha Halli } 552*59da522aSManjunatha Halli payload = (u16)rssi_lvl_toset; 553*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, SEARCH_LVL_SET, REG_WR, &payload, 554*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 555*59da522aSManjunatha Halli if (ret < 0) 556*59da522aSManjunatha Halli return ret; 557*59da522aSManjunatha Halli 558*59da522aSManjunatha Halli fmdev->rx.rssi_threshold = rssi_lvl_toset; 559*59da522aSManjunatha Halli 560*59da522aSManjunatha Halli return 0; 561*59da522aSManjunatha Halli } 562*59da522aSManjunatha Halli 563*59da522aSManjunatha Halli /* Returns current RX RSSI threshold value */ 564*59da522aSManjunatha Halli u32 fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl) 565*59da522aSManjunatha Halli { 566*59da522aSManjunatha Halli if (fmdev->curr_fmmode != FM_MODE_RX) 567*59da522aSManjunatha Halli return -EPERM; 568*59da522aSManjunatha Halli 569*59da522aSManjunatha Halli if (curr_rssi_lvl == NULL) { 570*59da522aSManjunatha Halli fmerr("Invalid memory\n"); 571*59da522aSManjunatha Halli return -ENOMEM; 572*59da522aSManjunatha Halli } 573*59da522aSManjunatha Halli 574*59da522aSManjunatha Halli *curr_rssi_lvl = fmdev->rx.rssi_threshold; 575*59da522aSManjunatha Halli 576*59da522aSManjunatha Halli return 0; 577*59da522aSManjunatha Halli } 578*59da522aSManjunatha Halli 579*59da522aSManjunatha Halli /* Sets RX stereo/mono modes */ 580*59da522aSManjunatha Halli u32 fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode) 581*59da522aSManjunatha Halli { 582*59da522aSManjunatha Halli u16 payload; 583*59da522aSManjunatha Halli u32 ret; 584*59da522aSManjunatha Halli 585*59da522aSManjunatha Halli if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) { 586*59da522aSManjunatha Halli fmerr("Invalid mode\n"); 587*59da522aSManjunatha Halli return -EINVAL; 588*59da522aSManjunatha Halli } 589*59da522aSManjunatha Halli 590*59da522aSManjunatha Halli /* Set stereo/mono mode */ 591*59da522aSManjunatha Halli payload = (u16)mode; 592*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_WR, &payload, 593*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 594*59da522aSManjunatha Halli if (ret < 0) 595*59da522aSManjunatha Halli return ret; 596*59da522aSManjunatha Halli 597*59da522aSManjunatha Halli /* Set stereo blending mode */ 598*59da522aSManjunatha Halli payload = FM_STEREO_SOFT_BLEND; 599*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, MOST_BLEND_SET, REG_WR, &payload, 600*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 601*59da522aSManjunatha Halli if (ret < 0) 602*59da522aSManjunatha Halli return ret; 603*59da522aSManjunatha Halli 604*59da522aSManjunatha Halli return 0; 605*59da522aSManjunatha Halli } 606*59da522aSManjunatha Halli 607*59da522aSManjunatha Halli /* Gets current RX stereo/mono mode */ 608*59da522aSManjunatha Halli u32 fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode) 609*59da522aSManjunatha Halli { 610*59da522aSManjunatha Halli u16 curr_mode; 611*59da522aSManjunatha Halli u32 ret, resp_len; 612*59da522aSManjunatha Halli 613*59da522aSManjunatha Halli if (mode == NULL) { 614*59da522aSManjunatha Halli fmerr("Invalid memory\n"); 615*59da522aSManjunatha Halli return -ENOMEM; 616*59da522aSManjunatha Halli } 617*59da522aSManjunatha Halli 618*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_RD, NULL, 2, 619*59da522aSManjunatha Halli &curr_mode, &resp_len); 620*59da522aSManjunatha Halli if (ret < 0) 621*59da522aSManjunatha Halli return ret; 622*59da522aSManjunatha Halli 623*59da522aSManjunatha Halli *mode = be16_to_cpu(curr_mode); 624*59da522aSManjunatha Halli 625*59da522aSManjunatha Halli return 0; 626*59da522aSManjunatha Halli } 627*59da522aSManjunatha Halli 628*59da522aSManjunatha Halli /* Choose RX de-emphasis filter mode (50us/75us) */ 629*59da522aSManjunatha Halli u32 fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode) 630*59da522aSManjunatha Halli { 631*59da522aSManjunatha Halli u16 payload; 632*59da522aSManjunatha Halli u32 ret; 633*59da522aSManjunatha Halli 634*59da522aSManjunatha Halli if (fmdev->curr_fmmode != FM_MODE_RX) 635*59da522aSManjunatha Halli return -EPERM; 636*59da522aSManjunatha Halli 637*59da522aSManjunatha Halli if (mode != FM_RX_EMPHASIS_FILTER_50_USEC && 638*59da522aSManjunatha Halli mode != FM_RX_EMPHASIS_FILTER_75_USEC) { 639*59da522aSManjunatha Halli fmerr("Invalid rx de-emphasis mode (%d)\n", mode); 640*59da522aSManjunatha Halli return -EINVAL; 641*59da522aSManjunatha Halli } 642*59da522aSManjunatha Halli 643*59da522aSManjunatha Halli payload = mode; 644*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, DEMPH_MODE_SET, REG_WR, &payload, 645*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 646*59da522aSManjunatha Halli if (ret < 0) 647*59da522aSManjunatha Halli return ret; 648*59da522aSManjunatha Halli 649*59da522aSManjunatha Halli fmdev->rx.deemphasis_mode = mode; 650*59da522aSManjunatha Halli 651*59da522aSManjunatha Halli return 0; 652*59da522aSManjunatha Halli } 653*59da522aSManjunatha Halli 654*59da522aSManjunatha Halli /* Gets current RX de-emphasis filter mode */ 655*59da522aSManjunatha Halli u32 fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode) 656*59da522aSManjunatha Halli { 657*59da522aSManjunatha Halli if (fmdev->curr_fmmode != FM_MODE_RX) 658*59da522aSManjunatha Halli return -EPERM; 659*59da522aSManjunatha Halli 660*59da522aSManjunatha Halli if (curr_deemphasis_mode == NULL) { 661*59da522aSManjunatha Halli fmerr("Invalid memory\n"); 662*59da522aSManjunatha Halli return -ENOMEM; 663*59da522aSManjunatha Halli } 664*59da522aSManjunatha Halli 665*59da522aSManjunatha Halli *curr_deemphasis_mode = fmdev->rx.deemphasis_mode; 666*59da522aSManjunatha Halli 667*59da522aSManjunatha Halli return 0; 668*59da522aSManjunatha Halli } 669*59da522aSManjunatha Halli 670*59da522aSManjunatha Halli /* Enable/Disable RX RDS */ 671*59da522aSManjunatha Halli u32 fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) 672*59da522aSManjunatha Halli { 673*59da522aSManjunatha Halli u16 payload; 674*59da522aSManjunatha Halli u32 ret; 675*59da522aSManjunatha Halli 676*59da522aSManjunatha Halli if (rds_en_dis != FM_RDS_ENABLE && rds_en_dis != FM_RDS_DISABLE) { 677*59da522aSManjunatha Halli fmerr("Invalid rds option\n"); 678*59da522aSManjunatha Halli return -EINVAL; 679*59da522aSManjunatha Halli } 680*59da522aSManjunatha Halli 681*59da522aSManjunatha Halli if (rds_en_dis == FM_RDS_ENABLE 682*59da522aSManjunatha Halli && fmdev->rx.rds.flag == FM_RDS_DISABLE) { 683*59da522aSManjunatha Halli /* Turn on RX RDS and RDS circuit */ 684*59da522aSManjunatha Halli payload = FM_RX_PWR_SET_FM_AND_RDS_BLK_ON; 685*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload, 686*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 687*59da522aSManjunatha Halli if (ret < 0) 688*59da522aSManjunatha Halli return ret; 689*59da522aSManjunatha Halli 690*59da522aSManjunatha Halli /* Clear and reset RDS FIFO */ 691*59da522aSManjunatha Halli payload = FM_RX_RDS_FLUSH_FIFO; 692*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, RDS_CNTRL_SET, REG_WR, &payload, 693*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 694*59da522aSManjunatha Halli if (ret < 0) 695*59da522aSManjunatha Halli return ret; 696*59da522aSManjunatha Halli 697*59da522aSManjunatha Halli /* Read flags - just to clear any pending interrupts. */ 698*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, 699*59da522aSManjunatha Halli NULL, NULL); 700*59da522aSManjunatha Halli if (ret < 0) 701*59da522aSManjunatha Halli return ret; 702*59da522aSManjunatha Halli 703*59da522aSManjunatha Halli /* Set RDS FIFO threshold value */ 704*59da522aSManjunatha Halli payload = FM_RX_RDS_FIFO_THRESHOLD; 705*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, RDS_MEM_SET, REG_WR, &payload, 706*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 707*59da522aSManjunatha Halli if (ret < 0) 708*59da522aSManjunatha Halli return ret; 709*59da522aSManjunatha Halli 710*59da522aSManjunatha Halli /* Enable RDS interrupt */ 711*59da522aSManjunatha Halli fmdev->irq_info.mask |= FM_RDS_EVENT; 712*59da522aSManjunatha Halli payload = fmdev->irq_info.mask; 713*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, 714*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 715*59da522aSManjunatha Halli if (ret < 0) { 716*59da522aSManjunatha Halli fmdev->irq_info.mask &= ~FM_RDS_EVENT; 717*59da522aSManjunatha Halli return ret; 718*59da522aSManjunatha Halli } 719*59da522aSManjunatha Halli 720*59da522aSManjunatha Halli /* Update our local flag */ 721*59da522aSManjunatha Halli fmdev->rx.rds.flag = FM_RDS_ENABLE; 722*59da522aSManjunatha Halli } else if (rds_en_dis == FM_RDS_DISABLE 723*59da522aSManjunatha Halli && fmdev->rx.rds.flag == FM_RDS_ENABLE) { 724*59da522aSManjunatha Halli /* Turn off RX RDS */ 725*59da522aSManjunatha Halli payload = FM_RX_PWR_SET_FM_ON_RDS_OFF; 726*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload, 727*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 728*59da522aSManjunatha Halli if (ret < 0) 729*59da522aSManjunatha Halli return ret; 730*59da522aSManjunatha Halli 731*59da522aSManjunatha Halli /* Reset RDS pointers */ 732*59da522aSManjunatha Halli fmdev->rx.rds.last_blk_idx = 0; 733*59da522aSManjunatha Halli fmdev->rx.rds.wr_idx = 0; 734*59da522aSManjunatha Halli fmdev->rx.rds.rd_idx = 0; 735*59da522aSManjunatha Halli fm_rx_reset_station_info(fmdev); 736*59da522aSManjunatha Halli 737*59da522aSManjunatha Halli /* Update RDS local cache */ 738*59da522aSManjunatha Halli fmdev->irq_info.mask &= ~(FM_RDS_EVENT); 739*59da522aSManjunatha Halli fmdev->rx.rds.flag = FM_RDS_DISABLE; 740*59da522aSManjunatha Halli } 741*59da522aSManjunatha Halli 742*59da522aSManjunatha Halli return 0; 743*59da522aSManjunatha Halli } 744*59da522aSManjunatha Halli 745*59da522aSManjunatha Halli /* Returns current RX RDS enable/disable status */ 746*59da522aSManjunatha Halli u32 fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis) 747*59da522aSManjunatha Halli { 748*59da522aSManjunatha Halli if (fmdev->curr_fmmode != FM_MODE_RX) 749*59da522aSManjunatha Halli return -EPERM; 750*59da522aSManjunatha Halli 751*59da522aSManjunatha Halli if (curr_rds_en_dis == NULL) { 752*59da522aSManjunatha Halli fmerr("Invalid memory\n"); 753*59da522aSManjunatha Halli return -ENOMEM; 754*59da522aSManjunatha Halli } 755*59da522aSManjunatha Halli 756*59da522aSManjunatha Halli *curr_rds_en_dis = fmdev->rx.rds.flag; 757*59da522aSManjunatha Halli 758*59da522aSManjunatha Halli return 0; 759*59da522aSManjunatha Halli } 760*59da522aSManjunatha Halli 761*59da522aSManjunatha Halli /* Sets RDS operation mode (RDS/RDBS) */ 762*59da522aSManjunatha Halli u32 fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode) 763*59da522aSManjunatha Halli { 764*59da522aSManjunatha Halli u16 payload; 765*59da522aSManjunatha Halli u32 ret; 766*59da522aSManjunatha Halli 767*59da522aSManjunatha Halli if (fmdev->curr_fmmode != FM_MODE_RX) 768*59da522aSManjunatha Halli return -EPERM; 769*59da522aSManjunatha Halli 770*59da522aSManjunatha Halli if (rds_mode != FM_RDS_SYSTEM_RDS && rds_mode != FM_RDS_SYSTEM_RBDS) { 771*59da522aSManjunatha Halli fmerr("Invalid rds mode\n"); 772*59da522aSManjunatha Halli return -EINVAL; 773*59da522aSManjunatha Halli } 774*59da522aSManjunatha Halli /* Set RDS operation mode */ 775*59da522aSManjunatha Halli payload = (u16)rds_mode; 776*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, RDS_SYSTEM_SET, REG_WR, &payload, 777*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 778*59da522aSManjunatha Halli if (ret < 0) 779*59da522aSManjunatha Halli return ret; 780*59da522aSManjunatha Halli 781*59da522aSManjunatha Halli fmdev->rx.rds_mode = rds_mode; 782*59da522aSManjunatha Halli 783*59da522aSManjunatha Halli return 0; 784*59da522aSManjunatha Halli } 785*59da522aSManjunatha Halli 786*59da522aSManjunatha Halli /* Returns current RDS operation mode */ 787*59da522aSManjunatha Halli u32 fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode) 788*59da522aSManjunatha Halli { 789*59da522aSManjunatha Halli if (fmdev->curr_fmmode != FM_MODE_RX) 790*59da522aSManjunatha Halli return -EPERM; 791*59da522aSManjunatha Halli 792*59da522aSManjunatha Halli if (rds_mode == NULL) { 793*59da522aSManjunatha Halli fmerr("Invalid memory\n"); 794*59da522aSManjunatha Halli return -ENOMEM; 795*59da522aSManjunatha Halli } 796*59da522aSManjunatha Halli 797*59da522aSManjunatha Halli *rds_mode = fmdev->rx.rds_mode; 798*59da522aSManjunatha Halli 799*59da522aSManjunatha Halli return 0; 800*59da522aSManjunatha Halli } 801*59da522aSManjunatha Halli 802*59da522aSManjunatha Halli /* Configures Alternate Frequency switch mode */ 803*59da522aSManjunatha Halli u32 fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode) 804*59da522aSManjunatha Halli { 805*59da522aSManjunatha Halli u16 payload; 806*59da522aSManjunatha Halli u32 ret; 807*59da522aSManjunatha Halli 808*59da522aSManjunatha Halli if (fmdev->curr_fmmode != FM_MODE_RX) 809*59da522aSManjunatha Halli return -EPERM; 810*59da522aSManjunatha Halli 811*59da522aSManjunatha Halli if (af_mode != FM_RX_RDS_AF_SWITCH_MODE_ON && 812*59da522aSManjunatha Halli af_mode != FM_RX_RDS_AF_SWITCH_MODE_OFF) { 813*59da522aSManjunatha Halli fmerr("Invalid af mode\n"); 814*59da522aSManjunatha Halli return -EINVAL; 815*59da522aSManjunatha Halli } 816*59da522aSManjunatha Halli /* Enable/disable low RSSI interrupt based on af_mode */ 817*59da522aSManjunatha Halli if (af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) 818*59da522aSManjunatha Halli fmdev->irq_info.mask |= FM_LEV_EVENT; 819*59da522aSManjunatha Halli else 820*59da522aSManjunatha Halli fmdev->irq_info.mask &= ~FM_LEV_EVENT; 821*59da522aSManjunatha Halli 822*59da522aSManjunatha Halli payload = fmdev->irq_info.mask; 823*59da522aSManjunatha Halli ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, 824*59da522aSManjunatha Halli sizeof(payload), NULL, NULL); 825*59da522aSManjunatha Halli if (ret < 0) 826*59da522aSManjunatha Halli return ret; 827*59da522aSManjunatha Halli 828*59da522aSManjunatha Halli fmdev->rx.af_mode = af_mode; 829*59da522aSManjunatha Halli 830*59da522aSManjunatha Halli return 0; 831*59da522aSManjunatha Halli } 832*59da522aSManjunatha Halli 833*59da522aSManjunatha Halli /* Returns Alternate Frequency switch status */ 834*59da522aSManjunatha Halli u32 fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode) 835*59da522aSManjunatha Halli { 836*59da522aSManjunatha Halli if (fmdev->curr_fmmode != FM_MODE_RX) 837*59da522aSManjunatha Halli return -EPERM; 838*59da522aSManjunatha Halli 839*59da522aSManjunatha Halli if (af_mode == NULL) { 840*59da522aSManjunatha Halli fmerr("Invalid memory\n"); 841*59da522aSManjunatha Halli return -ENOMEM; 842*59da522aSManjunatha Halli } 843*59da522aSManjunatha Halli 844*59da522aSManjunatha Halli *af_mode = fmdev->rx.af_mode; 845*59da522aSManjunatha Halli 846*59da522aSManjunatha Halli return 0; 847*59da522aSManjunatha Halli } 848