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