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