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