Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/radio/wl128x/fmdrv_rx.c
15112 views
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 <[email protected]>
7
* Author: Manjunatha Halli <[email protected]>
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
}
848
849