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