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