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