linux/drivers/media/radio/wl128x/fmdrv_rx.c
<<
>>
Prefs
   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}
 821