blob: d5426048ee796b828f1340356e80edc16c3997a5 [file] [log] [blame]
Venkateshwarlu Domakonda54ec3252013-02-18 21:25:57 +05301/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define DRIVER_AUTHOR "Archana Ramchandran <archanar@codeaurora.org>"
14#define DRIVER_NAME "radio-iris"
15#define DRIVER_CARD "Qualcomm FM Radio Transceiver"
16#define DRIVER_DESC "Driver for Qualcomm FM Radio Transceiver "
17
18#include <linux/version.h>
19#include <linux/init.h>
20#include <linux/delay.h>
21#include <linux/uaccess.h>
22#include <linux/kfifo.h>
23#include <linux/param.h>
24#include <linux/interrupt.h>
25#include <linux/kernel.h>
26#include <linux/module.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070027#include <linux/sched.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028#include <linux/version.h>
29#include <linux/videodev2.h>
30#include <linux/mutex.h>
31#include <linux/unistd.h>
32#include <linux/atomic.h>
33#include <linux/platform_device.h>
34#include <linux/workqueue.h>
35#include <linux/slab.h>
36#include <media/v4l2-common.h>
37#include <media/v4l2-ioctl.h>
38#include <media/radio-iris.h>
39#include <asm/unaligned.h>
40
41static unsigned int rds_buf = 100;
Ayaz Ahmad89265112012-10-05 19:39:11 +053042static int oda_agt;
43static int grp_mask;
44static int rt_plus_carrier = -1;
45static int ert_carrier = -1;
46static unsigned char ert_buf[256];
47static unsigned char ert_len;
48static unsigned char c_byt_pair_index;
49static char utf_8_flag;
50static char rt_ert_flag;
51static char formatting_dir;
Sheng Fang8ec3c6f2013-08-12 14:09:14 +080052static unsigned char sig_blend = CTRL_ON;
Venkateshwarlu Domakonda3ab02ad2013-02-25 14:36:39 +053053static DEFINE_MUTEX(iris_fm);
Ayaz Ahmad89265112012-10-05 19:39:11 +053054
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055module_param(rds_buf, uint, 0);
56MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
57
Sheng Fang8ec3c6f2013-08-12 14:09:14 +080058module_param(sig_blend, byte, S_IWUSR | S_IRUGO);
59MODULE_PARM_DESC(sig_blend, "signal blending switch: 0:OFF 1:ON");
60
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061static void radio_hci_cmd_task(unsigned long arg);
62static void radio_hci_rx_task(unsigned long arg);
63static struct video_device *video_get_dev(void);
64static DEFINE_RWLOCK(hci_task_lock);
65
66struct iris_device {
67 struct device *dev;
68 struct kfifo data_buf[IRIS_BUF_MAX];
69
70 int pending_xfrs[IRIS_XFR_MAX];
71 int xfr_bytes_left;
72 int xfr_in_progress;
73 struct completion sync_xfr_start;
74 int tune_req;
Ankur Nandwanid928d542011-08-11 13:15:41 -070075 unsigned int mode;
76
77 __u16 pi;
78 __u8 pty;
79 __u8 ps_repeatcount;
Ankur Nandwani8f972e52011-08-24 11:48:32 -070080 __u8 prev_trans_rds;
Srinivasa Rao Uppala1da1a242012-01-11 11:00:10 +053081 __u8 af_jump_bit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070082 struct video_device *videodev;
83
84 struct mutex lock;
85 spinlock_t buf_lock[IRIS_BUF_MAX];
86 wait_queue_head_t event_queue;
87 wait_queue_head_t read_queue;
88
89 struct radio_hci_dev *fm_hdev;
90
91 struct v4l2_capability *g_cap;
92 struct v4l2_control *g_ctl;
93
94 struct hci_fm_mute_mode_req mute_mode;
95 struct hci_fm_stereo_mode_req stereo_mode;
96 struct hci_fm_station_rsp fm_st_rsp;
97 struct hci_fm_search_station_req srch_st;
98 struct hci_fm_search_rds_station_req srch_rds;
99 struct hci_fm_search_station_list_req srch_st_list;
100 struct hci_fm_recv_conf_req recv_conf;
Ankur Nandwanid928d542011-08-11 13:15:41 -0700101 struct hci_fm_trans_conf_req_struct trans_conf;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700102 struct hci_fm_rds_grp_req rds_grp;
103 unsigned char g_search_mode;
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +0530104 unsigned char power_mode;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +0530105 int search_on;
Ankur Nandwanid928d542011-08-11 13:15:41 -0700106 unsigned int tone_freq;
Anantha Krishnanf950e322012-06-06 14:25:49 +0530107 unsigned char spur_table_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700108 unsigned char g_scan_time;
109 unsigned int g_antenna;
110 unsigned int g_rds_grp_proc_ps;
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +0530111 unsigned char event_mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700112 enum iris_region_t region;
113 struct hci_fm_dbg_param_rsp st_dbg_param;
114 struct hci_ev_srch_list_compl srch_st_result;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700115 struct hci_fm_riva_poke riva_data_req;
116 struct hci_fm_ssbi_req ssbi_data_accs;
117 struct hci_fm_ssbi_peek ssbi_peek_reg;
Venkateshwarlu Domakonda3d1d6e42011-12-09 15:08:58 +0530118 struct hci_fm_sig_threshold_rsp sig_th;
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +0530119 struct hci_fm_ch_det_threshold ch_det_threshold;
Venkateshwarlu Domakonda71731d52012-04-04 12:30:51 +0530120 struct hci_fm_data_rd_rsp default_data;
Anantha Krishnanf950e322012-06-06 14:25:49 +0530121 struct hci_fm_spur_data spur_data;
Ayaz Ahmad37294ba2012-07-10 16:38:11 +0530122 unsigned char is_station_valid;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700123};
124
125static struct video_device *priv_videodev;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +0530126static int iris_do_calibration(struct iris_device *radio);
Ayaz Ahmad89265112012-10-05 19:39:11 +0530127static void hci_buff_ert(struct iris_device *radio,
128 struct rds_grp_data *rds_buf);
129static void hci_ev_rt_plus(struct iris_device *radio,
130 struct rds_grp_data rds_buf);
131static void hci_ev_ert(struct iris_device *radio);
Anantha Krishnanf950e322012-06-06 14:25:49 +0530132static int update_spur_table(struct iris_device *radio);
Ayaz Ahmad64b1e472013-06-04 15:19:56 +0530133static int initialise_recv(struct iris_device *radio);
134static int initialise_trans(struct iris_device *radio);
135static int is_enable_rx_possible(struct iris_device *radio);
136static int is_enable_tx_possible(struct iris_device *radio);
137
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138static struct v4l2_queryctrl iris_v4l2_queryctrl[] = {
139 {
140 .id = V4L2_CID_AUDIO_VOLUME,
141 .type = V4L2_CTRL_TYPE_INTEGER,
142 .name = "Volume",
143 .minimum = 0,
144 .maximum = 15,
145 .step = 1,
146 .default_value = 15,
147 },
148 {
149 .id = V4L2_CID_AUDIO_BALANCE,
150 .flags = V4L2_CTRL_FLAG_DISABLED,
151 },
152 {
153 .id = V4L2_CID_AUDIO_BASS,
154 .flags = V4L2_CTRL_FLAG_DISABLED,
155 },
156 {
157 .id = V4L2_CID_AUDIO_TREBLE,
158 .flags = V4L2_CTRL_FLAG_DISABLED,
159 },
160 {
161 .id = V4L2_CID_AUDIO_MUTE,
162 .type = V4L2_CTRL_TYPE_BOOLEAN,
163 .name = "Mute",
164 .minimum = 0,
165 .maximum = 1,
166 .step = 1,
167 .default_value = 1,
168 },
169 {
170 .id = V4L2_CID_AUDIO_LOUDNESS,
171 .flags = V4L2_CTRL_FLAG_DISABLED,
172 },
173 {
174 .id = V4L2_CID_PRIVATE_IRIS_SRCHMODE,
175 .type = V4L2_CTRL_TYPE_INTEGER,
176 .name = "Search mode",
177 .minimum = 0,
178 .maximum = 7,
179 .step = 1,
180 .default_value = 0,
181 },
182 {
183 .id = V4L2_CID_PRIVATE_IRIS_SCANDWELL,
184 .type = V4L2_CTRL_TYPE_INTEGER,
185 .name = "Search dwell time",
186 .minimum = 0,
187 .maximum = 7,
188 .step = 1,
189 .default_value = 0,
190 },
191 {
192 .id = V4L2_CID_PRIVATE_IRIS_SRCHON,
193 .type = V4L2_CTRL_TYPE_BOOLEAN,
194 .name = "Search on/off",
195 .minimum = 0,
196 .maximum = 1,
197 .step = 1,
198 .default_value = 1,
199
200 },
201 {
202 .id = V4L2_CID_PRIVATE_IRIS_STATE,
203 .type = V4L2_CTRL_TYPE_INTEGER,
204 .name = "radio 0ff/rx/tx/reset",
205 .minimum = 0,
206 .maximum = 3,
207 .step = 1,
208 .default_value = 1,
209
210 },
211 {
212 .id = V4L2_CID_PRIVATE_IRIS_REGION,
213 .type = V4L2_CTRL_TYPE_INTEGER,
214 .name = "radio standard",
215 .minimum = 0,
216 .maximum = 2,
217 .step = 1,
218 .default_value = 0,
219 },
220 {
221 .id = V4L2_CID_PRIVATE_IRIS_SIGNAL_TH,
222 .type = V4L2_CTRL_TYPE_INTEGER,
223 .name = "Signal Threshold",
224 .minimum = 0x80,
225 .maximum = 0x7F,
226 .step = 1,
227 .default_value = 0,
228 },
229 {
230 .id = V4L2_CID_PRIVATE_IRIS_SRCH_PTY,
231 .type = V4L2_CTRL_TYPE_INTEGER,
232 .name = "Search PTY",
233 .minimum = 0,
234 .maximum = 31,
235 .default_value = 0,
236 },
237 {
238 .id = V4L2_CID_PRIVATE_IRIS_SRCH_PI,
239 .type = V4L2_CTRL_TYPE_INTEGER,
240 .name = "Search PI",
241 .minimum = 0,
242 .maximum = 0xFF,
243 .default_value = 0,
244 },
245 {
246 .id = V4L2_CID_PRIVATE_IRIS_SRCH_CNT,
247 .type = V4L2_CTRL_TYPE_INTEGER,
248 .name = "Preset num",
249 .minimum = 0,
250 .maximum = 12,
251 .default_value = 0,
252 },
253 {
254 .id = V4L2_CID_PRIVATE_IRIS_EMPHASIS,
255 .type = V4L2_CTRL_TYPE_BOOLEAN,
256 .name = "Emphasis",
257 .minimum = 0,
258 .maximum = 1,
259 .default_value = 0,
260 },
261 {
262 .id = V4L2_CID_PRIVATE_IRIS_RDS_STD,
263 .type = V4L2_CTRL_TYPE_BOOLEAN,
264 .name = "RDS standard",
265 .minimum = 0,
266 .maximum = 1,
267 .default_value = 0,
268 },
269 {
270 .id = V4L2_CID_PRIVATE_IRIS_SPACING,
271 .type = V4L2_CTRL_TYPE_INTEGER,
272 .name = "Channel spacing",
273 .minimum = 0,
274 .maximum = 2,
275 .default_value = 0,
276 },
277 {
278 .id = V4L2_CID_PRIVATE_IRIS_RDSON,
279 .type = V4L2_CTRL_TYPE_BOOLEAN,
280 .name = "RDS on/off",
281 .minimum = 0,
282 .maximum = 1,
283 .default_value = 0,
284 },
285 {
286 .id = V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK,
287 .type = V4L2_CTRL_TYPE_INTEGER,
288 .name = "RDS group mask",
289 .minimum = 0,
290 .maximum = 0xFFFFFFFF,
291 .default_value = 0,
292 },
293 {
294 .id = V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC,
295 .type = V4L2_CTRL_TYPE_INTEGER,
296 .name = "RDS processing",
297 .minimum = 0,
298 .maximum = 0xFF,
299 .default_value = 0,
300 },
301 {
302 .id = V4L2_CID_PRIVATE_IRIS_RDSD_BUF,
303 .type = V4L2_CTRL_TYPE_INTEGER,
304 .name = "RDS data groups to buffer",
305 .minimum = 1,
306 .maximum = 21,
307 .default_value = 0,
308 },
309 {
310 .id = V4L2_CID_PRIVATE_IRIS_PSALL,
311 .type = V4L2_CTRL_TYPE_BOOLEAN,
312 .name = "pass all ps strings",
313 .minimum = 0,
314 .maximum = 1,
315 .default_value = 0,
316 },
317 {
318 .id = V4L2_CID_PRIVATE_IRIS_LP_MODE,
319 .type = V4L2_CTRL_TYPE_BOOLEAN,
320 .name = "Low power mode",
321 .minimum = 0,
322 .maximum = 1,
323 .default_value = 0,
324 },
325 {
326 .id = V4L2_CID_PRIVATE_IRIS_ANTENNA,
327 .type = V4L2_CTRL_TYPE_BOOLEAN,
328 .name = "headset/internal",
329 .minimum = 0,
330 .maximum = 1,
331 .default_value = 0,
332 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333 {
334 .id = V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT,
335 .type = V4L2_CTRL_TYPE_INTEGER,
336 .name = "Set PS REPEATCOUNT",
337 .minimum = 0,
338 .maximum = 15,
339 },
340 {
341 .id = V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME,
342 .type = V4L2_CTRL_TYPE_BOOLEAN,
343 .name = "Stop PS NAME",
344 .minimum = 0,
345 .maximum = 1,
346 },
347 {
348 .id = V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT,
349 .type = V4L2_CTRL_TYPE_BOOLEAN,
350 .name = "Stop RT",
351 .minimum = 0,
352 .maximum = 1,
353 },
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700354 {
355 .id = V4L2_CID_PRIVATE_IRIS_SOFT_MUTE,
356 .type = V4L2_CTRL_TYPE_BOOLEAN,
357 .name = "Soft Mute",
358 .minimum = 0,
359 .maximum = 1,
360 },
361 {
362 .id = V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR,
363 .type = V4L2_CTRL_TYPE_BOOLEAN,
364 .name = "Riva addr",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530365 .minimum = 0x3180000,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700366 .maximum = 0x31E0004,
367 },
368 {
369 .id = V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN,
370 .type = V4L2_CTRL_TYPE_INTEGER,
371 .name = "Data len",
372 .minimum = 0,
373 .maximum = 0xFF,
374 },
375 {
376 .id = V4L2_CID_PRIVATE_IRIS_RIVA_PEEK,
377 .type = V4L2_CTRL_TYPE_BOOLEAN,
378 .name = "Riva peek",
379 .minimum = 0,
380 .maximum = 1,
381 },
382 {
383 .id = V4L2_CID_PRIVATE_IRIS_RIVA_POKE,
384 .type = V4L2_CTRL_TYPE_INTEGER,
385 .name = "Riva poke",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530386 .minimum = 0x3180000,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700387 .maximum = 0x31E0004,
388 },
389 {
390 .id = V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR,
391 .type = V4L2_CTRL_TYPE_INTEGER,
392 .name = "Ssbi addr",
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530393 .minimum = 0x280,
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -0700394 .maximum = 0x37F,
395 },
396 {
397 .id = V4L2_CID_PRIVATE_IRIS_SSBI_PEEK,
398 .type = V4L2_CTRL_TYPE_INTEGER,
399 .name = "Ssbi peek",
400 .minimum = 0,
401 .maximum = 0x37F,
402 },
403 {
404 .id = V4L2_CID_PRIVATE_IRIS_SSBI_POKE,
405 .type = V4L2_CTRL_TYPE_INTEGER,
406 .name = "ssbi poke",
407 .minimum = 0x01,
408 .maximum = 0xFF,
409 },
410 {
411 .id = V4L2_CID_PRIVATE_IRIS_HLSI,
412 .type = V4L2_CTRL_TYPE_INTEGER,
413 .name = "set hlsi",
414 .minimum = 0,
415 .maximum = 2,
416 },
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +0530417 {
418 .id = V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS,
419 .type = V4L2_CTRL_TYPE_BOOLEAN,
420 .name = "RDS grp",
421 .minimum = 0,
422 .maximum = 1,
423 },
424 {
425 .id = V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER,
426 .type = V4L2_CTRL_TYPE_INTEGER,
427 .name = "Notch filter",
428 .minimum = 0,
429 .maximum = 2,
430 },
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +0530431 {
432 .id = V4L2_CID_PRIVATE_IRIS_READ_DEFAULT,
433 .type = V4L2_CTRL_TYPE_INTEGER,
434 .name = "Read default",
435 },
436 {
437 .id = V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT,
438 .type = V4L2_CTRL_TYPE_INTEGER,
439 .name = "Write default",
440 },
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +0530441 {
442 .id = V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION,
443 .type = V4L2_CTRL_TYPE_BOOLEAN,
444 .name = "SET Calibration",
445 .minimum = 0,
446 .maximum = 1,
447 },
448 {
449 .id = V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION,
450 .type = V4L2_CTRL_TYPE_BOOLEAN,
451 .name = "SET Calibration",
452 .minimum = 0,
453 .maximum = 1,
454 },
Srinivasa Rao Uppalaacdebcc2011-12-23 14:31:38 +0530455 {
456 .id = V4L2_CID_PRIVATE_IRIS_GET_SINR,
457 .type = V4L2_CTRL_TYPE_INTEGER,
458 .name = "GET SINR",
459 .minimum = -128,
460 .maximum = 127,
461 },
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +0530462 {
463 .id = V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD,
464 .type = V4L2_CTRL_TYPE_INTEGER,
465 .name = "Intf High Threshold",
466 .minimum = 0,
467 .maximum = 0xFF,
468 .default_value = 0,
469 },
470 {
471 .id = V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD,
472 .type = V4L2_CTRL_TYPE_INTEGER,
473 .name = "Intf low Threshold",
474 .minimum = 0,
475 .maximum = 0xFF,
476 .default_value = 0,
477 },
478 {
479 .id = V4L2_CID_PRIVATE_SINR_THRESHOLD,
480 .type = V4L2_CTRL_TYPE_INTEGER,
481 .name = "SINR Threshold",
482 .minimum = -128,
483 .maximum = 127,
484 .default_value = 0,
485 },
486 {
487 .id = V4L2_CID_PRIVATE_SINR_SAMPLES,
488 .type = V4L2_CTRL_TYPE_INTEGER,
489 .name = "SINR samples",
490 .minimum = 1,
491 .maximum = 0xFF,
492 .default_value = 0,
493 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700494};
495
496static void iris_q_event(struct iris_device *radio,
497 enum iris_evt_t event)
498{
Ayaz Ahmad53177572013-10-09 16:20:40 +0530499 struct kfifo *data_b;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700500 unsigned char evt = event;
Ayaz Ahmad53177572013-10-09 16:20:40 +0530501
502 if (radio == NULL) {
503 FMDERR(":radio is null");
504 return;
505 }
506
507 data_b = &radio->data_buf[IRIS_BUF_EVENTS];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508 if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[IRIS_BUF_EVENTS]))
509 wake_up_interruptible(&radio->event_queue);
510}
511
512static int hci_send_frame(struct sk_buff *skb)
513{
514 struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
515
516 if (!hdev) {
517 kfree_skb(skb);
518 return -ENODEV;
519 }
520
521 __net_timestamp(skb);
522
523 skb_orphan(skb);
524 return hdev->send(skb);
525}
526
527static void radio_hci_cmd_task(unsigned long arg)
528{
529 struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
530 struct sk_buff *skb;
531 if (!(atomic_read(&hdev->cmd_cnt))
532 && time_after(jiffies, hdev->cmd_last_tx + HZ)) {
533 FMDERR("%s command tx timeout", hdev->name);
534 atomic_set(&hdev->cmd_cnt, 1);
535 }
536
537 skb = skb_dequeue(&hdev->cmd_q);
538 if (atomic_read(&hdev->cmd_cnt) && skb) {
539 kfree_skb(hdev->sent_cmd);
540 hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);
541 if (hdev->sent_cmd) {
542 atomic_dec(&hdev->cmd_cnt);
543 hci_send_frame(skb);
544 hdev->cmd_last_tx = jiffies;
545 } else {
546 skb_queue_head(&hdev->cmd_q, skb);
547 tasklet_schedule(&hdev->cmd_task);
548 }
549 }
550
551}
552
553static void radio_hci_rx_task(unsigned long arg)
554{
555 struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
556 struct sk_buff *skb;
557
558 read_lock(&hci_task_lock);
559
560 skb = skb_dequeue(&hdev->rx_q);
561 radio_hci_event_packet(hdev, skb);
562
563 read_unlock(&hci_task_lock);
564}
565
566int radio_hci_register_dev(struct radio_hci_dev *hdev)
567{
568 struct iris_device *radio = video_get_drvdata(video_get_dev());
569 if (!radio) {
570 FMDERR(":radio is null");
571 return -EINVAL;
572 }
573
574 if (!hdev) {
575 FMDERR("hdev is null");
576 return -EINVAL;
577 }
578
579 hdev->flags = 0;
580
581 tasklet_init(&hdev->cmd_task, radio_hci_cmd_task, (unsigned long)
582 hdev);
583 tasklet_init(&hdev->rx_task, radio_hci_rx_task, (unsigned long)
584 hdev);
585
586 init_waitqueue_head(&hdev->req_wait_q);
587
588 skb_queue_head_init(&hdev->rx_q);
589 skb_queue_head_init(&hdev->cmd_q);
590 skb_queue_head_init(&hdev->raw_q);
591
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700592
593 radio->fm_hdev = hdev;
594
595 return 0;
596}
597EXPORT_SYMBOL(radio_hci_register_dev);
598
599int radio_hci_unregister_dev(struct radio_hci_dev *hdev)
600{
601 struct iris_device *radio = video_get_drvdata(video_get_dev());
602 if (!radio) {
603 FMDERR(":radio is null");
604 return -EINVAL;
605 }
606
607 tasklet_kill(&hdev->rx_task);
608 tasklet_kill(&hdev->cmd_task);
609 skb_queue_purge(&hdev->rx_q);
610 skb_queue_purge(&hdev->cmd_q);
611 skb_queue_purge(&hdev->raw_q);
612 kfree(radio->fm_hdev);
613 kfree(radio->videodev);
614
615 return 0;
616}
617EXPORT_SYMBOL(radio_hci_unregister_dev);
618
619int radio_hci_recv_frame(struct sk_buff *skb)
620{
621 struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
622 if (!hdev) {
623 FMDERR("%s hdev is null while receiving frame", hdev->name);
624 kfree_skb(skb);
625 return -ENXIO;
626 }
627
628 __net_timestamp(skb);
629
630 radio_hci_event_packet(hdev, skb);
Srinivasa Rao Uppalacf3a8112011-09-22 21:02:02 +0530631 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700632 return 0;
633}
634EXPORT_SYMBOL(radio_hci_recv_frame);
635
636int radio_hci_send_cmd(struct radio_hci_dev *hdev, __u16 opcode, __u32 plen,
637 void *param)
638{
639 int len = RADIO_HCI_COMMAND_HDR_SIZE + plen;
640 struct radio_hci_command_hdr *hdr;
641 struct sk_buff *skb;
642 int ret = 0;
643
644 skb = alloc_skb(len, GFP_ATOMIC);
645 if (!skb) {
646 FMDERR("%s no memory for command", hdev->name);
647 return -ENOMEM;
648 }
649
650 hdr = (struct radio_hci_command_hdr *) skb_put(skb,
651 RADIO_HCI_COMMAND_HDR_SIZE);
652 hdr->opcode = cpu_to_le16(opcode);
653 hdr->plen = plen;
654
655 if (plen)
656 memcpy(skb_put(skb, plen), param, plen);
657
658 skb->dev = (void *) hdev;
659
660 ret = hci_send_frame(skb);
661
662 return ret;
663}
664EXPORT_SYMBOL(radio_hci_send_cmd);
665
666static int hci_fm_enable_recv_req(struct radio_hci_dev *hdev,
667 unsigned long param)
668{
669 __u16 opcode = 0;
670
671 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
672 HCI_OCF_FM_ENABLE_RECV_REQ);
673 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
674}
675
Ankur Nandwanid928d542011-08-11 13:15:41 -0700676static int hci_fm_tone_generator(struct radio_hci_dev *hdev,
677 unsigned long param)
678{
679 struct iris_device *radio = video_get_drvdata(video_get_dev());
680 __u16 opcode = 0;
681
Ayaz Ahmad53177572013-10-09 16:20:40 +0530682 if (radio == NULL) {
683 FMDERR(":radio is null");
684 return -EINVAL;
685 }
Ankur Nandwanid928d542011-08-11 13:15:41 -0700686 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
687 HCI_FM_SET_INTERNAL_TONE_GENRATOR);
688 return radio_hci_send_cmd(hdev, opcode,
689 sizeof(radio->tone_freq), &radio->tone_freq);
690}
691
692static int hci_fm_enable_trans_req(struct radio_hci_dev *hdev,
693 unsigned long param)
694{
695 __u16 opcode = 0;
696
697 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
698 HCI_OCF_FM_ENABLE_TRANS_REQ);
699 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
700}
701
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700702static int hci_fm_disable_recv_req(struct radio_hci_dev *hdev,
703 unsigned long param)
704{
705 __u16 opcode = 0;
706
707 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
708 HCI_OCF_FM_DISABLE_RECV_REQ);
709 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
710}
711
Ankur Nandwanid928d542011-08-11 13:15:41 -0700712static int hci_fm_disable_trans_req(struct radio_hci_dev *hdev,
713 unsigned long param)
714{
715 __u16 opcode = 0;
716
717 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
718 HCI_OCF_FM_DISABLE_TRANS_REQ);
719 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
720}
721
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722static int hci_get_fm_recv_conf_req(struct radio_hci_dev *hdev,
723 unsigned long param)
724{
725 __u16 opcode = 0;
726
727 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
728 HCI_OCF_FM_GET_RECV_CONF_REQ);
729 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
730}
731
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +0530732static int hci_get_fm_trans_conf_req(struct radio_hci_dev *hdev,
733 unsigned long param)
734{
735 u16 opcode = 0;
736
737 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
738 HCI_OCF_FM_GET_TRANS_CONF_REQ);
739 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
740}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700741static int hci_set_fm_recv_conf_req(struct radio_hci_dev *hdev,
742 unsigned long param)
743{
744 __u16 opcode = 0;
745
746 struct hci_fm_recv_conf_req *recv_conf_req =
747 (struct hci_fm_recv_conf_req *) param;
748
749 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
750 HCI_OCF_FM_SET_RECV_CONF_REQ);
751 return radio_hci_send_cmd(hdev, opcode, sizeof((*recv_conf_req)),
752 recv_conf_req);
753}
754
Ankur Nandwanid928d542011-08-11 13:15:41 -0700755static int hci_set_fm_trans_conf_req(struct radio_hci_dev *hdev,
756 unsigned long param)
757{
758 __u16 opcode = 0;
759
760 struct hci_fm_trans_conf_req_struct *trans_conf_req =
761 (struct hci_fm_trans_conf_req_struct *) param;
762
763 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
764 HCI_OCF_FM_SET_TRANS_CONF_REQ);
765 return radio_hci_send_cmd(hdev, opcode, sizeof((*trans_conf_req)),
766 trans_conf_req);
767}
768
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700769static int hci_fm_get_station_param_req(struct radio_hci_dev *hdev,
770 unsigned long param)
771{
772 __u16 opcode = 0;
773
774 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
775 HCI_OCF_FM_GET_STATION_PARAM_REQ);
776 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
777}
778
779static int hci_set_fm_mute_mode_req(struct radio_hci_dev *hdev,
780 unsigned long param)
781{
782 __u16 opcode = 0;
783 struct hci_fm_mute_mode_req *mute_mode_req =
784 (struct hci_fm_mute_mode_req *) param;
785
786 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
787 HCI_OCF_FM_SET_MUTE_MODE_REQ);
788 return radio_hci_send_cmd(hdev, opcode, sizeof((*mute_mode_req)),
789 mute_mode_req);
790}
791
Ankur Nandwanid928d542011-08-11 13:15:41 -0700792
793static int hci_trans_ps_req(struct radio_hci_dev *hdev,
794 unsigned long param)
795{
796 __u16 opcode = 0;
797 struct hci_fm_tx_ps *tx_ps_req =
798 (struct hci_fm_tx_ps *) param;
799
800 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
801 HCI_OCF_FM_RDS_PS_REQ);
802
803 return radio_hci_send_cmd(hdev, opcode, sizeof((*tx_ps_req)),
804 tx_ps_req);
805}
806
807static int hci_trans_rt_req(struct radio_hci_dev *hdev,
808 unsigned long param)
809{
810 __u16 opcode = 0;
811 struct hci_fm_tx_rt *tx_rt_req =
812 (struct hci_fm_tx_rt *) param;
813
814 opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
815 HCI_OCF_FM_RDS_RT_REQ);
816
817 return radio_hci_send_cmd(hdev, opcode, sizeof((*tx_rt_req)),
818 tx_rt_req);
819}
820
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821static int hci_set_fm_stereo_mode_req(struct radio_hci_dev *hdev,
822 unsigned long param)
823{
824 __u16 opcode = 0;
825 struct hci_fm_stereo_mode_req *stereo_mode_req =
826 (struct hci_fm_stereo_mode_req *) param;
827 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
828 HCI_OCF_FM_SET_STEREO_MODE_REQ);
829 return radio_hci_send_cmd(hdev, opcode, sizeof((*stereo_mode_req)),
830 stereo_mode_req);
831}
832
833static int hci_fm_set_antenna_req(struct radio_hci_dev *hdev,
834 unsigned long param)
835{
836 __u16 opcode = 0;
837
838 __u8 antenna = param;
839
840 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
841 HCI_OCF_FM_SET_ANTENNA);
842 return radio_hci_send_cmd(hdev, opcode, sizeof(antenna), &antenna);
843}
844
845static int hci_fm_set_sig_threshold_req(struct radio_hci_dev *hdev,
846 unsigned long param)
847{
848 __u16 opcode = 0;
849
850 __u8 sig_threshold = param;
851
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530852 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700853 HCI_OCF_FM_SET_SIGNAL_THRESHOLD);
854 return radio_hci_send_cmd(hdev, opcode, sizeof(sig_threshold),
855 &sig_threshold);
856}
857
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +0530858static int hci_fm_set_event_mask(struct radio_hci_dev *hdev,
859 unsigned long param)
860{
861 u16 opcode = 0;
862 u8 event_mask = param;
863
864 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
865 HCI_OCF_FM_SET_EVENT_MASK);
866 return radio_hci_send_cmd(hdev, opcode, sizeof(event_mask),
867 &event_mask);
868}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700869static int hci_fm_get_sig_threshold_req(struct radio_hci_dev *hdev,
870 unsigned long param)
871{
872 __u16 opcode = 0;
873
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530874 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700875 HCI_OCF_FM_GET_SIGNAL_THRESHOLD);
876 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
877}
878
879static int hci_fm_get_program_service_req(struct radio_hci_dev *hdev,
880 unsigned long param)
881{
882 __u16 opcode = 0;
883
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530884 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700885 HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ);
886 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
887}
888
889static int hci_fm_get_radio_text_req(struct radio_hci_dev *hdev,
890 unsigned long param)
891{
892 __u16 opcode = 0;
893
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530894 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700895 HCI_OCF_FM_GET_RADIO_TEXT_REQ);
896 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
897}
898
899static int hci_fm_get_af_list_req(struct radio_hci_dev *hdev,
900 unsigned long param)
901{
902 __u16 opcode = 0;
903
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +0530904 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700905 HCI_OCF_FM_GET_AF_LIST_REQ);
906 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
907}
908
909static int hci_fm_search_stations_req(struct radio_hci_dev *hdev,
910 unsigned long param)
911{
912 __u16 opcode = 0;
913 struct hci_fm_search_station_req *srch_stations =
914 (struct hci_fm_search_station_req *) param;
915
916 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
917 HCI_OCF_FM_SEARCH_STATIONS);
918 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
919 srch_stations);
920}
921
922static int hci_fm_srch_rds_stations_req(struct radio_hci_dev *hdev,
923 unsigned long param)
924{
925 __u16 opcode = 0;
926 struct hci_fm_search_rds_station_req *srch_stations =
927 (struct hci_fm_search_rds_station_req *) param;
928
929 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
930 HCI_OCF_FM_SEARCH_RDS_STATIONS);
931 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
932 srch_stations);
933}
934
935static int hci_fm_srch_station_list_req(struct radio_hci_dev *hdev,
936 unsigned long param)
937{
938 __u16 opcode = 0;
939 struct hci_fm_search_station_list_req *srch_list =
940 (struct hci_fm_search_station_list_req *) param;
941
942 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
943 HCI_OCF_FM_SEARCH_STATIONS_LIST);
944 return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_list)),
945 srch_list);
946}
947
948static int hci_fm_cancel_search_req(struct radio_hci_dev *hdev,
949 unsigned long param)
950{
951 __u16 opcode = 0;
952
953 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
954 HCI_OCF_FM_CANCEL_SEARCH);
955 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
956}
957
Ayaz Ahmad89265112012-10-05 19:39:11 +0530958static int hci_fm_rds_grp_mask_req(struct radio_hci_dev *hdev,
959 unsigned long param)
960{
961 __u16 opcode = 0;
962
963 struct hci_fm_rds_grp_req *fm_grp_mask =
964 (struct hci_fm_rds_grp_req *)param;
965
966 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
967 HCI_OCF_FM_RDS_GRP);
968 return radio_hci_send_cmd(hdev, opcode, sizeof(*fm_grp_mask),
969 fm_grp_mask);
970}
971
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700972static int hci_fm_rds_grp_process_req(struct radio_hci_dev *hdev,
973 unsigned long param)
974{
975 __u16 opcode = 0;
976
977 __u32 fm_grps_process = param;
978
979 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
980 HCI_OCF_FM_RDS_GRP_PROCESS);
981 return radio_hci_send_cmd(hdev, opcode, sizeof(fm_grps_process),
982 &fm_grps_process);
983}
984
985static int hci_fm_tune_station_req(struct radio_hci_dev *hdev,
986 unsigned long param)
987{
988 __u16 opcode = 0;
989
990 __u32 tune_freq = param;
991
992 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
993 HCI_OCF_FM_TUNE_STATION_REQ);
994 return radio_hci_send_cmd(hdev, opcode, sizeof(tune_freq), &tune_freq);
995}
996
997static int hci_def_data_read_req(struct radio_hci_dev *hdev,
998 unsigned long param)
999{
1000 __u16 opcode = 0;
1001 struct hci_fm_def_data_rd_req *def_data_rd =
1002 (struct hci_fm_def_data_rd_req *) param;
1003
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301004 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001005 HCI_OCF_FM_DEFAULT_DATA_READ);
1006 return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_rd)),
1007 def_data_rd);
1008}
1009
1010static int hci_def_data_write_req(struct radio_hci_dev *hdev,
1011 unsigned long param)
1012{
1013 __u16 opcode = 0;
1014 struct hci_fm_def_data_wr_req *def_data_wr =
1015 (struct hci_fm_def_data_wr_req *) param;
1016
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301017 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001018 HCI_OCF_FM_DEFAULT_DATA_WRITE);
Anantha Krishnan152fe5b2012-02-28 18:07:20 +05301019
1020 return radio_hci_send_cmd(hdev, opcode, (def_data_wr->length+2),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001021 def_data_wr);
1022}
1023
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301024static int hci_set_notch_filter_req(struct radio_hci_dev *hdev,
1025 unsigned long param)
1026{
1027 __u16 opcode = 0;
1028 __u8 notch_filter_val = param;
1029
1030 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
1031 HCI_OCF_FM_EN_NOTCH_CTRL);
1032 return radio_hci_send_cmd(hdev, opcode, sizeof(notch_filter_val),
1033 &notch_filter_val);
1034}
1035
1036
1037
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001038static int hci_fm_reset_req(struct radio_hci_dev *hdev, unsigned long param)
1039{
1040 __u16 opcode = 0;
1041
1042 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1043 HCI_OCF_FM_RESET);
1044 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
1045}
1046
1047static int hci_fm_get_feature_lists_req(struct radio_hci_dev *hdev,
1048 unsigned long param)
1049{
1050 __u16 opcode = 0;
1051
1052 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1053 HCI_OCF_FM_GET_FEATURE_LIST);
1054 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
1055}
1056
1057static int hci_fm_do_calibration_req(struct radio_hci_dev *hdev,
1058 unsigned long param)
1059{
1060 __u16 opcode = 0;
1061
1062 __u8 mode = param;
1063
1064 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1065 HCI_OCF_FM_DO_CALIBRATION);
1066 return radio_hci_send_cmd(hdev, opcode, sizeof(mode), &mode);
1067}
1068
1069static int hci_read_grp_counters_req(struct radio_hci_dev *hdev,
1070 unsigned long param)
1071{
1072 __u16 opcode = 0;
1073
1074 __u8 reset_counters = param;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301075 opcode = hci_opcode_pack(HCI_OGF_FM_STATUS_PARAMETERS_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001076 HCI_OCF_FM_READ_GRP_COUNTERS);
1077 return radio_hci_send_cmd(hdev, opcode, sizeof(reset_counters),
1078 &reset_counters);
1079}
1080
1081static int hci_peek_data_req(struct radio_hci_dev *hdev, unsigned long param)
1082{
1083 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001084 struct hci_fm_riva_data *peek_data = (struct hci_fm_riva_data *)param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001085
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001086 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001087 HCI_OCF_FM_PEEK_DATA);
1088 return radio_hci_send_cmd(hdev, opcode, sizeof((*peek_data)),
1089 peek_data);
1090}
1091
1092static int hci_poke_data_req(struct radio_hci_dev *hdev, unsigned long param)
1093{
1094 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001095 struct hci_fm_riva_poke *poke_data = (struct hci_fm_riva_poke *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001096
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -07001097 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001098 HCI_OCF_FM_POKE_DATA);
1099 return radio_hci_send_cmd(hdev, opcode, sizeof((*poke_data)),
1100 poke_data);
1101}
1102
1103static int hci_ssbi_peek_reg_req(struct radio_hci_dev *hdev,
1104 unsigned long param)
1105{
1106 __u16 opcode = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001107 struct hci_fm_ssbi_peek *ssbi_peek = (struct hci_fm_ssbi_peek *) param;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001108
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001109 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001110 HCI_OCF_FM_SSBI_PEEK_REG);
1111 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_peek)),
1112 ssbi_peek);
1113}
1114
1115static int hci_ssbi_poke_reg_req(struct radio_hci_dev *hdev,
1116 unsigned long param)
1117{
1118 __u16 opcode = 0;
1119 struct hci_fm_ssbi_req *ssbi_poke = (struct hci_fm_ssbi_req *) param;
1120
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001121 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122 HCI_OCF_FM_SSBI_POKE_REG);
1123 return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_poke)),
1124 ssbi_poke);
1125}
1126
1127static int hci_fm_get_station_dbg_param_req(struct radio_hci_dev *hdev,
1128 unsigned long param)
1129{
1130 __u16 opcode = 0;
1131
Venkateshwarlu Domakonda1c67b752011-10-17 13:05:48 +05301132 opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001133 HCI_OCF_FM_STATION_DBG_PARAM);
1134 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
1135}
1136
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +05301137static int hci_fm_set_ch_det_th(struct radio_hci_dev *hdev,
1138 unsigned long param)
1139{
1140 struct hci_fm_ch_det_threshold *ch_det_th =
1141 (struct hci_fm_ch_det_threshold *) param;
1142 u16 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
1143 HCI_OCF_FM_SET_CH_DET_THRESHOLD);
1144 return radio_hci_send_cmd(hdev, opcode, sizeof((*ch_det_th)),
1145 ch_det_th);
1146}
1147
1148static int hci_fm_get_ch_det_th(struct radio_hci_dev *hdev,
1149 unsigned long param)
1150{
1151 u16 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
1152 HCI_OCF_FM_GET_CH_DET_THRESHOLD);
1153 return radio_hci_send_cmd(hdev, opcode, 0, NULL);
1154}
1155
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001156static int radio_hci_err(__u16 code)
1157{
1158 switch (code) {
1159 case 0:
1160 return 0;
1161 case 0x01:
1162 return -EBADRQC;
1163 case 0x02:
1164 return -ENOTCONN;
1165 case 0x03:
1166 return -EIO;
1167 case 0x07:
1168 return -ENOMEM;
1169 case 0x0c:
1170 return -EBUSY;
1171 case 0x11:
1172 return -EOPNOTSUPP;
1173 case 0x12:
1174 return -EINVAL;
1175 default:
1176 return -ENOSYS;
1177 }
1178}
1179
1180static int __radio_hci_request(struct radio_hci_dev *hdev,
1181 int (*req)(struct radio_hci_dev *hdev,
1182 unsigned long param),
1183 unsigned long param, __u32 timeout)
1184{
1185 int err = 0;
1186
1187 DECLARE_WAITQUEUE(wait, current);
1188
Venkateshwarlu Domakonda3ab02ad2013-02-25 14:36:39 +05301189 mutex_lock(&iris_fm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001190 hdev->req_status = HCI_REQ_PEND;
1191
1192 add_wait_queue(&hdev->req_wait_q, &wait);
1193 set_current_state(TASK_INTERRUPTIBLE);
1194
1195 err = req(hdev, param);
1196
1197 schedule_timeout(timeout);
1198
1199 remove_wait_queue(&hdev->req_wait_q, &wait);
1200
Venkateshwarlu Domakonda3ab02ad2013-02-25 14:36:39 +05301201 if (signal_pending(current)) {
1202 mutex_unlock(&iris_fm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001203 return -EINTR;
Venkateshwarlu Domakonda3ab02ad2013-02-25 14:36:39 +05301204 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205
1206 switch (hdev->req_status) {
1207 case HCI_REQ_DONE:
1208 case HCI_REQ_STATUS:
1209 err = radio_hci_err(hdev->req_result);
1210 break;
1211
1212 case HCI_REQ_CANCELED:
1213 err = -hdev->req_result;
1214 break;
1215
1216 default:
1217 err = -ETIMEDOUT;
1218 break;
1219 }
1220
1221 hdev->req_status = hdev->req_result = 0;
Venkateshwarlu Domakonda3ab02ad2013-02-25 14:36:39 +05301222 mutex_unlock(&iris_fm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001223
1224 return err;
1225}
1226
1227static inline int radio_hci_request(struct radio_hci_dev *hdev,
1228 int (*req)(struct
1229 radio_hci_dev * hdev, unsigned long param),
1230 unsigned long param, __u32 timeout)
1231{
1232 int ret = 0;
1233
1234 ret = __radio_hci_request(hdev, req, param, timeout);
1235
1236 return ret;
1237}
1238
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05301239static inline int hci_conf_event_mask(__u8 *arg,
1240 struct radio_hci_dev *hdev)
1241{
1242 u8 event_mask = *arg;
1243 return radio_hci_request(hdev, hci_fm_set_event_mask,
1244 event_mask, RADIO_HCI_TIMEOUT);
1245}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001246static int hci_set_fm_recv_conf(struct hci_fm_recv_conf_req *arg,
1247 struct radio_hci_dev *hdev)
1248{
1249 int ret = 0;
1250 struct hci_fm_recv_conf_req *set_recv_conf = arg;
1251
1252 ret = radio_hci_request(hdev, hci_set_fm_recv_conf_req, (unsigned
1253 long)set_recv_conf, RADIO_HCI_TIMEOUT);
1254
1255 return ret;
1256}
1257
Ankur Nandwanid928d542011-08-11 13:15:41 -07001258static int hci_set_fm_trans_conf(struct hci_fm_trans_conf_req_struct *arg,
1259 struct radio_hci_dev *hdev)
1260{
1261 int ret = 0;
1262 struct hci_fm_trans_conf_req_struct *set_trans_conf = arg;
1263
1264 ret = radio_hci_request(hdev, hci_set_fm_trans_conf_req, (unsigned
1265 long)set_trans_conf, RADIO_HCI_TIMEOUT);
1266
1267 return ret;
1268}
1269
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001270static int hci_fm_tune_station(__u32 *arg, struct radio_hci_dev *hdev)
1271{
1272 int ret = 0;
1273 __u32 tune_freq = *arg;
1274
1275 ret = radio_hci_request(hdev, hci_fm_tune_station_req, tune_freq,
1276 RADIO_HCI_TIMEOUT);
1277
1278 return ret;
1279}
1280
1281static int hci_set_fm_mute_mode(struct hci_fm_mute_mode_req *arg,
1282 struct radio_hci_dev *hdev)
1283{
1284 int ret = 0;
1285 struct hci_fm_mute_mode_req *set_mute_conf = arg;
1286
1287 ret = radio_hci_request(hdev, hci_set_fm_mute_mode_req, (unsigned
1288 long)set_mute_conf, RADIO_HCI_TIMEOUT);
1289
1290 return ret;
1291}
1292
1293static int hci_set_fm_stereo_mode(struct hci_fm_stereo_mode_req *arg,
1294 struct radio_hci_dev *hdev)
1295{
1296 int ret = 0;
1297 struct hci_fm_stereo_mode_req *set_stereo_conf = arg;
1298
1299 ret = radio_hci_request(hdev, hci_set_fm_stereo_mode_req, (unsigned
1300 long)set_stereo_conf, RADIO_HCI_TIMEOUT);
1301
1302 return ret;
1303}
1304
1305static int hci_fm_set_antenna(__u8 *arg, struct radio_hci_dev *hdev)
1306{
1307 int ret = 0;
1308 __u8 antenna = *arg;
1309
1310 ret = radio_hci_request(hdev, hci_fm_set_antenna_req, antenna,
1311 RADIO_HCI_TIMEOUT);
1312
1313 return ret;
1314}
1315
1316static int hci_fm_set_signal_threshold(__u8 *arg,
1317 struct radio_hci_dev *hdev)
1318{
1319 int ret = 0;
1320 __u8 sig_threshold = *arg;
1321
1322 ret = radio_hci_request(hdev, hci_fm_set_sig_threshold_req,
1323 sig_threshold, RADIO_HCI_TIMEOUT);
1324
1325 return ret;
1326}
1327
1328static int hci_fm_search_stations(struct hci_fm_search_station_req *arg,
1329 struct radio_hci_dev *hdev)
1330{
1331 int ret = 0;
1332 struct hci_fm_search_station_req *srch_stations = arg;
1333
1334 ret = radio_hci_request(hdev, hci_fm_search_stations_req, (unsigned
1335 long)srch_stations, RADIO_HCI_TIMEOUT);
1336
1337 return ret;
1338}
1339
1340static int hci_fm_search_rds_stations(struct hci_fm_search_rds_station_req *arg,
1341 struct radio_hci_dev *hdev)
1342{
1343 int ret = 0;
1344 struct hci_fm_search_rds_station_req *srch_stations = arg;
1345
1346 ret = radio_hci_request(hdev, hci_fm_srch_rds_stations_req, (unsigned
1347 long)srch_stations, RADIO_HCI_TIMEOUT);
1348
1349 return ret;
1350}
1351
1352static int hci_fm_search_station_list
1353 (struct hci_fm_search_station_list_req *arg,
1354 struct radio_hci_dev *hdev)
1355{
1356 int ret = 0;
1357 struct hci_fm_search_station_list_req *srch_list = arg;
1358
1359 ret = radio_hci_request(hdev, hci_fm_srch_station_list_req, (unsigned
1360 long)srch_list, RADIO_HCI_TIMEOUT);
1361
1362 return ret;
1363}
1364
1365static int hci_fm_rds_grp(struct hci_fm_rds_grp_req *arg,
1366 struct radio_hci_dev *hdev)
1367{
Ayaz Ahmad89265112012-10-05 19:39:11 +05301368 int ret = 0;
1369 struct hci_fm_rds_grp_req *fm_grp_mask = arg;
1370
1371 ret = radio_hci_request(hdev, hci_fm_rds_grp_mask_req, (unsigned
1372 long)fm_grp_mask, RADIO_HCI_TIMEOUT);
1373
1374 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001375}
1376
1377static int hci_fm_rds_grps_process(__u32 *arg, struct radio_hci_dev *hdev)
1378{
1379 int ret = 0;
1380 __u32 fm_grps_process = *arg;
1381
1382 ret = radio_hci_request(hdev, hci_fm_rds_grp_process_req,
1383 fm_grps_process, RADIO_HCI_TIMEOUT);
1384
1385 return ret;
1386}
1387
1388int hci_def_data_read(struct hci_fm_def_data_rd_req *arg,
1389 struct radio_hci_dev *hdev)
1390{
1391 int ret = 0;
1392 struct hci_fm_def_data_rd_req *def_data_rd = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393 ret = radio_hci_request(hdev, hci_def_data_read_req, (unsigned
1394 long)def_data_rd, RADIO_HCI_TIMEOUT);
1395
1396 return ret;
1397}
1398
1399int hci_def_data_write(struct hci_fm_def_data_wr_req *arg,
1400 struct radio_hci_dev *hdev)
1401{
1402 int ret = 0;
1403 struct hci_fm_def_data_wr_req *def_data_wr = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001404 ret = radio_hci_request(hdev, hci_def_data_write_req, (unsigned
1405 long)def_data_wr, RADIO_HCI_TIMEOUT);
1406
1407 return ret;
1408}
1409
1410int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev)
1411{
1412 int ret = 0;
1413 __u8 mode = *arg;
1414
1415 ret = radio_hci_request(hdev, hci_fm_do_calibration_req, mode,
1416 RADIO_HCI_TIMEOUT);
1417
1418 return ret;
1419}
1420
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301421static int hci_read_grp_counters(__u8 *arg, struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001422{
1423 int ret = 0;
1424 __u8 reset_counters = *arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001425 ret = radio_hci_request(hdev, hci_read_grp_counters_req,
1426 reset_counters, RADIO_HCI_TIMEOUT);
1427
1428 return ret;
1429}
1430
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301431static int hci_set_notch_filter(__u8 *arg, struct radio_hci_dev *hdev)
1432{
1433 int ret = 0;
1434 __u8 notch_filter = *arg;
1435 ret = radio_hci_request(hdev, hci_set_notch_filter_req,
1436 notch_filter, RADIO_HCI_TIMEOUT);
1437
1438 return ret;
1439}
1440
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001441static int hci_peek_data(struct hci_fm_riva_data *arg,
1442 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001443{
1444 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001445 struct hci_fm_riva_data *peek_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001446
1447 ret = radio_hci_request(hdev, hci_peek_data_req, (unsigned
1448 long)peek_data, RADIO_HCI_TIMEOUT);
1449
1450 return ret;
1451}
1452
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001453static int hci_poke_data(struct hci_fm_riva_poke *arg,
1454 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001455{
1456 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001457 struct hci_fm_riva_poke *poke_data = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458
1459 ret = radio_hci_request(hdev, hci_poke_data_req, (unsigned
1460 long)poke_data, RADIO_HCI_TIMEOUT);
1461
1462 return ret;
1463}
1464
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001465static int hci_ssbi_peek_reg(struct hci_fm_ssbi_peek *arg,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001466 struct radio_hci_dev *hdev)
1467{
1468 int ret = 0;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001469 struct hci_fm_ssbi_peek *ssbi_peek_reg = arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001470
1471 ret = radio_hci_request(hdev, hci_ssbi_peek_reg_req, (unsigned
1472 long)ssbi_peek_reg, RADIO_HCI_TIMEOUT);
1473
1474 return ret;
1475}
1476
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001477static int hci_ssbi_poke_reg(struct hci_fm_ssbi_req *arg,
1478 struct radio_hci_dev *hdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001479{
1480 int ret = 0;
1481 struct hci_fm_ssbi_req *ssbi_poke_reg = arg;
1482
1483 ret = radio_hci_request(hdev, hci_ssbi_poke_reg_req, (unsigned
1484 long)ssbi_poke_reg, RADIO_HCI_TIMEOUT);
1485
1486 return ret;
1487}
1488
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +05301489static int hci_set_ch_det_thresholds_req(struct hci_fm_ch_det_threshold *arg,
1490 struct radio_hci_dev *hdev)
1491{
1492 int ret = 0;
1493 struct hci_fm_ch_det_threshold *ch_det_threshold = arg;
1494 ret = radio_hci_request(hdev, hci_fm_set_ch_det_th,
1495 (unsigned long)ch_det_threshold, RADIO_HCI_TIMEOUT);
1496 return ret;
1497}
1498
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301499static int hci_fm_set_cal_req_proc(struct radio_hci_dev *hdev,
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301500 unsigned long param)
1501{
1502 u16 opcode = 0;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301503 struct hci_fm_set_cal_req_proc *cal_req =
1504 (struct hci_fm_set_cal_req_proc *)param;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301505
1506 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1507 HCI_OCF_FM_SET_CALIBRATION);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301508 return radio_hci_send_cmd(hdev, opcode, sizeof(*cal_req),
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301509 cal_req);
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05301510}
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301511
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301512static int hci_fm_do_cal_req(struct radio_hci_dev *hdev,
1513 unsigned long param)
1514{
1515 u16 opcode = 0;
1516 u8 cal_mode = param;
1517
1518 opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
1519 HCI_OCF_FM_DO_CALIBRATION);
1520 return radio_hci_send_cmd(hdev, opcode, sizeof(cal_mode),
1521 &cal_mode);
1522
1523}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001524static int hci_cmd(unsigned int cmd, struct radio_hci_dev *hdev)
1525{
1526 int ret = 0;
1527 unsigned long arg = 0;
1528
Ankur Nandwanid928d542011-08-11 13:15:41 -07001529 if (!hdev)
1530 return -ENODEV;
1531
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001532 switch (cmd) {
1533 case HCI_FM_ENABLE_RECV_CMD:
1534 ret = radio_hci_request(hdev, hci_fm_enable_recv_req, arg,
1535 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1536 break;
1537
1538 case HCI_FM_DISABLE_RECV_CMD:
1539 ret = radio_hci_request(hdev, hci_fm_disable_recv_req, arg,
1540 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1541 break;
1542
1543 case HCI_FM_GET_RECV_CONF_CMD:
1544 ret = radio_hci_request(hdev, hci_get_fm_recv_conf_req, arg,
1545 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1546 break;
1547
1548 case HCI_FM_GET_STATION_PARAM_CMD:
1549 ret = radio_hci_request(hdev,
1550 hci_fm_get_station_param_req, arg,
1551 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1552 break;
1553
1554 case HCI_FM_GET_SIGNAL_TH_CMD:
1555 ret = radio_hci_request(hdev,
1556 hci_fm_get_sig_threshold_req, arg,
1557 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1558 break;
1559
1560 case HCI_FM_GET_PROGRAM_SERVICE_CMD:
1561 ret = radio_hci_request(hdev,
1562 hci_fm_get_program_service_req, arg,
1563 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1564 break;
1565
1566 case HCI_FM_GET_RADIO_TEXT_CMD:
1567 ret = radio_hci_request(hdev, hci_fm_get_radio_text_req, arg,
1568 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1569 break;
1570
1571 case HCI_FM_GET_AF_LIST_CMD:
1572 ret = radio_hci_request(hdev, hci_fm_get_af_list_req, arg,
1573 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1574 break;
1575
1576 case HCI_FM_CANCEL_SEARCH_CMD:
1577 ret = radio_hci_request(hdev, hci_fm_cancel_search_req, arg,
1578 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1579 break;
1580
1581 case HCI_FM_RESET_CMD:
1582 ret = radio_hci_request(hdev, hci_fm_reset_req, arg,
1583 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1584 break;
1585
1586 case HCI_FM_GET_FEATURES_CMD:
1587 ret = radio_hci_request(hdev,
1588 hci_fm_get_feature_lists_req, arg,
1589 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1590 break;
1591
1592 case HCI_FM_STATION_DBG_PARAM_CMD:
1593 ret = radio_hci_request(hdev,
1594 hci_fm_get_station_dbg_param_req, arg,
1595 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1596 break;
1597
Ankur Nandwanid928d542011-08-11 13:15:41 -07001598 case HCI_FM_ENABLE_TRANS_CMD:
1599 ret = radio_hci_request(hdev, hci_fm_enable_trans_req, arg,
1600 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1601 break;
1602
1603 case HCI_FM_DISABLE_TRANS_CMD:
1604 ret = radio_hci_request(hdev, hci_fm_disable_trans_req, arg,
1605 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1606 break;
1607
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301608 case HCI_FM_GET_TX_CONFIG:
1609 ret = radio_hci_request(hdev, hci_get_fm_trans_conf_req, arg,
1610 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1611 break;
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +05301612 case HCI_FM_GET_DET_CH_TH_CMD:
1613 ret = radio_hci_request(hdev, hci_fm_get_ch_det_th, arg,
1614 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
1615 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001616 default:
1617 ret = -EINVAL;
1618 break;
1619 }
1620
1621 return ret;
1622}
1623
1624static void radio_hci_req_complete(struct radio_hci_dev *hdev, int result)
1625{
1626 hdev->req_result = result;
1627 hdev->req_status = HCI_REQ_DONE;
1628 wake_up_interruptible(&hdev->req_wait_q);
1629}
1630
1631static void radio_hci_status_complete(struct radio_hci_dev *hdev, int result)
1632{
1633 hdev->req_result = result;
1634 hdev->req_status = HCI_REQ_STATUS;
1635 wake_up_interruptible(&hdev->req_wait_q);
1636}
1637
1638static void hci_cc_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1639{
1640 __u8 status = *((__u8 *) skb->data);
1641
1642 if (status)
1643 return;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301644
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001645 radio_hci_req_complete(hdev, status);
1646}
1647
1648static void hci_cc_fm_disable_rsp(struct radio_hci_dev *hdev,
1649 struct sk_buff *skb)
1650{
1651 __u8 status = *((__u8 *) skb->data);
1652 struct iris_device *radio = video_get_drvdata(video_get_dev());
1653
Ayaz Ahmad53177572013-10-09 16:20:40 +05301654 if (radio == NULL) {
1655 FMDERR(":radio is null");
1656 return;
1657 }
1658
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05301659 if ((radio->mode == FM_TURNING_OFF) && (status == 0)) {
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05301660 iris_q_event(radio, IRIS_EVT_RADIO_DISABLED);
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05301661 radio_hci_req_complete(hdev, status);
1662 radio->mode = FM_OFF;
1663 } else if (radio->mode == FM_CALIB) {
1664 radio_hci_req_complete(hdev, status);
1665 } else if ((radio->mode == FM_RECV) || (radio->mode == FM_TRANS)) {
1666 iris_q_event(radio, IRIS_EVT_RADIO_DISABLED);
1667 radio->mode = FM_OFF;
1668 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001669}
1670
1671static void hci_cc_conf_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1672{
1673 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1674 struct iris_device *radio = video_get_drvdata(video_get_dev());
1675
Ayaz Ahmad53177572013-10-09 16:20:40 +05301676 if (radio == NULL) {
1677 FMDERR(":radio is null");
1678 return;
1679 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001680 if (rsp->status)
1681 return;
1682
1683 radio->recv_conf = rsp->recv_conf_rsp;
1684 radio_hci_req_complete(hdev, rsp->status);
1685}
1686
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301687static void hci_cc_fm_trans_get_conf_rsp(struct radio_hci_dev *hdev,
1688 struct sk_buff *skb)
1689{
1690 struct hci_fm_get_trans_conf_rsp *rsp = (void *)skb->data;
1691 struct iris_device *radio = video_get_drvdata(video_get_dev());
1692
Ayaz Ahmad53177572013-10-09 16:20:40 +05301693 if (radio == NULL) {
1694 FMDERR(":radio is null");
1695 return;
1696 }
1697
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05301698 if (rsp->status)
1699 return;
1700 memcpy((void *)&radio->trans_conf, (void*)&rsp->trans_conf_rsp,
1701 sizeof(rsp->trans_conf_rsp));
1702 radio_hci_req_complete(hdev, rsp->status);
1703}
1704
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001705static void hci_cc_fm_enable_rsp(struct radio_hci_dev *hdev,
1706 struct sk_buff *skb)
1707{
1708 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1709 struct iris_device *radio = video_get_drvdata(video_get_dev());
1710
Ayaz Ahmad53177572013-10-09 16:20:40 +05301711 if (radio == NULL) {
1712 FMDERR(":radio is null");
1713 return;
1714 }
1715
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05301716 if (rsp->status) {
1717 radio_hci_req_complete(hdev, rsp->status);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718 return;
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05301719 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05301721 if (radio->mode == FM_RECV_TURNING_ON) {
1722 radio->mode = FM_RECV;
1723 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1724 } else if (radio->mode == FM_TRANS_TURNING_ON) {
1725 radio->mode = FM_TRANS;
1726 iris_q_event(radio, IRIS_EVT_RADIO_READY);
1727 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001728 radio_hci_req_complete(hdev, rsp->status);
1729}
1730
Ankur Nandwanid928d542011-08-11 13:15:41 -07001731
1732static void hci_cc_fm_trans_set_conf_rsp(struct radio_hci_dev *hdev,
1733 struct sk_buff *skb)
1734{
1735 struct hci_fm_conf_rsp *rsp = (void *)skb->data;
1736 struct iris_device *radio = video_get_drvdata(video_get_dev());
1737
Ayaz Ahmad53177572013-10-09 16:20:40 +05301738 if (radio == NULL) {
1739 FMDERR(":radio is null");
1740 return;
1741 }
1742
Ankur Nandwanid928d542011-08-11 13:15:41 -07001743 if (rsp->status)
1744 return;
1745
1746 iris_q_event(radio, HCI_EV_CMD_COMPLETE);
1747
1748 radio_hci_req_complete(hdev, rsp->status);
1749}
1750
1751
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001752static void hci_cc_sig_threshold_rsp(struct radio_hci_dev *hdev,
1753 struct sk_buff *skb)
1754{
1755 struct hci_fm_sig_threshold_rsp *rsp = (void *)skb->data;
1756 struct iris_device *radio = video_get_drvdata(video_get_dev());
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001757
Ayaz Ahmad53177572013-10-09 16:20:40 +05301758 if (radio == NULL) {
1759 FMDERR(":radio is null");
1760 return;
1761 }
1762
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001763 if (rsp->status)
1764 return;
1765
Venkateshwarlu Domakonda3d1d6e42011-12-09 15:08:58 +05301766 memcpy(&radio->sig_th, rsp, sizeof(struct hci_fm_sig_threshold_rsp));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001767 radio_hci_req_complete(hdev, rsp->status);
1768}
1769
1770static void hci_cc_station_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1771{
1772 struct iris_device *radio = video_get_drvdata(video_get_dev());
1773 struct hci_fm_station_rsp *rsp = (void *)skb->data;
Ayaz Ahmad53177572013-10-09 16:20:40 +05301774
1775 if (radio == NULL) {
1776 FMDERR(":radio is null");
1777 return;
1778 }
1779
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001780 radio->fm_st_rsp = *(rsp);
1781
1782 /* Tune is always succesful */
1783 radio_hci_req_complete(hdev, 0);
1784}
1785
1786static void hci_cc_prg_srv_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1787{
1788 struct hci_fm_prgm_srv_rsp *rsp = (void *)skb->data;
1789
1790 if (rsp->status)
1791 return;
1792
1793 radio_hci_req_complete(hdev, rsp->status);
1794}
1795
1796static void hci_cc_rd_txt_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1797{
1798 struct hci_fm_radio_txt_rsp *rsp = (void *)skb->data;
1799
1800 if (rsp->status)
1801 return;
1802
1803 radio_hci_req_complete(hdev, rsp->status);
1804}
1805
1806static void hci_cc_af_list_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
1807{
1808 struct hci_fm_af_list_rsp *rsp = (void *)skb->data;
1809
1810 if (rsp->status)
1811 return;
1812
1813 radio_hci_req_complete(hdev, rsp->status);
1814}
1815
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001816static void hci_cc_feature_list_rsp(struct radio_hci_dev *hdev,
1817 struct sk_buff *skb)
1818{
Ayaz Ahmad53177572013-10-09 16:20:40 +05301819 struct v4l2_capability *v4l_cap;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001820 struct hci_fm_feature_list_rsp *rsp = (void *)skb->data;
1821 struct iris_device *radio = video_get_drvdata(video_get_dev());
Ayaz Ahmad53177572013-10-09 16:20:40 +05301822
1823 if (radio == NULL) {
1824 FMDERR(":radio is null");
1825 return;
1826 }
1827
1828 v4l_cap = radio->g_cap;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001829
1830 if (rsp->status)
1831 return;
1832 v4l_cap->capabilities = (rsp->feature_mask & 0x000002) |
1833 (rsp->feature_mask & 0x000001);
1834
1835 radio_hci_req_complete(hdev, rsp->status);
1836}
1837
1838static void hci_cc_dbg_param_rsp(struct radio_hci_dev *hdev,
1839 struct sk_buff *skb)
1840{
1841 struct iris_device *radio = video_get_drvdata(video_get_dev());
1842 struct hci_fm_dbg_param_rsp *rsp = (void *)skb->data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001843
Ayaz Ahmad53177572013-10-09 16:20:40 +05301844 if (radio == NULL) {
1845 FMDERR(":radio is null");
1846 return;
1847 }
1848
1849 radio->st_dbg_param = *(rsp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001850 if (radio->st_dbg_param.status)
1851 return;
1852
1853 radio_hci_req_complete(hdev, radio->st_dbg_param.status);
1854}
1855
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001856static void iris_q_evt_data(struct iris_device *radio,
1857 char *data, int len, int event)
1858{
Ayaz Ahmad53177572013-10-09 16:20:40 +05301859 struct kfifo *data_b;
1860
1861 if (radio == NULL) {
1862 FMDERR(":radio is null");
1863 return;
1864 }
1865 data_b = &radio->data_buf[event];
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001866 if (kfifo_in_locked(data_b, data, len, &radio->buf_lock[event]))
1867 wake_up_interruptible(&radio->event_queue);
1868}
1869
1870static void hci_cc_riva_peek_rsp(struct radio_hci_dev *hdev,
1871 struct sk_buff *skb)
1872{
1873 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301874 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001875 int len;
1876 char *data;
1877
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301878 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001879 return;
1880 len = skb->data[RIVA_PEEK_LEN_OFSET] + RIVA_PEEK_PARAM;
1881 data = kmalloc(len, GFP_ATOMIC);
1882
1883 if (!data) {
1884 FMDERR("Memory allocation failed");
1885 return;
1886 }
1887
1888 memcpy(data, &skb->data[PEEK_DATA_OFSET], len);
1889 iris_q_evt_data(radio, data, len, IRIS_BUF_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301890 radio_hci_req_complete(hdev, status);
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05301891 kfree(data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001892
1893}
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301894
1895static void hci_cc_riva_read_default_rsp(struct radio_hci_dev *hdev,
1896 struct sk_buff *skb)
1897{
1898 struct iris_device *radio = video_get_drvdata(video_get_dev());
1899 __u8 status = *((__u8 *) skb->data);
1900 __u8 len;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301901
Ayaz Ahmad53177572013-10-09 16:20:40 +05301902 if (radio == NULL) {
1903 FMDERR(":radio is null");
1904 return;
1905 }
1906
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301907 if (status)
1908 return;
1909 len = skb->data[1];
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301910
Venkateshwarlu Domakonda71731d52012-04-04 12:30:51 +05301911 memset(&radio->default_data, 0 , sizeof(struct hci_fm_data_rd_rsp));
1912 memcpy(&radio->default_data, &skb->data[0], len+2);
1913 iris_q_evt_data(radio, &skb->data[0], len+2, IRIS_BUF_RD_DEFAULT);
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301914 radio_hci_req_complete(hdev, status);
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05301915}
1916
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001917static void hci_cc_ssbi_peek_rsp(struct radio_hci_dev *hdev,
1918 struct sk_buff *skb)
1919{
1920 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301921 __u8 status = *((__u8 *) skb->data);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001922 char *data;
1923
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301924 if (status)
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001925 return;
1926 data = kmalloc(SSBI_PEEK_LEN, GFP_ATOMIC);
1927 if (!data) {
1928 FMDERR("Memory allocation failed");
1929 return;
1930 }
1931
1932 data[0] = skb->data[PEEK_DATA_OFSET];
1933 iris_q_evt_data(radio, data, SSBI_PEEK_LEN, IRIS_BUF_SSBI_PEEK);
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301934 radio_hci_req_complete(hdev, status);
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07001935 kfree(data);
1936}
1937
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05301938static void hci_cc_rds_grp_cntrs_rsp(struct radio_hci_dev *hdev,
1939 struct sk_buff *skb)
1940{
1941 struct iris_device *radio = video_get_drvdata(video_get_dev());
1942 __u8 status = *((__u8 *) skb->data);
1943 char *data;
1944 if (status)
1945 return;
1946 data = kmalloc(RDS_GRP_CNTR_LEN, GFP_ATOMIC);
1947 if (!data) {
1948 FMDERR("memory allocation failed");
1949 return;
1950 }
1951 memcpy(data, &skb->data[1], RDS_GRP_CNTR_LEN);
1952 iris_q_evt_data(radio, data, RDS_GRP_CNTR_LEN, IRIS_BUF_RDS_CNTRS);
1953 radio_hci_req_complete(hdev, status);
1954 kfree(data);
1955
1956}
1957
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301958static void hci_cc_do_calibration_rsp(struct radio_hci_dev *hdev,
1959 struct sk_buff *skb)
1960{
1961 struct iris_device *radio = video_get_drvdata(video_get_dev());
1962 static struct hci_cc_do_calibration_rsp rsp ;
1963 rsp.status = skb->data[0];
1964 rsp.mode = skb->data[CALIB_MODE_OFSET];
1965
1966 if (rsp.status) {
1967 FMDERR("status = %d", rsp.status);
1968 return;
1969 }
1970 if (rsp.mode == PROCS_CALIB_MODE) {
1971 memcpy(&rsp.data[0], &skb->data[CALIB_DATA_OFSET],
1972 PROCS_CALIB_SIZE);
Venkateshwarlu Domakonda5e96e692011-12-05 17:36:06 +05301973 iris_q_evt_data(radio, rsp.data, PROCS_CALIB_SIZE,
1974 IRIS_BUF_CAL_DATA);
1975 } else {
1976 return;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301977 }
Venkateshwarlu Domakonda5e96e692011-12-05 17:36:06 +05301978
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05301979 radio_hci_req_complete(hdev, rsp.status);
1980}
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +05301981
1982static void hci_cc_get_ch_det_threshold_rsp(struct radio_hci_dev *hdev,
1983 struct sk_buff *skb)
1984{
1985 struct iris_device *radio = video_get_drvdata(video_get_dev());
1986 u8 status = skb->data[0];
Ayaz Ahmad53177572013-10-09 16:20:40 +05301987
1988 if (radio == NULL) {
1989 FMDERR(":radio is null");
1990 return;
1991 }
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +05301992 if (status) {
1993 FMDERR("status = %d", status);
1994 return;
1995 }
1996 memcpy(&radio->ch_det_threshold, &skb->data[1],
1997 sizeof(struct hci_fm_ch_det_threshold));
1998 radio_hci_req_complete(hdev, status);
1999}
2000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002001static inline void hci_cmd_complete_event(struct radio_hci_dev *hdev,
2002 struct sk_buff *skb)
2003{
2004 struct hci_ev_cmd_complete *cmd_compl_ev = (void *) skb->data;
2005 __u16 opcode;
2006
2007 skb_pull(skb, sizeof(*cmd_compl_ev));
2008
2009 opcode = __le16_to_cpu(cmd_compl_ev->cmd_opcode);
2010
2011 switch (opcode) {
2012 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_RECV_REQ):
Ayaz Ahmad3dad6512012-03-13 13:41:19 +05302013 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_TRANS_REQ):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002014 hci_cc_fm_enable_rsp(hdev, skb);
2015 break;
2016 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RECV_CONF_REQ):
2017 hci_cc_conf_rsp(hdev, skb);
2018 break;
2019
2020 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_RECV_REQ):
Ayaz Ahmad3dad6512012-03-13 13:41:19 +05302021 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_TRANS_REQ):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002022 hci_cc_fm_disable_rsp(hdev, skb);
2023 break;
2024
2025 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_RECV_CONF_REQ):
2026 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_MUTE_MODE_REQ):
2027 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_STEREO_MODE_REQ):
2028 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_ANTENNA):
2029 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_SIGNAL_THRESHOLD):
2030 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_CANCEL_SEARCH):
2031 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP):
2032 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP_PROCESS):
2033 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_WAN_AVD_CTRL):
2034 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_NOTCH_CTRL):
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +05302035 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_CH_DET_THRESHOLD):
Ankur Nandwanid928d542011-08-11 13:15:41 -07002036 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_RT_REQ):
2037 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_PS_REQ):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002038 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_WRITE):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302039 hci_cc_rsp(hdev, skb);
2040 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002041 case hci_common_cmd_op_pack(HCI_OCF_FM_RESET):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002042 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_POKE_REG):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002043 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_POKE_DATA):
Ankur Nandwanid928d542011-08-11 13:15:41 -07002044 case hci_diagnostic_cmd_op_pack(HCI_FM_SET_INTERNAL_TONE_GENRATOR):
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302045 case hci_common_cmd_op_pack(HCI_OCF_FM_SET_CALIBRATION):
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302046 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_EVENT_MASK):
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002047 hci_cc_rsp(hdev, skb);
2048 break;
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302049
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002050 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_PEEK_REG):
2051 hci_cc_ssbi_peek_rsp(hdev, skb);
2052 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002053 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_SIGNAL_THRESHOLD):
2054 hci_cc_sig_threshold_rsp(hdev, skb);
2055 break;
2056
2057 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_STATION_PARAM_REQ):
2058 hci_cc_station_rsp(hdev, skb);
2059 break;
2060
2061 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ):
2062 hci_cc_prg_srv_rsp(hdev, skb);
2063 break;
2064
2065 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RADIO_TEXT_REQ):
2066 hci_cc_rd_txt_rsp(hdev, skb);
2067 break;
2068
2069 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_AF_LIST_REQ):
2070 hci_cc_af_list_rsp(hdev, skb);
2071 break;
2072
2073 case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_READ):
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05302074 hci_cc_riva_read_default_rsp(hdev, skb);
2075 break;
2076
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002077 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_PEEK_DATA):
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002078 hci_cc_riva_peek_rsp(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002079 break;
2080
2081 case hci_common_cmd_op_pack(HCI_OCF_FM_GET_FEATURE_LIST):
2082 hci_cc_feature_list_rsp(hdev, skb);
2083 break;
2084
2085 case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_STATION_DBG_PARAM):
2086 hci_cc_dbg_param_rsp(hdev, skb);
2087 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002088 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_SET_TRANS_CONF_REQ):
2089 hci_cc_fm_trans_set_conf_rsp(hdev, skb);
2090 break;
2091
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302092 case hci_status_param_op_pack(HCI_OCF_FM_READ_GRP_COUNTERS):
2093 hci_cc_rds_grp_cntrs_rsp(hdev, skb);
2094 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302095 case hci_common_cmd_op_pack(HCI_OCF_FM_DO_CALIBRATION):
2096 hci_cc_do_calibration_rsp(hdev, skb);
2097 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05302098
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05302099 case hci_trans_ctrl_cmd_op_pack(HCI_OCF_FM_GET_TRANS_CONF_REQ):
2100 hci_cc_fm_trans_get_conf_rsp(hdev, skb);
2101 break;
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +05302102 case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_CH_DET_THRESHOLD):
2103 hci_cc_get_ch_det_threshold_rsp(hdev, skb);
2104 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002105 default:
2106 FMDERR("%s opcode 0x%x", hdev->name, opcode);
2107 break;
2108 }
2109
2110}
2111
2112static inline void hci_cmd_status_event(struct radio_hci_dev *hdev,
2113 struct sk_buff *skb)
2114{
2115 struct hci_ev_cmd_status *ev = (void *) skb->data;
2116 radio_hci_status_complete(hdev, ev->status);
2117}
2118
2119static inline void hci_ev_tune_status(struct radio_hci_dev *hdev,
2120 struct sk_buff *skb)
2121{
2122 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002123 struct iris_device *radio = video_get_drvdata(video_get_dev());
2124
Ayaz Ahmad53177572013-10-09 16:20:40 +05302125 if (radio == NULL) {
2126 FMDERR(":radio is null");
2127 return;
2128 }
Venkateshwarlu Domakonda862492d2011-11-29 11:51:24 +05302129 memcpy(&radio->fm_st_rsp.station_rsp, &skb->data[0],
2130 sizeof(struct hci_ev_tune_status));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002131 iris_q_event(radio, IRIS_EVT_TUNE_SUCC);
2132
2133 for (i = 0; i < IRIS_BUF_MAX; i++) {
2134 if (i >= IRIS_BUF_RT_RDS)
2135 kfifo_reset(&radio->data_buf[i]);
2136 }
Srinivasa Rao Uppalaacdebcc2011-12-23 14:31:38 +05302137 if (radio->fm_st_rsp.station_rsp.serv_avble)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002138 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
2139 else
2140 iris_q_event(radio, IRIS_EVT_BELOW_TH);
2141
2142 if (radio->fm_st_rsp.station_rsp.stereo_prg)
2143 iris_q_event(radio, IRIS_EVT_STEREO);
Ayaz Ahmada4b0d8e2013-09-02 15:18:23 +05302144 else if (radio->fm_st_rsp.station_rsp.stereo_prg == 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002145 iris_q_event(radio, IRIS_EVT_MONO);
2146
2147 if (radio->fm_st_rsp.station_rsp.rds_sync_status)
2148 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
2149 else
2150 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
2151}
2152
2153static inline void hci_ev_search_compl(struct radio_hci_dev *hdev,
2154 struct sk_buff *skb)
2155{
2156 struct iris_device *radio = video_get_drvdata(video_get_dev());
2157 iris_q_event(radio, IRIS_EVT_SEEK_COMPLETE);
2158}
2159
2160static inline void hci_ev_srch_st_list_compl(struct radio_hci_dev *hdev,
2161 struct sk_buff *skb)
2162{
2163 struct iris_device *radio = video_get_drvdata(video_get_dev());
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002164 struct hci_ev_srch_list_compl *ev ;
2165 int cnt;
2166 int stn_num;
2167 int rel_freq;
2168 int abs_freq;
2169 int len;
2170
Ayaz Ahmad53177572013-10-09 16:20:40 +05302171 if (radio == NULL) {
2172 FMDERR(":radio is null");
2173 return;
2174 }
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002175 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
2176 if (!ev) {
2177 FMDERR("Memory allocation failed");
2178 return ;
2179 }
2180
2181 ev->num_stations_found = skb->data[STN_NUM_OFFSET];
2182 len = ev->num_stations_found * PARAMS_PER_STATION + STN_FREQ_OFFSET;
2183
2184 for (cnt = STN_FREQ_OFFSET, stn_num = 0;
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05302185 (cnt < len) && (stn_num < ev->num_stations_found)
2186 && (stn_num < ARRAY_SIZE(ev->rel_freq));
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002187 cnt += PARAMS_PER_STATION, stn_num++) {
2188 abs_freq = *((int *)&skb->data[cnt]);
2189 rel_freq = abs_freq - radio->recv_conf.band_low_limit;
2190 rel_freq = (rel_freq * 20) / KHZ_TO_MHZ;
2191
2192 ev->rel_freq[stn_num].rel_freq_lsb = GET_LSB(rel_freq);
2193 ev->rel_freq[stn_num].rel_freq_msb = GET_MSB(rel_freq);
2194 }
2195
2196 len = ev->num_stations_found * 2 + sizeof(ev->num_stations_found);
2197 iris_q_event(radio, IRIS_EVT_NEW_SRCH_LIST);
2198 iris_q_evt_data(radio, (char *)ev, len, IRIS_BUF_SRCH_LIST);
2199 kfree(ev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002200}
2201
2202static inline void hci_ev_search_next(struct radio_hci_dev *hdev,
2203 struct sk_buff *skb)
2204{
2205 struct iris_device *radio = video_get_drvdata(video_get_dev());
2206 iris_q_event(radio, IRIS_EVT_SCAN_NEXT);
2207}
2208
2209static inline void hci_ev_stereo_status(struct radio_hci_dev *hdev,
2210 struct sk_buff *skb)
2211{
2212 struct iris_device *radio = video_get_drvdata(video_get_dev());
2213 __u8 st_status = *((__u8 *) skb->data);
2214 if (st_status)
2215 iris_q_event(radio, IRIS_EVT_STEREO);
2216 else
2217 iris_q_event(radio, IRIS_EVT_MONO);
2218}
2219
Ayaz Ahmad89265112012-10-05 19:39:11 +05302220static void hci_ev_raw_rds_group_data(struct radio_hci_dev *hdev,
2221 struct sk_buff *skb)
2222{
2223 struct iris_device *radio;
2224 unsigned char blocknum, index;
2225 struct rds_grp_data temp;
2226 unsigned int mask_bit;
2227 unsigned short int aid, agt, gtc;
2228 unsigned short int carrier;
2229
2230 radio = video_get_drvdata(video_get_dev());
2231 index = RDSGRP_DATA_OFFSET;
2232
Ayaz Ahmad53177572013-10-09 16:20:40 +05302233 if (radio == NULL) {
2234 FMDERR(":radio is null");
2235 return;
2236 }
Ayaz Ahmad89265112012-10-05 19:39:11 +05302237 for (blocknum = 0; blocknum < RDS_BLOCKS_NUM; blocknum++) {
2238 temp.rdsBlk[blocknum].rdsLsb =
2239 (skb->data[index]);
2240 temp.rdsBlk[blocknum].rdsMsb =
2241 (skb->data[index+1]);
2242 index = index + 2;
2243 }
2244
2245 aid = AID(temp.rdsBlk[3].rdsLsb, temp.rdsBlk[3].rdsMsb);
2246 gtc = GTC(temp.rdsBlk[1].rdsMsb);
2247 agt = AGT(temp.rdsBlk[1].rdsLsb);
2248
2249 if (gtc == GRP_3A) {
2250 switch (aid) {
2251 case ERT_AID:
2252 /* calculate the grp mask for RDS grp
2253 * which will contain actual eRT text
2254 *
2255 * Bit Pos 0 1 2 3 4 5 6 7
2256 * Grp Type 0A 0B 1A 1B 2A 2B 3A 3B
2257 *
2258 * similary for rest grps
2259 */
2260 mask_bit = (((agt >> 1) << 1) + (agt & 1));
2261 oda_agt = (1 << mask_bit);
2262 utf_8_flag = (temp.rdsBlk[2].rdsLsb & 1);
2263 formatting_dir = EXTRACT_BIT(temp.rdsBlk[2].rdsLsb,
2264 ERT_FORMAT_DIR_BIT);
2265 if (ert_carrier != agt)
2266 iris_q_event(radio, IRIS_EVT_NEW_ODA);
2267 ert_carrier = agt;
2268 break;
2269 case RT_PLUS_AID:
2270 /* calculate the grp mask for RDS grp
2271 * which will contain actual eRT text
2272 *
2273 * Bit Pos 0 1 2 3 4 5 6 7
2274 * Grp Type 0A 0B 1A 1B 2A 2B 3A 3B
2275 *
2276 * similary for rest grps
2277 */
2278 mask_bit = (((agt >> 1) << 1) + (agt & 1));
2279 oda_agt = (1 << mask_bit);
2280 /*Extract 5th bit of MSB (b7b6b5b4b3b2b1b0)*/
2281 rt_ert_flag = EXTRACT_BIT(temp.rdsBlk[2].rdsMsb,
2282 RT_ERT_FLAG_BIT);
2283 if (rt_plus_carrier != agt)
2284 iris_q_event(radio, IRIS_EVT_NEW_ODA);
2285 rt_plus_carrier = agt;
2286 break;
2287 default:
2288 oda_agt = 0;
2289 break;
2290 }
2291 } else {
2292 carrier = gtc;
2293 if ((carrier == rt_plus_carrier))
2294 hci_ev_rt_plus(radio, temp);
2295 else if (carrier == ert_carrier)
2296 hci_buff_ert(radio, &temp);
2297 }
2298}
2299
2300static void hci_buff_ert(struct iris_device *radio,
2301 struct rds_grp_data *rds_buf)
2302{
2303 int i;
2304 unsigned short int info_byte = 0;
2305 unsigned short int byte_pair_index;
2306
2307 byte_pair_index = AGT(rds_buf->rdsBlk[1].rdsLsb);
2308 if (byte_pair_index == 0) {
2309 c_byt_pair_index = 0;
2310 ert_len = 0;
2311 }
2312 if (c_byt_pair_index == byte_pair_index) {
2313 c_byt_pair_index++;
2314 for (i = 2; i <= 3; i++) {
2315 info_byte = rds_buf->rdsBlk[i].rdsLsb;
2316 info_byte |= (rds_buf->rdsBlk[i].rdsMsb << 8);
2317 ert_buf[ert_len++] = rds_buf->rdsBlk[i].rdsMsb;
2318 ert_buf[ert_len++] = rds_buf->rdsBlk[i].rdsLsb;
2319 if ((utf_8_flag == 0)
2320 && (info_byte == CARRIAGE_RETURN)) {
2321 ert_len -= 2;
2322 break;
2323 } else if ((utf_8_flag == 1)
2324 &&
2325 (rds_buf->rdsBlk[i].rdsMsb
2326 == CARRIAGE_RETURN)) {
2327 info_byte = CARRIAGE_RETURN;
2328 ert_len -= 2;
2329 break;
2330 } else if ((utf_8_flag == 1)
2331 &&
2332 (rds_buf->rdsBlk[i].rdsLsb
2333 == CARRIAGE_RETURN)) {
2334 info_byte = CARRIAGE_RETURN;
2335 ert_len--;
2336 break;
2337 }
2338 }
2339 if ((byte_pair_index == MAX_ERT_SEGMENT) ||
2340 (info_byte == CARRIAGE_RETURN)) {
2341 hci_ev_ert(radio);
2342 c_byt_pair_index = 0;
2343 ert_len = 0;
2344 }
2345 } else {
2346 ert_len = 0;
2347 c_byt_pair_index = 0;
2348 }
2349}
2350static void hci_ev_ert(struct iris_device *radio)
2351
2352{
2353 char *data = NULL;
2354
2355 if (ert_len <= 0)
2356 return;
2357 data = kmalloc((ert_len + 3), GFP_ATOMIC);
2358 if (data != NULL) {
2359 data[0] = ert_len;
2360 data[1] = utf_8_flag;
2361 data[2] = formatting_dir;
2362 memcpy((data + 3), ert_buf, ert_len);
2363 iris_q_evt_data(radio, data, (ert_len + 3), IRIS_BUF_ERT);
2364 iris_q_event(radio, IRIS_EVT_NEW_ERT);
2365 kfree(data);
2366 }
2367}
2368
2369static void hci_ev_rt_plus(struct iris_device *radio,
2370 struct rds_grp_data rds_buf)
2371{
2372 char tag_type1, tag_type2;
2373 char *data = NULL;
2374 int len = 0;
2375 unsigned short int agt;
2376
2377 agt = AGT(rds_buf.rdsBlk[1].rdsLsb);
2378 /*right most 3 bits of Lsb of block 2
2379 * and left most 3 bits of Msb of block 3
2380 */
2381 tag_type1 = (((agt & TAG1_MSB_MASK) << TAG1_MSB_OFFSET) |
2382 (rds_buf.rdsBlk[2].rdsMsb >> TAG1_LSB_OFFSET));
2383
2384 /*right most 1 bit of lsb of 3rd block
2385 * and left most 5 bits of Msb of 4th block
2386 */
2387 tag_type2 = (((rds_buf.rdsBlk[2].rdsLsb & TAG2_MSB_MASK)
2388 << TAG2_MSB_OFFSET) |
2389 (rds_buf.rdsBlk[3].rdsMsb >> TAG2_LSB_OFFSET));
2390
2391 if (tag_type1 != DUMMY_CLASS)
2392 len += RT_PLUS_LEN_1_TAG;
2393 if (tag_type2 != DUMMY_CLASS)
2394 len += RT_PLUS_LEN_1_TAG;
2395
2396 if (len != 0) {
2397 len += 2;
2398 data = kmalloc(len, GFP_ATOMIC);
2399 } else {
2400 FMDERR("Len is zero\n");
2401 return ;
2402 }
2403 if (data != NULL) {
2404 data[0] = len;
2405 len = 1;
2406 data[len++] = rt_ert_flag;
2407 if (tag_type1 != DUMMY_CLASS) {
2408 data[len++] = tag_type1;
2409 /*start position of tag1
2410 *right most 5 bits of msb of 3rd block
2411 *and left most bit of lsb of 3rd block
2412 */
2413 data[len++] = (((rds_buf.rdsBlk[2].rdsMsb &
2414 TAG1_POS_MSB_MASK)
2415 << TAG1_POS_MSB_OFFSET)
2416 |
2417 (rds_buf.rdsBlk[2].rdsLsb >>
2418 TAG1_POS_LSB_OFFSET));
2419 /*length of tag1
2420 *left most 6 bits of lsb of 3rd block
2421 */
2422 data[len++] = ((rds_buf.rdsBlk[2].rdsLsb
2423 >> TAG1_LEN_OFFSET)
2424 &
2425 TAG1_LEN_MASK) + 1;
2426 }
2427 if (tag_type2 != DUMMY_CLASS) {
2428 data[len++] = tag_type2;
2429 /*start position of tag2
2430 *right most 3 bit of msb of 4th block
2431 *and left most 3 bits of lsb of 4th block
2432 */
2433 data[len++] = (((rds_buf.rdsBlk[3].rdsMsb
2434 & TAG2_POS_MSB_MASK)
2435 << TAG2_POS_MSB_OFFSET)
2436 |
2437 (rds_buf.rdsBlk[3].rdsLsb
2438 >> TAG2_POS_LSB_OFFSET));
2439 /*length of tag2
2440 *right most 5 bits of lsb of 4th block
2441 */
2442 data[len++] = (rds_buf.rdsBlk[3].rdsLsb
2443 & TAG2_LEN_MASK) + 1;
2444 }
2445 iris_q_evt_data(radio, data, len, IRIS_BUF_RT_PLUS);
2446 iris_q_event(radio, IRIS_EVT_NEW_RT_PLUS);
2447 kfree(data);
2448 } else {
2449 FMDERR("memory allocation failed\n");
2450 }
2451}
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002452
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002453static inline void hci_ev_program_service(struct radio_hci_dev *hdev,
2454 struct sk_buff *skb)
2455{
2456 struct iris_device *radio = video_get_drvdata(video_get_dev());
2457 int len;
2458 char *data;
2459
2460 len = (skb->data[RDS_PS_LENGTH_OFFSET] * RDS_STRING) + RDS_OFFSET;
2461 iris_q_event(radio, IRIS_EVT_NEW_PS_RDS);
2462 data = kmalloc(len, GFP_ATOMIC);
2463 if (!data) {
2464 FMDERR("Failed to allocate memory");
2465 return;
2466 }
2467
2468 data[0] = skb->data[RDS_PS_LENGTH_OFFSET];
2469 data[1] = skb->data[RDS_PTYPE];
2470 data[2] = skb->data[RDS_PID_LOWER];
2471 data[3] = skb->data[RDS_PID_HIGHER];
2472 data[4] = 0;
2473
2474 memcpy(data+RDS_OFFSET, &skb->data[RDS_PS_DATA_OFFSET], len-RDS_OFFSET);
2475
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002476 iris_q_evt_data(radio, data, len, IRIS_BUF_PS_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002477
2478 kfree(data);
2479}
2480
2481
2482static inline void hci_ev_radio_text(struct radio_hci_dev *hdev,
2483 struct sk_buff *skb)
2484{
2485 struct iris_device *radio = video_get_drvdata(video_get_dev());
2486 int len = 0;
2487 char *data;
2488
2489 iris_q_event(radio, IRIS_EVT_NEW_RT_RDS);
2490
Ayaz Ahmade4a0c172013-06-27 17:32:30 +05302491 while ((skb->data[len+RDS_OFFSET] != 0x0d) && (len < MAX_RT_LENGTH))
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002492 len++;
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002493 data = kmalloc(len+RDS_OFFSET, GFP_ATOMIC);
2494 if (!data) {
2495 FMDERR("Failed to allocate memory");
2496 return;
2497 }
2498
2499 data[0] = len;
2500 data[1] = skb->data[RDS_PTYPE];
2501 data[2] = skb->data[RDS_PID_LOWER];
2502 data[3] = skb->data[RDS_PID_HIGHER];
Ayaz Ahmade4a0c172013-06-27 17:32:30 +05302503 data[4] = skb->data[RT_A_B_FLAG_OFFSET];
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002504
2505 memcpy(data+RDS_OFFSET, &skb->data[RDS_OFFSET], len);
2506 data[len+RDS_OFFSET] = 0x00;
2507
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002508 iris_q_evt_data(radio, data, len+RDS_OFFSET, IRIS_BUF_RT_RDS);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002509
2510 kfree(data);
2511}
2512
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302513static void hci_ev_af_list(struct radio_hci_dev *hdev,
2514 struct sk_buff *skb)
2515{
2516 struct iris_device *radio = video_get_drvdata(video_get_dev());
2517 struct hci_ev_af_list ev;
2518
2519 ev.tune_freq = *((int *) &skb->data[0]);
2520 ev.pi_code = *((__le16 *) &skb->data[PI_CODE_OFFSET]);
2521 ev.af_size = skb->data[AF_SIZE_OFFSET];
Venkateshwarlu Domakondae8a4187c2013-06-25 18:56:54 +05302522 if (ev.af_size > AF_LIST_MAX) {
2523 FMDERR("AF list size received more than available size");
2524 return;
2525 }
Venkateshwarlu Domakondacc705e32013-07-15 18:08:06 +05302526 memcpy(&ev.af_list[0], &skb->data[AF_LIST_OFFSET],
2527 ev.af_size * sizeof(int));
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302528 iris_q_event(radio, IRIS_EVT_NEW_AF_LIST);
Venkateshwarlu Domakondacc705e32013-07-15 18:08:06 +05302529 iris_q_evt_data(radio, (char *)&ev, (7 + ev.af_size * sizeof(int)),
2530 IRIS_BUF_AF_LIST);
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302531}
2532
2533static void hci_ev_rds_lock_status(struct radio_hci_dev *hdev,
2534 struct sk_buff *skb)
2535{
2536 struct iris_device *radio = video_get_drvdata(video_get_dev());
2537 __u8 rds_status = skb->data[0];
2538
2539 if (rds_status)
2540 iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
2541 else
2542 iris_q_event(radio, IRIS_EVT_RDS_NOT_AVAIL);
2543}
2544
2545static void hci_ev_service_available(struct radio_hci_dev *hdev,
2546 struct sk_buff *skb)
2547{
2548 struct iris_device *radio = video_get_drvdata(video_get_dev());
Venkateshwarlu Domakondad6140eb2012-01-17 16:23:52 +05302549 u8 serv_avble = skb->data[0];
2550 if (serv_avble)
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302551 iris_q_event(radio, IRIS_EVT_ABOVE_TH);
2552 else
2553 iris_q_event(radio, IRIS_EVT_BELOW_TH);
2554}
2555
2556static void hci_ev_rds_grp_complete(struct radio_hci_dev *hdev,
2557 struct sk_buff *skb)
2558{
2559 struct iris_device *radio = video_get_drvdata(video_get_dev());
2560 iris_q_event(radio, IRIS_EVT_TXRDSDONE);
2561}
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002562
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002563void radio_hci_event_packet(struct radio_hci_dev *hdev, struct sk_buff *skb)
2564{
Priyanka Vunnambab6b7e2011-11-01 15:41:54 +05302565 struct radio_hci_event_hdr *hdr;
2566 u8 event;
2567
2568 if (skb == NULL) {
2569 FMDERR("Socket buffer is NULL");
2570 return;
2571 }
2572
2573 hdr = (void *) skb->data;
2574 event = hdr->evt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002575
2576 skb_pull(skb, RADIO_HCI_EVENT_HDR_SIZE);
2577
2578 switch (event) {
2579 case HCI_EV_TUNE_STATUS:
2580 hci_ev_tune_status(hdev, skb);
2581 break;
2582 case HCI_EV_SEARCH_PROGRESS:
2583 case HCI_EV_SEARCH_RDS_PROGRESS:
2584 case HCI_EV_SEARCH_LIST_PROGRESS:
2585 hci_ev_search_next(hdev, skb);
2586 break;
2587 case HCI_EV_STEREO_STATUS:
2588 hci_ev_stereo_status(hdev, skb);
2589 break;
2590 case HCI_EV_RDS_LOCK_STATUS:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302591 hci_ev_rds_lock_status(hdev, skb);
2592 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002593 case HCI_EV_SERVICE_AVAILABLE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302594 hci_ev_service_available(hdev, skb);
2595 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002596 case HCI_EV_RDS_RX_DATA:
Ayaz Ahmad89265112012-10-05 19:39:11 +05302597 hci_ev_raw_rds_group_data(hdev, skb);
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002598 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002599 case HCI_EV_PROGRAM_SERVICE:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002600 hci_ev_program_service(hdev, skb);
2601 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002602 case HCI_EV_RADIO_TEXT:
Ankur Nandwani78a782b2011-07-07 21:11:21 -07002603 hci_ev_radio_text(hdev, skb);
2604 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002605 case HCI_EV_FM_AF_LIST:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302606 hci_ev_af_list(hdev, skb);
2607 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002608 case HCI_EV_TX_RDS_GRP_COMPL:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302609 hci_ev_rds_grp_complete(hdev, skb);
2610 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002611 case HCI_EV_TX_RDS_CONT_GRP_COMPL:
2612 break;
2613
2614 case HCI_EV_CMD_COMPLETE:
2615 hci_cmd_complete_event(hdev, skb);
2616 break;
2617
2618 case HCI_EV_CMD_STATUS:
2619 hci_cmd_status_event(hdev, skb);
2620 break;
2621
2622 case HCI_EV_SEARCH_COMPLETE:
2623 case HCI_EV_SEARCH_RDS_COMPLETE:
2624 hci_ev_search_compl(hdev, skb);
2625 break;
2626
2627 case HCI_EV_SEARCH_LIST_COMPLETE:
Srinivasa Rao Uppala18fb80e2011-07-17 17:33:00 -07002628 hci_ev_srch_st_list_compl(hdev, skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002629 break;
2630
2631 default:
2632 break;
2633 }
2634}
2635
2636/*
2637 * fops/IOCTL helper functions
2638 */
2639
2640static int iris_search(struct iris_device *radio, int on, int dir)
2641{
2642 int retval = 0;
Ayaz Ahmad53177572013-10-09 16:20:40 +05302643 enum search_t srch;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002644
Ayaz Ahmad53177572013-10-09 16:20:40 +05302645 if (radio == NULL) {
2646 FMDERR(":radio is null");
2647 return -EINVAL;
2648 }
2649
2650 srch = radio->g_search_mode & SRCH_MODE;
2651 radio->search_on = on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002652 if (on) {
2653 switch (srch) {
2654 case SCAN_FOR_STRONG:
2655 case SCAN_FOR_WEAK:
2656 radio->srch_st_list.srch_list_dir = dir;
2657 radio->srch_st_list.srch_list_mode = srch;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002658 retval = hci_fm_search_station_list(
2659 &radio->srch_st_list, radio->fm_hdev);
2660 break;
2661 case RDS_SEEK_PTY:
2662 case RDS_SCAN_PTY:
2663 case RDS_SEEK_PI:
Srinivasa Rao Uppala7bb22102011-07-14 11:27:30 -07002664 srch = srch - SEARCH_RDS_STNS_MODE_OFFSET;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002665 radio->srch_rds.srch_station.srch_mode = srch;
2666 radio->srch_rds.srch_station.srch_dir = dir;
2667 radio->srch_rds.srch_station.scan_time =
2668 radio->g_scan_time;
2669 retval = hci_fm_search_rds_stations(&radio->srch_rds,
2670 radio->fm_hdev);
2671 break;
2672 default:
2673 radio->srch_st.srch_mode = srch;
2674 radio->srch_st.scan_time = radio->g_scan_time;
2675 radio->srch_st.srch_dir = dir;
2676 retval = hci_fm_search_stations(
2677 &radio->srch_st, radio->fm_hdev);
2678 break;
2679 }
2680
2681 } else {
2682 retval = hci_cmd(HCI_FM_CANCEL_SEARCH_CMD, radio->fm_hdev);
2683 }
2684
2685 return retval;
2686}
2687
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302688static int set_low_power_mode(struct iris_device *radio, int power_mode)
2689{
2690
2691 int rds_grps_proc = 0x00;
2692 int retval = 0;
Ayaz Ahmad53177572013-10-09 16:20:40 +05302693
2694 if (radio == NULL) {
2695 FMDERR(":radio is null");
2696 return -EINVAL;
2697 }
2698
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302699 if (radio->power_mode != power_mode) {
2700
2701 if (power_mode) {
2702 radio->event_mask = 0x00;
Srinivasa Rao Uppala1da1a242012-01-11 11:00:10 +05302703 if (radio->af_jump_bit)
2704 rds_grps_proc = 0x00 | AF_JUMP_ENABLE;
2705 else
2706 rds_grps_proc = 0x00;
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302707 retval = hci_fm_rds_grps_process(
2708 &rds_grps_proc,
2709 radio->fm_hdev);
2710 if (retval < 0) {
2711 FMDERR("Disable RDS failed");
2712 return retval;
2713 }
2714 retval = hci_conf_event_mask(&radio->event_mask,
2715 radio->fm_hdev);
2716 } else {
2717
2718 radio->event_mask = SIG_LEVEL_INTR |
2719 RDS_SYNC_INTR | AUDIO_CTRL_INTR;
2720 retval = hci_conf_event_mask(&radio->event_mask,
2721 radio->fm_hdev);
2722 if (retval < 0) {
2723 FMDERR("Enable Async events failed");
2724 return retval;
2725 }
2726 retval = hci_fm_rds_grps_process(
2727 &radio->g_rds_grp_proc_ps,
2728 radio->fm_hdev);
2729 }
2730 radio->power_mode = power_mode;
2731 }
2732 return retval;
2733}
Ankur Nandwanid928d542011-08-11 13:15:41 -07002734static int iris_recv_set_region(struct iris_device *radio, int req_region)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002735{
2736 int retval;
Ayaz Ahmad53177572013-10-09 16:20:40 +05302737
2738 if (radio == NULL) {
2739 FMDERR(":radio is null");
2740 return -EINVAL;
2741 }
2742
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002743 radio->region = req_region;
2744
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002745 retval = hci_set_fm_recv_conf(
2746 &radio->recv_conf,
2747 radio->fm_hdev);
2748
2749 return retval;
2750}
2751
Ankur Nandwanid928d542011-08-11 13:15:41 -07002752
2753static int iris_trans_set_region(struct iris_device *radio, int req_region)
2754{
2755 int retval;
Ayaz Ahmad53177572013-10-09 16:20:40 +05302756
2757 if (radio == NULL) {
2758 FMDERR(":radio is null");
2759 return -EINVAL;
2760 }
Ankur Nandwanid928d542011-08-11 13:15:41 -07002761 radio->region = req_region;
2762
Ankur Nandwanid928d542011-08-11 13:15:41 -07002763 retval = hci_set_fm_trans_conf(
2764 &radio->trans_conf,
2765 radio->fm_hdev);
2766 return retval;
2767}
2768
2769
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002770static int iris_set_freq(struct iris_device *radio, unsigned int freq)
2771{
2772
2773 int retval;
Ayaz Ahmad53177572013-10-09 16:20:40 +05302774
2775 if (radio == NULL) {
2776 FMDERR(":radio is null");
2777 return -EINVAL;
2778 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002779 retval = hci_fm_tune_station(&freq, radio->fm_hdev);
2780 if (retval < 0)
2781 FMDERR("Error while setting the frequency : %d\n", retval);
2782 return retval;
2783}
2784
2785
2786static int iris_vidioc_queryctrl(struct file *file, void *priv,
2787 struct v4l2_queryctrl *qc)
2788{
2789 unsigned char i;
2790 int retval = -EINVAL;
2791
2792 for (i = 0; i < ARRAY_SIZE(iris_v4l2_queryctrl); i++) {
2793 if (qc->id && qc->id == iris_v4l2_queryctrl[i].id) {
2794 memcpy(qc, &(iris_v4l2_queryctrl[i]), sizeof(*qc));
2795 retval = 0;
2796 break;
2797 }
2798 }
2799
2800 return retval;
2801}
2802
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302803static int iris_do_calibration(struct iris_device *radio)
2804{
2805 char cal_mode = 0x00;
2806 int retval = 0x00;
2807
Ayaz Ahmad53177572013-10-09 16:20:40 +05302808 if (radio == NULL) {
2809 FMDERR(":radio is null");
2810 return -EINVAL;
2811 }
2812
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302813 cal_mode = PROCS_CALIB_MODE;
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05302814 radio->mode = FM_CALIB;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302815 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
2816 radio->fm_hdev);
2817 if (retval < 0) {
2818 FMDERR("Enable failed before calibration %x", retval);
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05302819 radio->mode = FM_OFF;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302820 return retval;
2821 }
2822 retval = radio_hci_request(radio->fm_hdev, hci_fm_do_cal_req,
2823 (unsigned long)cal_mode, RADIO_HCI_TIMEOUT);
2824 if (retval < 0) {
2825 FMDERR("Do Process calibration failed %x", retval);
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05302826 radio->mode = FM_RECV;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302827 return retval;
2828 }
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302829 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
2830 radio->fm_hdev);
2831 if (retval < 0)
2832 FMDERR("Disable Failed after calibration %d", retval);
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05302833 else
2834 radio->mode = FM_OFF;
2835
Anantha Krishnan152fe5b2012-02-28 18:07:20 +05302836 return retval;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302837}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002838static int iris_vidioc_g_ctrl(struct file *file, void *priv,
2839 struct v4l2_control *ctrl)
2840{
2841 struct iris_device *radio = video_get_drvdata(video_devdata(file));
2842 int retval = 0;
Ayaz Ahmaddb04b0c2013-02-01 17:18:34 +05302843 int cf0;
2844 struct hci_fm_def_data_rd_req rd;
2845 int lsb, msb;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002846
Ayaz Ahmad53177572013-10-09 16:20:40 +05302847 if (radio == NULL) {
2848 FMDERR(":radio is null");
2849 return -EINVAL;
2850 }
2851
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002852 switch (ctrl->id) {
2853 case V4L2_CID_AUDIO_VOLUME:
2854 break;
2855 case V4L2_CID_AUDIO_MUTE:
2856 ctrl->value = radio->mute_mode.hard_mute;
2857 break;
2858 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
2859 ctrl->value = radio->g_search_mode;
2860 break;
2861 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
2862 ctrl->value = radio->g_scan_time;
2863 break;
2864 case V4L2_CID_PRIVATE_IRIS_SRCHON:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302865 ctrl->value = radio->search_on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002866 break;
2867 case V4L2_CID_PRIVATE_IRIS_STATE:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302868 ctrl->value = radio->mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002869 break;
2870 case V4L2_CID_PRIVATE_IRIS_IOVERC:
2871 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2872 if (retval < 0)
2873 return retval;
2874 ctrl->value = radio->st_dbg_param.io_verc;
2875 break;
2876 case V4L2_CID_PRIVATE_IRIS_INTDET:
2877 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
2878 if (retval < 0)
2879 return retval;
2880 ctrl->value = radio->st_dbg_param.in_det_out;
2881 break;
2882 case V4L2_CID_PRIVATE_IRIS_REGION:
2883 ctrl->value = radio->region;
2884 break;
2885 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
2886 retval = hci_cmd(HCI_FM_GET_SIGNAL_TH_CMD, radio->fm_hdev);
Venkateshwarlu Domakonda3d1d6e42011-12-09 15:08:58 +05302887 if (retval < 0) {
2888 FMDERR("Error in get signal threshold %d\n", retval);
2889 return retval;
2890 }
2891 ctrl->value = radio->sig_th.sig_threshold;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002892 break;
2893 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302894 ctrl->value = radio->srch_rds.srch_pty;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002895 break;
2896 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302897 ctrl->value = radio->srch_rds.srch_pi;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002898 break;
2899 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05302900 ctrl->value = radio->srch_st_result.num_stations_found;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002901 break;
2902 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002903 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002904 ctrl->value = radio->recv_conf.emphasis;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002905 } else if (radio->mode == FM_TRANS) {
2906 ctrl->value = radio->trans_conf.emphasis;
2907 } else {
2908 FMDERR("Error in radio mode"
2909 " %d\n", retval);
2910 return -EINVAL;
2911 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002912 break;
2913 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002914 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002915 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002916 } else if (radio->mode == FM_TRANS) {
2917 ctrl->value = radio->trans_conf.rds_std;
2918 } else {
2919 FMDERR("Error in radio mode"
2920 " %d\n", retval);
2921 return -EINVAL;
2922 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002923 break;
2924 case V4L2_CID_PRIVATE_IRIS_SPACING:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002925 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002926 ctrl->value = radio->recv_conf.ch_spacing;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002927 } else {
2928 FMDERR("Error in radio mode"
2929 " %d\n", retval);
2930 return -EINVAL;
2931 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002932 break;
2933 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwanid928d542011-08-11 13:15:41 -07002934 if (radio->mode == FM_RECV) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002935 ctrl->value = radio->recv_conf.rds_std;
Ankur Nandwanid928d542011-08-11 13:15:41 -07002936 } else {
2937 FMDERR("Error in radio mode"
2938 " %d\n", retval);
2939 return -EINVAL;
2940 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002941 break;
2942 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
2943 ctrl->value = radio->rds_grp.rds_grp_enable_mask;
2944 break;
2945 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07002946 case V4L2_CID_PRIVATE_IRIS_PSALL:
2947 ctrl->value = (radio->g_rds_grp_proc_ps << RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002948 break;
2949 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
2950 ctrl->value = radio->rds_grp.rds_buf_size;
2951 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002952 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05302953 ctrl->value = radio->power_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002954 break;
2955 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
2956 ctrl->value = radio->g_antenna;
2957 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07002958 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
2959 ctrl->value = radio->mute_mode.soft_mute;
2960 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05302961 case V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION:
2962 retval = iris_do_calibration(radio);
2963 break;
Srinivasa Rao Uppalaacdebcc2011-12-23 14:31:38 +05302964 case V4L2_CID_PRIVATE_IRIS_GET_SINR:
2965 if (radio->mode == FM_RECV) {
2966 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD,
2967 radio->fm_hdev);
2968 if (retval < 0) {
2969 FMDERR("Get SINR Failed");
2970 return retval;
2971 }
2972 ctrl->value = radio->fm_st_rsp.station_rsp.sinr;
2973
2974 } else
2975 retval = -EINVAL;
Ayaz Ahmadb69202b2012-02-23 19:24:46 +05302976 break;
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +05302977 case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
2978 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
2979 if (retval < 0) {
2980 FMDERR("Get High det threshold failed %x", retval);
2981 return retval;
2982 }
2983 ctrl->value = radio->ch_det_threshold.high_th;
2984 break;
2985 case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
2986 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
2987 if (retval < 0) {
2988 FMDERR("Get Low det threshold failed %x", retval);
2989 return retval;
2990 }
2991 ctrl->value = radio->ch_det_threshold.low_th;
2992 break;
2993 case V4L2_CID_PRIVATE_SINR_THRESHOLD:
2994 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
2995 if (retval < 0) {
2996 FMDERR("Get SINR threshold failed %x", retval);
2997 return retval;
2998 }
2999 ctrl->value = radio->ch_det_threshold.sinr;
3000 break;
3001 case V4L2_CID_PRIVATE_SINR_SAMPLES:
3002 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
3003 if (retval < 0) {
3004 FMDERR("Get SINR samples failed %x", retval);
3005 return retval;
3006 }
3007
3008 ctrl->value = radio->ch_det_threshold.sinr_samples;
Srinivasa Rao Uppalaacdebcc2011-12-23 14:31:38 +05303009 break;
Ayaz Ahmad37294ba2012-07-10 16:38:11 +05303010 case V4L2_CID_PRIVATE_VALID_CHANNEL:
3011 ctrl->value = radio->is_station_valid;
3012 break;
Ayaz Ahmaddb04b0c2013-02-01 17:18:34 +05303013 case V4L2_CID_PRIVATE_AF_RMSSI_TH:
3014 rd.mode = FM_RDS_CNFG_MODE;
3015 rd.length = FM_RDS_CNFG_LEN;
3016 rd.param_len = 0;
3017 rd.param = 0;
3018
3019 retval = hci_def_data_read(&rd, radio->fm_hdev);
3020 if (retval < 0) {
3021 FMDERR("Get AF Jump Threshold failed %x", retval);
3022 return retval;
3023 }
3024 lsb = radio->default_data.data[AF_RMSSI_TH_LSB_OFFSET];
3025 msb = radio->default_data.data[AF_RMSSI_TH_MSB_OFFSET];
3026 ctrl->value = ((msb << 8) | lsb);
3027 break;
3028 case V4L2_CID_PRIVATE_AF_RMSSI_SAMPLES:
3029 rd.mode = FM_RDS_CNFG_MODE;
3030 rd.length = FM_RDS_CNFG_LEN;
3031 rd.param_len = 0;
3032 rd.param = 0;
3033
3034 retval = hci_def_data_read(&rd, radio->fm_hdev);
3035 if (retval < 0) {
3036 FMDERR("Get AF jump rmssi samples failed %x", retval);
3037 return retval;
3038 }
3039 ctrl->value = radio->default_data.data[AF_RMSSI_SAMPLES_OFFSET];
3040 break;
3041 case V4L2_CID_PRIVATE_GOOD_CH_RMSSI_TH:
3042 rd.mode = FM_RX_CONFG_MODE;
3043 rd.length = FM_RX_CNFG_LEN;
3044 rd.param_len = 0;
3045 rd.param = 0;
3046
3047 retval = hci_def_data_read(&rd, radio->fm_hdev);
3048 if (retval < 0) {
3049 FMDERR("get good channel rmssi th failed %x", retval);
3050 return retval;
3051 }
3052 ctrl->value = radio->default_data.data[GD_CH_RMSSI_TH_OFFSET];
3053 if (ctrl->value > MAX_GD_CH_RMSSI_TH)
3054 ctrl->value -= 256;
3055 break;
3056 case V4L2_CID_PRIVATE_SRCHALGOTYPE:
3057 rd.mode = FM_RX_CONFG_MODE;
3058 rd.length = FM_RX_CNFG_LEN;
3059 rd.param_len = 0;
3060 rd.param = 0;
3061
3062 retval = hci_def_data_read(&rd, radio->fm_hdev);
3063 if (retval < 0) {
3064 FMDERR("get search algo type failed %x", retval);
3065 return retval;
3066 }
3067 ctrl->value = radio->default_data.data[SRCH_ALGO_TYPE_OFFSET];
3068 break;
3069 case V4L2_CID_PRIVATE_SINRFIRSTSTAGE:
3070 rd.mode = FM_RX_CONFG_MODE;
3071 rd.length = FM_RX_CNFG_LEN;
3072 rd.param_len = 0;
3073 rd.param = 0;
3074
3075 retval = hci_def_data_read(&rd, radio->fm_hdev);
3076 if (retval < 0) {
3077 FMDERR("default data read failed %x", retval);
3078 return retval;
3079 }
3080 ctrl->value = radio->default_data.data[SINRFIRSTSTAGE_OFFSET];
3081 if (ctrl->value > MAX_SINR_FIRSTSTAGE)
3082 ctrl->value -= 256;
3083 break;
3084 case V4L2_CID_PRIVATE_RMSSIFIRSTSTAGE:
3085 rd.mode = FM_RX_CONFG_MODE;
3086 rd.length = FM_RX_CNFG_LEN;
3087 rd.param_len = 0;
3088 rd.param = 0;
3089
3090 retval = hci_def_data_read(&rd, radio->fm_hdev);
3091 if (retval < 0) {
3092 FMDERR("default data read failed %x", retval);
3093 return retval;
3094 }
3095 ctrl->value = radio->default_data.data[RMSSIFIRSTSTAGE_OFFSET];
3096 if (ctrl->value > MAX_RMSSI_FIRSTSTAGE)
3097 ctrl->value -= 256;
3098 break;
3099 case V4L2_CID_PRIVATE_CF0TH12:
3100 rd.mode = FM_RX_CONFG_MODE;
3101 rd.length = FM_RX_CNFG_LEN;
3102 rd.param_len = 0;
3103 rd.param = 0;
3104
3105 retval = hci_def_data_read(&rd, radio->fm_hdev);
3106 if (retval < 0) {
3107 FMDERR("default data read failed %x", retval);
3108 return retval;
3109 }
3110 ctrl->value = radio->default_data.data[CF0TH12_BYTE1_OFFSET];
3111 cf0 = radio->default_data.data[CF0TH12_BYTE2_OFFSET];
3112 ctrl->value |= (cf0 << 8);
3113 cf0 = radio->default_data.data[CF0TH12_BYTE3_OFFSET];
3114 ctrl->value |= (cf0 << 16);
3115 cf0 = radio->default_data.data[CF0TH12_BYTE4_OFFSET];
3116 if (cf0 > 127)
3117 cf0 -= 256;
3118 ctrl->value |= (cf0 << 24);
3119 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003120 default:
3121 retval = -EINVAL;
3122 }
3123 if (retval < 0)
3124 FMDERR("get control failed with %d, id: %d\n",
3125 retval, ctrl->id);
3126 return retval;
3127}
3128
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05303129static int iris_vidioc_g_ext_ctrls(struct file *file, void *priv,
3130 struct v4l2_ext_controls *ctrl)
3131{
3132 int retval = 0;
3133 char *data = NULL;
3134 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3135 struct hci_fm_def_data_rd_req default_data_rd;
3136
Ayaz Ahmad53177572013-10-09 16:20:40 +05303137 if (radio == NULL) {
3138 FMDERR(":radio is null");
3139 return -EINVAL;
3140 }
3141
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05303142 switch ((ctrl->controls[0]).id) {
3143 case V4L2_CID_PRIVATE_IRIS_READ_DEFAULT:
3144 data = (ctrl->controls[0]).string;
3145 memset(&default_data_rd, 0, sizeof(default_data_rd));
3146 if (copy_from_user(&default_data_rd.mode, data,
3147 sizeof(default_data_rd)))
3148 return -EFAULT;
3149 retval = hci_def_data_read(&default_data_rd, radio->fm_hdev);
3150 break;
3151 default:
3152 retval = -EINVAL;
3153 }
3154
3155 return retval;
3156}
3157
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003158static int iris_vidioc_s_ext_ctrls(struct file *file, void *priv,
3159 struct v4l2_ext_controls *ctrl)
3160{
Ankur Nandwanid928d542011-08-11 13:15:41 -07003161 int retval = 0;
3162 int bytes_to_copy;
3163 struct hci_fm_tx_ps tx_ps;
3164 struct hci_fm_tx_rt tx_rt;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05303165 struct hci_fm_def_data_wr_req default_data;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05303166 struct hci_fm_set_cal_req_proc proc_cal_req;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003167
3168 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3169 char *data = NULL;
3170
Ayaz Ahmad53177572013-10-09 16:20:40 +05303171 if (radio == NULL) {
3172 FMDERR(":radio is null");
3173 return -EINVAL;
3174 }
Ankur Nandwanid928d542011-08-11 13:15:41 -07003175 switch ((ctrl->controls[0]).id) {
3176 case V4L2_CID_RDS_TX_PS_NAME:
3177 FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
3178 /*Pass a sample PS string */
3179
3180 memset(tx_ps.ps_data, 0, MAX_PS_LENGTH);
3181 bytes_to_copy = min((int)(ctrl->controls[0]).size,
3182 MAX_PS_LENGTH);
3183 data = (ctrl->controls[0]).string;
3184
3185 if (copy_from_user(tx_ps.ps_data,
3186 data, bytes_to_copy))
3187 return -EFAULT;
3188 tx_ps.ps_control = 0x01;
3189 tx_ps.pi = radio->pi;
3190 tx_ps.pty = radio->pty;
3191 tx_ps.ps_repeatcount = radio->ps_repeatcount;
Ayaz Ahmad1c0db522012-08-27 17:52:51 +05303192 tx_ps.ps_num = (bytes_to_copy / PS_STRING_LEN);
Ankur Nandwanid928d542011-08-11 13:15:41 -07003193
3194 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
3195 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
3196 break;
3197 case V4L2_CID_RDS_TX_RADIO_TEXT:
3198 bytes_to_copy =
3199 min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
3200 data = (ctrl->controls[0]).string;
3201
3202 memset(tx_rt.rt_data, 0, MAX_RT_LENGTH);
3203
3204 if (copy_from_user(tx_rt.rt_data,
3205 data, bytes_to_copy))
3206 return -EFAULT;
3207
3208 tx_rt.rt_control = 0x01;
3209 tx_rt.pi = radio->pi;
3210 tx_rt.pty = radio->pty;
Ayaz Ahmad1c0db522012-08-27 17:52:51 +05303211 tx_rt.rt_len = bytes_to_copy;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003212
3213 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
3214 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
3215 break;
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05303216 case V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT:
3217 data = (ctrl->controls[0]).string;
3218 memset(&default_data, 0, sizeof(default_data));
Anantha Krishnan152fe5b2012-02-28 18:07:20 +05303219 /*
3220 * Check if length of the 'FM Default Data' to be sent
3221 * is within the maximum 'FM Default Data' packet limit.
3222 * Max. 'FM Default Data' packet length is 251 bytes:
3223 * 1 byte - XFR Mode
3224 * 1 byte - length of the default data
3225 * 249 bytes - actual data to be configured
3226 */
3227 if (ctrl->controls[0].size > (DEFAULT_DATA_SIZE + 2)) {
3228 pr_err("%s: Default data buffer overflow!\n", __func__);
3229 return -EINVAL;
3230 }
3231
3232 /* copy only 'size' bytes of data as requested by user */
3233 retval = copy_from_user(&default_data, data,
3234 ctrl->controls[0].size);
3235 if (retval > 0) {
3236 pr_err("%s: Failed to copy %d bytes of default data"
3237 " passed by user\n", __func__, retval);
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05303238 return -EFAULT;
Anantha Krishnan152fe5b2012-02-28 18:07:20 +05303239 }
3240 FMDBG("%s: XFR Mode\t: 0x%x\n", __func__, default_data.mode);
3241 FMDBG("%s: XFR Data Length\t: %d\n", __func__,
3242 default_data.length);
3243 /*
3244 * Check if the 'length' of the actual XFR data to be configured
3245 * is valid or not. Length of actual XFR data should be always
3246 * 2 bytes less than the total length of the 'FM Default Data'.
3247 * Length of 'FM Default Data' DEF_DATA_LEN: (1+1+XFR Data Size)
3248 * Length of 'Actual XFR Data' XFR_DATA_LEN: (DEF_DATA_LEN - 2)
3249 */
3250 if (default_data.length != (ctrl->controls[0].size - 2)) {
3251 pr_err("%s: Invalid 'length' parameter passed for "
3252 "actual xfr data\n", __func__);
3253 return -EINVAL;
3254 }
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05303255 retval = hci_def_data_write(&default_data, radio->fm_hdev);
Anantha Krishnan152fe5b2012-02-28 18:07:20 +05303256 break;
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05303257 case V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION:
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05303258 data = (ctrl->controls[0]).string;
3259 bytes_to_copy = (ctrl->controls[0]).size;
Venkateshwarlu Domakonda5e96e692011-12-05 17:36:06 +05303260 if (bytes_to_copy < PROCS_CALIB_SIZE) {
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05303261 FMDERR("data is less than required size");
3262 return -EFAULT;
3263 }
3264 memset(proc_cal_req.data, 0, PROCS_CALIB_SIZE);
3265 proc_cal_req.mode = PROCS_CALIB_MODE;
3266 if (copy_from_user(&proc_cal_req.data[0],
3267 data, sizeof(proc_cal_req.data)))
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05303268 return -EFAULT;
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05303269 retval = radio_hci_request(radio->fm_hdev,
3270 hci_fm_set_cal_req_proc,
3271 (unsigned long)&proc_cal_req,
3272 RADIO_HCI_TIMEOUT);
Srinivasa Rao Uppalaacdebcc2011-12-23 14:31:38 +05303273 if (retval < 0)
Srinivasa Rao Uppalacb48ee62011-10-25 09:57:06 +05303274 FMDERR("Set Process calibration failed %d", retval);
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05303275 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003276 default:
3277 FMDBG("Shouldn't reach here\n");
3278 retval = -1;
3279 }
3280 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003281}
3282
3283static int iris_vidioc_s_ctrl(struct file *file, void *priv,
3284 struct v4l2_control *ctrl)
3285{
3286 struct iris_device *radio = video_get_drvdata(video_devdata(file));
3287 int retval = 0;
3288 unsigned int rds_grps_proc = 0;
3289 __u8 temp_val = 0;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003290 unsigned long arg = 0;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05303291 struct hci_fm_tx_ps tx_ps = {0};
3292 struct hci_fm_tx_rt tx_rt = {0};
Ayaz Ahmaddb04b0c2013-02-01 17:18:34 +05303293 struct hci_fm_def_data_rd_req rd;
3294 struct hci_fm_def_data_wr_req wrd;
Ayaz Ahmad37294ba2012-07-10 16:38:11 +05303295 char sinr_th, sinr;
3296 __u8 intf_det_low_th, intf_det_high_th, intf_det_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003297
Ayaz Ahmad53177572013-10-09 16:20:40 +05303298 if (radio == NULL) {
3299 FMDERR(":radio is null");
3300 return -EINVAL;
3301 }
3302
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003303 switch (ctrl->id) {
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05303304 case V4L2_CID_PRIVATE_IRIS_TX_TONE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07003305 radio->tone_freq = ctrl->value;
3306 retval = radio_hci_request(radio->fm_hdev,
3307 hci_fm_tone_generator, arg,
3308 msecs_to_jiffies(RADIO_HCI_TIMEOUT));
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303309 if (retval < 0)
3310 FMDERR("Error while setting the tone %d", retval);
Ankur Nandwanid928d542011-08-11 13:15:41 -07003311 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003312 case V4L2_CID_AUDIO_VOLUME:
3313 break;
3314 case V4L2_CID_AUDIO_MUTE:
3315 radio->mute_mode.hard_mute = ctrl->value;
3316 radio->mute_mode.soft_mute = IOC_SFT_MUTE;
3317 retval = hci_set_fm_mute_mode(
3318 &radio->mute_mode,
3319 radio->fm_hdev);
3320 if (retval < 0)
3321 FMDERR("Error while set FM hard mute"" %d\n",
3322 retval);
3323 break;
3324 case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
3325 radio->g_search_mode = ctrl->value;
3326 break;
3327 case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
3328 radio->g_scan_time = ctrl->value;
3329 break;
3330 case V4L2_CID_PRIVATE_IRIS_SRCHON:
3331 iris_search(radio, ctrl->value, SRCH_DIR_UP);
3332 break;
3333 case V4L2_CID_PRIVATE_IRIS_STATE:
Ankur Nandwanid928d542011-08-11 13:15:41 -07003334 switch (ctrl->value) {
3335 case FM_RECV:
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05303336 if (is_enable_rx_possible(radio) != 0)
3337 return -EINVAL;
3338 radio->mode = FM_RECV_TURNING_ON;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003339 retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
3340 radio->fm_hdev);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303341 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07003342 FMDERR("Error while enabling RECV FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07003343 " %d\n", retval);
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05303344 radio->mode = FM_OFF;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303345 return retval;
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05303346 } else {
3347 initialise_recv(radio);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303348 }
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07003349 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003350 case FM_TRANS:
Ayaz Ahmadaf8379e2013-08-20 12:54:20 +05303351 if (is_enable_tx_possible(radio) != 0)
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05303352 return -EINVAL;
3353 radio->mode = FM_TRANS_TURNING_ON;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003354 retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
3355 radio->fm_hdev);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303356 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07003357 FMDERR("Error while enabling TRANS FM"
3358 " %d\n", retval);
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05303359 radio->mode = FM_OFF;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303360 return retval;
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05303361 } else {
3362 initialise_trans(radio);
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05303363 }
Srinivasa Rao Uppala07522d92011-08-16 05:09:30 -07003364 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003365 case FM_OFF:
Anantha Krishnanf950e322012-06-06 14:25:49 +05303366 radio->spur_table_size = 0;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003367 switch (radio->mode) {
3368 case FM_RECV:
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05303369 radio->mode = FM_TURNING_OFF;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003370 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
3371 radio->fm_hdev);
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05303372 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07003373 FMDERR("Err on disable recv FM"
3374 " %d\n", retval);
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05303375 radio->mode = FM_RECV;
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05303376 return retval;
3377 }
Ankur Nandwanid928d542011-08-11 13:15:41 -07003378 break;
3379 case FM_TRANS:
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05303380 radio->mode = FM_TURNING_OFF;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003381 retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
3382 radio->fm_hdev);
3383
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05303384 if (retval < 0) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07003385 FMDERR("Err disabling trans FM"
Srinivasa Rao Uppala0ffb5d62011-08-02 17:54:13 -07003386 " %d\n", retval);
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05303387 radio->mode = FM_TRANS;
Ayaz Ahmadc1e6a952012-05-15 19:29:54 +05303388 return retval;
3389 }
Ankur Nandwanid928d542011-08-11 13:15:41 -07003390 break;
3391 default:
3392 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003393 }
Srinivasa Rao Uppalacc62b1c2011-08-22 19:15:29 +05303394 break;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003395 default:
3396 retval = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003397 }
3398 break;
3399 case V4L2_CID_PRIVATE_IRIS_REGION:
Ankur Nandwanid928d542011-08-11 13:15:41 -07003400 if (radio->mode == FM_RECV) {
3401 retval = iris_recv_set_region(radio, ctrl->value);
3402 } else {
3403 if (radio->mode == FM_TRANS)
3404 retval = iris_trans_set_region(radio,
3405 ctrl->value);
3406 else
3407 retval = -EINVAL;
3408 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003409 break;
3410 case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
3411 temp_val = ctrl->value;
3412 retval = hci_fm_set_signal_threshold(
3413 &temp_val,
3414 radio->fm_hdev);
3415 if (retval < 0) {
3416 FMDERR("Error while setting signal threshold\n");
3417 break;
3418 }
3419 break;
3420 case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
3421 radio->srch_rds.srch_pty = ctrl->value;
3422 radio->srch_st_list.srch_pty = ctrl->value;
3423 break;
3424 case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
3425 radio->srch_rds.srch_pi = ctrl->value;
3426 break;
3427 case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
Ayaz Ahmad7ba5c1c2012-11-20 14:55:15 +05303428 radio->srch_st_list.srch_list_max = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003429 break;
3430 case V4L2_CID_PRIVATE_IRIS_SPACING:
Venkateshwarlu Domakonda45496f12011-11-23 12:51:13 +05303431 if (radio->mode == FM_RECV) {
3432 radio->recv_conf.ch_spacing = ctrl->value;
3433 retval = hci_set_fm_recv_conf(
3434 &radio->recv_conf,
3435 radio->fm_hdev);
3436 if (retval < 0)
3437 FMDERR("Error in setting channel spacing");
3438 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003439 break;
3440 case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003441 switch (radio->mode) {
3442 case FM_RECV:
3443 radio->recv_conf.emphasis = ctrl->value;
3444 retval = hci_set_fm_recv_conf(
3445 &radio->recv_conf,
3446 radio->fm_hdev);
3447 if (retval < 0)
3448 FMDERR("Error in setting emphasis");
Ankur Nandwanid928d542011-08-11 13:15:41 -07003449 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003450 case FM_TRANS:
3451 radio->trans_conf.emphasis = ctrl->value;
3452 retval = hci_set_fm_trans_conf(
3453 &radio->trans_conf,
3454 radio->fm_hdev);
3455 if (retval < 0)
3456 FMDERR("Error in setting emphasis");
3457 break;
3458 default:
3459 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003460 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003461 break;
3462 case V4L2_CID_PRIVATE_IRIS_RDS_STD:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003463 switch (radio->mode) {
3464 case FM_RECV:
3465 radio->recv_conf.rds_std = ctrl->value;
3466 retval = hci_set_fm_recv_conf(
3467 &radio->recv_conf,
3468 radio->fm_hdev);
3469 if (retval < 0)
3470 FMDERR("Error in rds_std");
Ankur Nandwanid928d542011-08-11 13:15:41 -07003471 break;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003472 case FM_TRANS:
3473 radio->trans_conf.rds_std = ctrl->value;
3474 retval = hci_set_fm_trans_conf(
3475 &radio->trans_conf,
3476 radio->fm_hdev);
3477 if (retval < 0)
3478 FMDERR("Error in rds_Std");
3479 break;
3480 default:
3481 retval = -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07003482 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003483 break;
3484 case V4L2_CID_PRIVATE_IRIS_RDSON:
Ankur Nandwani8f972e52011-08-24 11:48:32 -07003485 switch (radio->mode) {
3486 case FM_RECV:
3487 radio->recv_conf.rds_std = ctrl->value;
3488 retval = hci_set_fm_recv_conf(
3489 &radio->recv_conf,
3490 radio->fm_hdev);
3491 if (retval < 0)
3492 FMDERR("Error in rds_std");
3493 break;
3494 case FM_TRANS:
3495 radio->trans_conf.rds_std = ctrl->value;
3496 retval = hci_set_fm_trans_conf(
3497 &radio->trans_conf,
3498 radio->fm_hdev);
3499 if (retval < 0)
3500 FMDERR("Error in rds_Std");
3501 break;
3502 default:
3503 retval = -EINVAL;
3504 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003505 break;
3506 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
Ayaz Ahmad89265112012-10-05 19:39:11 +05303507 grp_mask = (grp_mask | oda_agt | ctrl->value);
3508 radio->rds_grp.rds_grp_enable_mask = grp_mask;
3509 radio->rds_grp.rds_buf_size = 1;
3510 radio->rds_grp.en_rds_change_filter = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003511 retval = hci_fm_rds_grp(&radio->rds_grp, radio->fm_hdev);
Ayaz Ahmad89265112012-10-05 19:39:11 +05303512 if (retval < 0)
3513 FMDERR("error in setting group mask\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003514 break;
3515 case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
3516 rds_grps_proc = radio->g_rds_grp_proc_ps | ctrl->value;
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07003517 radio->g_rds_grp_proc_ps = (rds_grps_proc >> RDS_CONFIG_OFFSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003518 retval = hci_fm_rds_grps_process(
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07003519 &radio->g_rds_grp_proc_ps,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003520 radio->fm_hdev);
3521 break;
3522 case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
3523 radio->rds_grp.rds_buf_size = ctrl->value;
3524 break;
3525 case V4L2_CID_PRIVATE_IRIS_PSALL:
Srinivasa Rao Uppala58273f82011-08-10 19:07:45 -07003526 rds_grps_proc = (ctrl->value << RDS_CONFIG_OFFSET);
3527 radio->g_rds_grp_proc_ps |= rds_grps_proc;
3528 retval = hci_fm_rds_grps_process(
3529 &radio->g_rds_grp_proc_ps,
3530 radio->fm_hdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003531 break;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05303532 case V4L2_CID_PRIVATE_IRIS_AF_JUMP:
Srinivasa Rao Uppala1da1a242012-01-11 11:00:10 +05303533 /*Clear the current AF jump settings*/
3534 radio->g_rds_grp_proc_ps &= ~(1 << RDS_AF_JUMP_OFFSET);
3535 radio->af_jump_bit = ctrl->value;
3536 rds_grps_proc = 0x00;
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05303537 rds_grps_proc = (ctrl->value << RDS_AF_JUMP_OFFSET);
3538 radio->g_rds_grp_proc_ps |= rds_grps_proc;
3539 retval = hci_fm_rds_grps_process(
3540 &radio->g_rds_grp_proc_ps,
3541 radio->fm_hdev);
3542 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003543 case V4L2_CID_PRIVATE_IRIS_LP_MODE:
Srinivasa Rao Uppalaf856ae62011-10-17 18:43:26 +05303544 set_low_power_mode(radio, ctrl->value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003545 break;
3546 case V4L2_CID_PRIVATE_IRIS_ANTENNA:
3547 temp_val = ctrl->value;
3548 retval = hci_fm_set_antenna(&temp_val, radio->fm_hdev);
Srinivasa Rao Uppala2f51a972012-01-23 20:11:13 +05303549 if (retval < 0) {
3550 FMDERR("Set Antenna failed retval = %x", retval);
3551 return retval;
3552 }
3553 radio->g_antenna = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003554 break;
3555 case V4L2_CID_RDS_TX_PTY:
Ankur Nandwanid928d542011-08-11 13:15:41 -07003556 radio->pty = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003557 break;
3558 case V4L2_CID_RDS_TX_PI:
Ankur Nandwanid928d542011-08-11 13:15:41 -07003559 radio->pi = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003560 break;
3561 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05303562 tx_ps.ps_control = 0x00;
3563 retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
3564 (unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003565 break;
3566 case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_RT:
Srinivasa Rao Uppala3c7a8eb2011-09-18 09:10:21 +05303567 tx_rt.rt_control = 0x00;
3568 retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
3569 (unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003570 break;
3571 case V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT:
Ankur Nandwanid928d542011-08-11 13:15:41 -07003572 radio->ps_repeatcount = ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003573 break;
3574 case V4L2_CID_TUNE_POWER_LEVEL:
Venkateshwarlu Domakonda71731d52012-04-04 12:30:51 +05303575 if (ctrl->value > FM_TX_PWR_LVL_MAX)
3576 ctrl->value = FM_TX_PWR_LVL_MAX;
3577 if (ctrl->value < FM_TX_PWR_LVL_0)
3578 ctrl->value = FM_TX_PWR_LVL_0;
Ayaz Ahmaddb04b0c2013-02-01 17:18:34 +05303579 rd.mode = FM_TX_PHY_CFG_MODE;
3580 rd.length = FM_TX_PHY_CFG_LEN;
3581 rd.param_len = 0x00;
3582 rd.param = 0x00;
Venkateshwarlu Domakonda71731d52012-04-04 12:30:51 +05303583
Ayaz Ahmaddb04b0c2013-02-01 17:18:34 +05303584 retval = hci_def_data_read(&rd, radio->fm_hdev);
Venkateshwarlu Domakonda71731d52012-04-04 12:30:51 +05303585 if (retval < 0) {
3586 FMDERR("Default data read failed for PHY_CFG %d\n",
3587 retval);
3588 break;
3589 }
Ayaz Ahmaddb04b0c2013-02-01 17:18:34 +05303590 memset(&wrd, 0, sizeof(wrd));
3591 wrd.mode = FM_TX_PHY_CFG_MODE;
3592 wrd.length = FM_TX_PHY_CFG_LEN;
3593 memcpy(&wrd.data, &radio->default_data.data,
Venkateshwarlu Domakonda71731d52012-04-04 12:30:51 +05303594 radio->default_data.ret_data_len);
Ayaz Ahmaddb04b0c2013-02-01 17:18:34 +05303595 wrd.data[FM_TX_PWR_GAIN_OFFSET] =
Venkateshwarlu Domakonda71731d52012-04-04 12:30:51 +05303596 (ctrl->value) * FM_TX_PWR_LVL_STEP_SIZE;
Ayaz Ahmaddb04b0c2013-02-01 17:18:34 +05303597 retval = hci_def_data_write(&wrd, radio->fm_hdev);
Venkateshwarlu Domakonda71731d52012-04-04 12:30:51 +05303598 if (retval < 0)
3599 FMDERR("Default write failed for PHY_TXGAIN %d\n",
3600 retval);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003601 break;
Srinivasa Rao Uppalaabc8efa2011-08-02 14:31:30 -07003602 case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
3603 radio->mute_mode.soft_mute = ctrl->value;
3604 retval = hci_set_fm_mute_mode(
3605 &radio->mute_mode,
3606 radio->fm_hdev);
3607 if (retval < 0)
3608 FMDERR("Error while setting FM soft mute"" %d\n",
3609 retval);
3610 break;
3611 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR:
3612 radio->riva_data_req.cmd_params.start_addr = ctrl->value;
3613 break;
3614 case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN:
3615 radio->riva_data_req.cmd_params.length = ctrl->value;
3616 break;
3617 case V4L2_CID_PRIVATE_IRIS_RIVA_POKE:
3618 memcpy(radio->riva_data_req.data, (void *)ctrl->value,
3619 radio->riva_data_req.cmd_params.length);
3620 radio->riva_data_req.cmd_params.subopcode = RIVA_POKE_OPCODE;
3621 retval = hci_poke_data(&radio->riva_data_req , radio->fm_hdev);
3622 break;
3623 case V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR:
3624 radio->ssbi_data_accs.start_addr = ctrl->value;
3625 break;
3626 case V4L2_CID_PRIVATE_IRIS_SSBI_POKE:
3627 radio->ssbi_data_accs.data = ctrl->value;
3628 retval = hci_ssbi_poke_reg(&radio->ssbi_data_accs ,
3629 radio->fm_hdev);
3630 break;
3631 case V4L2_CID_PRIVATE_IRIS_RIVA_PEEK:
3632 radio->riva_data_req.cmd_params.subopcode = RIVA_PEEK_OPCODE;
3633 ctrl->value = hci_peek_data(&radio->riva_data_req.cmd_params ,
3634 radio->fm_hdev);
3635 break;
3636 case V4L2_CID_PRIVATE_IRIS_SSBI_PEEK:
3637 radio->ssbi_peek_reg.start_address = ctrl->value;
3638 hci_ssbi_peek_reg(&radio->ssbi_peek_reg, radio->fm_hdev);
3639 break;
Srinivasa Rao Uppala0f4098f2011-09-06 16:46:28 +05303640 case V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS:
3641 temp_val = ctrl->value;
3642 hci_read_grp_counters(&temp_val, radio->fm_hdev);
3643 break;
3644 case V4L2_CID_PRIVATE_IRIS_HLSI:
3645 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
3646 radio->fm_hdev);
3647 if (retval)
3648 break;
3649 radio->recv_conf.hlsi = ctrl->value;
3650 retval = hci_set_fm_recv_conf(
3651 &radio->recv_conf,
3652 radio->fm_hdev);
3653 break;
3654 case V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER:
3655 temp_val = ctrl->value;
3656 retval = hci_set_notch_filter(&temp_val, radio->fm_hdev);
3657 break;
Srinivasa Rao Uppalad3184a42012-01-04 21:18:01 +05303658 case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
3659 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
3660 if (retval < 0) {
3661 FMDERR("Failed to get chnl det thresholds %d", retval);
3662 return retval;
3663 }
3664 radio->ch_det_threshold.high_th = ctrl->value;
3665 retval = hci_set_ch_det_thresholds_req(&radio->ch_det_threshold,
3666 radio->fm_hdev);
3667 if (retval < 0) {
3668 FMDERR("Failed to set High det threshold %d ", retval);
3669 return retval;
3670 }
3671 break;
3672
3673 case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
3674 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
3675 if (retval < 0) {
3676 FMDERR("Failed to get chnl det thresholds %d", retval);
3677 return retval;
3678 }
3679 radio->ch_det_threshold.low_th = ctrl->value;
3680 retval = hci_set_ch_det_thresholds_req(&radio->ch_det_threshold,
3681 radio->fm_hdev);
3682 if (retval < 0) {
3683 FMDERR("Failed to Set Low det threshold %d", retval);
3684 return retval;
3685 }
3686 break;
3687
3688 case V4L2_CID_PRIVATE_SINR_THRESHOLD:
3689 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
3690 if (retval < 0) {
3691 FMDERR("Failed to get chnl det thresholds %d", retval);
3692 return retval;
3693 }
3694 radio->ch_det_threshold.sinr = ctrl->value;
3695 retval = hci_set_ch_det_thresholds_req(&radio->ch_det_threshold,
3696 radio->fm_hdev);
3697 if (retval < 0) {
3698 FMDERR("Failed to set SINR threshold %d", retval);
3699 return retval;
3700 }
3701 break;
3702
3703 case V4L2_CID_PRIVATE_SINR_SAMPLES:
3704 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
3705 if (retval < 0) {
3706 FMDERR("Failed to get chnl det thresholds %d", retval);
3707 return retval;
3708 }
3709 radio->ch_det_threshold.sinr_samples = ctrl->value;
3710 retval = hci_set_ch_det_thresholds_req(&radio->ch_det_threshold,
3711 radio->fm_hdev);
3712 if (retval < 0) {
3713 FMDERR("Failed to set SINR samples %d", retval);
3714 return retval;
3715 }
3716 break;
3717
Anantha Krishnan61dc15e2011-12-06 11:39:02 +05303718 case V4L2_CID_PRIVATE_IRIS_SRCH_ALGORITHM:
Srinivasa Rao Uppalade0b5d92011-12-27 18:09:10 +05303719 case V4L2_CID_PRIVATE_IRIS_SET_AUDIO_PATH:
Anantha Krishnan61dc15e2011-12-06 11:39:02 +05303720 /*
Srinivasa Rao Uppalade0b5d92011-12-27 18:09:10 +05303721 These private controls are place holders to keep the
Anantha Krishnan61dc15e2011-12-06 11:39:02 +05303722 driver compatible with changes done in the frameworks
3723 which are specific to TAVARUA.
3724 */
3725 retval = 0;
3726 break;
Anantha Krishnanf950e322012-06-06 14:25:49 +05303727 case V4L2_CID_PRIVATE_SPUR_FREQ:
3728 if (radio->spur_table_size >= MAX_SPUR_FREQ_LIMIT) {
3729 FMDERR("%s: Spur Table Full!\n", __func__);
3730 retval = -1;
3731 } else
3732 radio->spur_data.freq[radio->spur_table_size] =
3733 ctrl->value;
3734 break;
3735 case V4L2_CID_PRIVATE_SPUR_FREQ_RMSSI:
3736 if (radio->spur_table_size >= MAX_SPUR_FREQ_LIMIT) {
3737 FMDERR("%s: Spur Table Full!\n", __func__);
3738 retval = -1;
3739 } else
3740 radio->spur_data.rmssi[radio->spur_table_size] =
3741 ctrl->value;
3742 break;
3743 case V4L2_CID_PRIVATE_SPUR_SELECTION:
3744 if (radio->spur_table_size >= MAX_SPUR_FREQ_LIMIT) {
3745 FMDERR("%s: Spur Table Full!\n", __func__);
3746 retval = -1;
3747 } else {
3748 radio->spur_data.enable[radio->spur_table_size] =
3749 ctrl->value;
3750 radio->spur_table_size++;
3751 }
3752 break;
3753 case V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE:
3754 update_spur_table(radio);
3755 break;
Ayaz Ahmad37294ba2012-07-10 16:38:11 +05303756 case V4L2_CID_PRIVATE_VALID_CHANNEL:
3757 retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
3758 if (retval < 0) {
3759 FMDERR("%s: Failed to determine channel's validity\n",
3760 __func__);
3761 return retval;
3762 } else {
3763 sinr_th = radio->ch_det_threshold.sinr;
3764 intf_det_low_th = radio->ch_det_threshold.low_th;
3765 intf_det_high_th = radio->ch_det_threshold.high_th;
3766 }
3767
3768 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
3769 if (retval < 0) {
3770 FMDERR("%s: Failed to determine channel's validity\n",
3771 __func__);
3772 return retval;
3773 } else
3774 sinr = radio->fm_st_rsp.station_rsp.sinr;
3775
3776 retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
3777 if (retval < 0) {
3778 FMDERR("%s: Failed to determine channel's validity\n",
3779 __func__);
3780 return retval;
3781 } else
3782 intf_det_out = radio->st_dbg_param.in_det_out;
3783
3784 if ((sinr >= sinr_th) && (intf_det_out >= intf_det_low_th) &&
3785 (intf_det_out <= intf_det_high_th))
3786 radio->is_station_valid = VALID_CHANNEL;
3787 else
3788 radio->is_station_valid = INVALID_CHANNEL;
3789 break;
Ayaz Ahmaddb04b0c2013-02-01 17:18:34 +05303790 case V4L2_CID_PRIVATE_AF_RMSSI_TH:
3791 rd.mode = FM_RDS_CNFG_MODE;
3792 rd.length = FM_RDS_CNFG_LEN;
3793 rd.param_len = 0;
3794 rd.param = 0;
3795
3796 retval = hci_def_data_read(&rd, radio->fm_hdev);
3797 if (retval < 0) {
3798 FMDERR("default data read failed %x", retval);
3799 return retval;
3800 }
3801 wrd.mode = FM_RDS_CNFG_MODE;
3802 wrd.length = FM_RDS_CNFG_LEN;
3803 memcpy(&wrd.data, &radio->default_data.data,
3804 radio->default_data.ret_data_len);
3805 wrd.data[AF_RMSSI_TH_LSB_OFFSET] = ((ctrl->value) & 255);
3806 wrd.data[AF_RMSSI_TH_MSB_OFFSET] = ((ctrl->value) >> 8);
3807 retval = hci_def_data_write(&wrd, radio->fm_hdev);
3808 if (retval < 0)
3809 FMDERR("set AF jump RMSSI threshold failed\n");
3810 break;
3811 case V4L2_CID_PRIVATE_AF_RMSSI_SAMPLES:
3812 rd.mode = FM_RDS_CNFG_MODE;
3813 rd.length = FM_RDS_CNFG_LEN;
3814 rd.param_len = 0;
3815 rd.param = 0;
3816
3817 retval = hci_def_data_read(&rd, radio->fm_hdev);
3818 if (retval < 0) {
3819 FMDERR("default data read failed %x", retval);
3820 return retval;
3821 }
3822 wrd.mode = FM_RDS_CNFG_MODE;
3823 wrd.length = FM_RDS_CNFG_LEN;
3824 memcpy(&wrd.data, &radio->default_data.data,
3825 radio->default_data.ret_data_len);
3826 wrd.data[AF_RMSSI_SAMPLES_OFFSET] = ctrl->value;
3827 retval = hci_def_data_write(&wrd, radio->fm_hdev);
3828 if (retval < 0)
3829 FMDERR("set AF jump RMSSI Samples failed\n");
3830 break;
3831 case V4L2_CID_PRIVATE_GOOD_CH_RMSSI_TH:
3832 rd.mode = FM_RX_CONFG_MODE;
3833 rd.length = FM_RX_CNFG_LEN;
3834 rd.param_len = 0;
3835 rd.param = 0;
3836
3837 retval = hci_def_data_read(&rd, radio->fm_hdev);
3838 if (retval < 0) {
3839 FMDERR("default data read failed %x", retval);
3840 return retval;
3841 }
3842 wrd.mode = FM_RX_CONFG_MODE;
3843 wrd.length = FM_RX_CNFG_LEN;
3844 memcpy(&wrd.data, &radio->default_data.data,
3845 radio->default_data.ret_data_len);
3846 wrd.data[GD_CH_RMSSI_TH_OFFSET] = ctrl->value;
3847 retval = hci_def_data_write(&wrd, radio->fm_hdev);
3848 if (retval < 0)
3849 FMDERR("set good channel RMSSI th failed\n");
3850 break;
3851 case V4L2_CID_PRIVATE_SRCHALGOTYPE:
3852 rd.mode = FM_RX_CONFG_MODE;
3853 rd.length = FM_RX_CNFG_LEN;
3854 rd.param_len = 0;
3855 rd.param = 0;
3856
3857 retval = hci_def_data_read(&rd, radio->fm_hdev);
3858 if (retval < 0) {
3859 FMDERR("default data read failed %x", retval);
3860 return retval;
3861 }
3862 wrd.mode = FM_RX_CONFG_MODE;
3863 wrd.length = FM_RX_CNFG_LEN;
3864 memcpy(&wrd.data, &radio->default_data.data,
3865 radio->default_data.ret_data_len);
3866 wrd.data[SRCH_ALGO_TYPE_OFFSET] = ctrl->value;
3867 retval = hci_def_data_write(&wrd, radio->fm_hdev);
3868 if (retval < 0)
3869 FMDERR("set Search Algo Type failed\n");
3870 break;
3871 case V4L2_CID_PRIVATE_SINRFIRSTSTAGE:
3872 rd.mode = FM_RX_CONFG_MODE;
3873 rd.length = FM_RX_CNFG_LEN;
3874 rd.param_len = 0;
3875 rd.param = 0;
3876
3877 retval = hci_def_data_read(&rd, radio->fm_hdev);
3878 if (retval < 0) {
3879 FMDERR("default data read failed %x", retval);
3880 return retval;
3881 }
3882 wrd.mode = FM_RX_CONFG_MODE;
3883 wrd.length = FM_RX_CNFG_LEN;
3884 memcpy(&wrd.data, &radio->default_data.data,
3885 radio->default_data.ret_data_len);
3886 wrd.data[SINRFIRSTSTAGE_OFFSET] = ctrl->value;
3887 retval = hci_def_data_write(&wrd, radio->fm_hdev);
3888 if (retval < 0)
3889 FMDERR("set SINR First Stage failed\n");
3890 break;
3891 case V4L2_CID_PRIVATE_RMSSIFIRSTSTAGE:
3892 rd.mode = FM_RX_CONFG_MODE;
3893 rd.length = FM_RX_CNFG_LEN;
3894 rd.param_len = 0;
3895 rd.param = 0;
3896
3897 retval = hci_def_data_read(&rd, radio->fm_hdev);
3898 if (retval < 0) {
3899 FMDERR("default data read failed %x", retval);
3900 return retval;
3901 }
3902 wrd.mode = FM_RX_CONFG_MODE;
3903 wrd.length = FM_RX_CNFG_LEN;
3904 memcpy(&wrd.data, &radio->default_data.data,
3905 radio->default_data.ret_data_len);
3906 wrd.data[RMSSIFIRSTSTAGE_OFFSET] = ctrl->value;
3907 retval = hci_def_data_write(&wrd, radio->fm_hdev);
3908 if (retval < 0)
3909 FMDERR("set RMSSI First Stage failed\n");
3910 break;
3911 case V4L2_CID_PRIVATE_CF0TH12:
3912 rd.mode = FM_RX_CONFG_MODE;
3913 rd.length = FM_RX_CNFG_LEN;
3914 rd.param_len = 0;
3915 rd.param = 0;
3916
3917 retval = hci_def_data_read(&rd, radio->fm_hdev);
3918 if (retval < 0) {
3919 FMDERR("default data read failed %x", retval);
3920 return retval;
3921 }
3922 wrd.mode = FM_RX_CONFG_MODE;
3923 wrd.length = FM_RX_CNFG_LEN;
3924 memcpy(&wrd.data, &radio->default_data.data,
3925 radio->default_data.ret_data_len);
3926 wrd.data[CF0TH12_BYTE1_OFFSET] = (ctrl->value & 255);
3927 wrd.data[CF0TH12_BYTE2_OFFSET] = ((ctrl->value >> 8) & 255);
3928 wrd.data[CF0TH12_BYTE3_OFFSET] = ((ctrl->value >> 16) & 255);
3929 wrd.data[CF0TH12_BYTE4_OFFSET] = ((ctrl->value >> 24) & 255);
3930 retval = hci_def_data_write(&wrd, radio->fm_hdev);
3931 if (retval < 0)
3932 FMDERR("set CF0 Threshold failed\n");
3933 break;
Venkateshwarlu Domakonda70e47162013-04-30 14:12:13 +05303934 case V4L2_CID_PRIVATE_RXREPEATCOUNT:
3935 rd.mode = RDS_PS0_XFR_MODE;
3936 rd.length = RDS_PS0_LEN;
3937 rd.param_len = 0;
3938 rd.param = 0;
3939
3940 retval = hci_def_data_read(&rd, radio->fm_hdev);
3941 if (retval < 0) {
3942 FMDERR("default data read failed for PS0 %x", retval);
3943 return retval;
3944 }
3945 wrd.mode = RDS_PS0_XFR_MODE;
3946 wrd.length = RDS_PS0_LEN;
3947 memcpy(&wrd.data, &radio->default_data.data,
3948 radio->default_data.ret_data_len);
3949 wrd.data[RX_REPEATE_BYTE_OFFSET] = ctrl->value;
3950
3951 retval = hci_def_data_write(&wrd, radio->fm_hdev);
3952 if (retval < 0)
3953 FMDERR("set RxRePeat count failed\n");
3954 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003955 default:
3956 retval = -EINVAL;
3957 }
3958 return retval;
3959}
3960
Anantha Krishnanf950e322012-06-06 14:25:49 +05303961static int update_spur_table(struct iris_device *radio)
3962{
3963 struct hci_fm_def_data_wr_req default_data;
3964 int len = 0, index = 0, offset = 0, i = 0;
3965 int retval = 0, temp = 0, cnt = 0;
3966
3967 memset(&default_data, 0, sizeof(default_data));
3968
3969 /* Pass the mode of SPUR_CLK */
3970 default_data.mode = CKK_SPUR;
3971
Ayaz Ahmad53177572013-10-09 16:20:40 +05303972 if (radio == NULL) {
3973 FMDERR(":radio is null");
3974 return -EINVAL;
3975 }
Anantha Krishnanf950e322012-06-06 14:25:49 +05303976 temp = radio->spur_table_size;
3977 for (cnt = 0; cnt < (temp / 5); cnt++) {
3978 offset = 0;
3979 /*
3980 * Program the spur entries in spur table in following order:
3981 * Spur index
3982 * Length of the spur data
3983 * Spur Data:
3984 * MSB of the spur frequency
3985 * LSB of the spur frequency
3986 * Enable/Disable the spur frequency
3987 * RMSSI value of the spur frequency
3988 */
3989 default_data.data[offset++] = ENTRY_0 + cnt;
3990 for (i = 0; i < SPUR_ENTRIES_PER_ID; i++) {
3991 default_data.data[offset++] = GET_FREQ(COMPUTE_SPUR(
3992 radio->spur_data.freq[index]), 0);
3993 default_data.data[offset++] = GET_FREQ(COMPUTE_SPUR(
3994 radio->spur_data.freq[index]), 1);
3995 default_data.data[offset++] =
3996 radio->spur_data.enable[index];
3997 default_data.data[offset++] =
3998 radio->spur_data.rmssi[index];
3999 index++;
4000 }
4001 len = (SPUR_ENTRIES_PER_ID * SPUR_DATA_SIZE);
4002 default_data.length = (len + 1);
4003 retval = hci_def_data_write(&default_data, radio->fm_hdev);
4004 if (retval < 0) {
4005 FMDBG("%s: Failed to configure entries for ID : %d\n",
4006 __func__, default_data.data[0]);
4007 return retval;
4008 }
4009 }
4010
4011 /* Compute balance SPUR frequencies to be programmed */
4012 temp %= SPUR_ENTRIES_PER_ID;
4013 if (temp > 0) {
4014 offset = 0;
4015 default_data.data[offset++] = (radio->spur_table_size / 5);
4016 for (i = 0; i < temp; i++) {
4017 default_data.data[offset++] = GET_FREQ(COMPUTE_SPUR(
4018 radio->spur_data.freq[index]), 0);
4019 default_data.data[offset++] = GET_FREQ(COMPUTE_SPUR(
4020 radio->spur_data.freq[index]), 1);
4021 default_data.data[offset++] =
4022 radio->spur_data.enable[index];
4023 default_data.data[offset++] =
4024 radio->spur_data.rmssi[index];
4025 index++;
4026 }
4027 len = (temp * SPUR_DATA_SIZE);
4028 default_data.length = (len + 1);
4029 retval = hci_def_data_write(&default_data, radio->fm_hdev);
4030 if (retval < 0) {
4031 FMDERR("%s: Failed to configure entries for ID : %d\n",
4032 __func__, default_data.data[0]);
4033 return retval;
4034 }
4035 }
4036
4037 return retval;
4038}
4039
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004040static int iris_vidioc_g_tuner(struct file *file, void *priv,
4041 struct v4l2_tuner *tuner)
4042{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004043 int retval;
Ankur Nandwanid928d542011-08-11 13:15:41 -07004044 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004045
Ayaz Ahmad53177572013-10-09 16:20:40 +05304046 if (radio == NULL) {
4047 FMDERR(":radio is null");
4048 return -EINVAL;
4049 }
Srinivasa Rao Uppalad2ec4682011-12-12 14:02:15 +05304050 if (tuner->index > 0) {
4051 FMDERR("Invalid Tuner Index");
4052 return -EINVAL;
4053 }
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05304054 if (radio->mode == FM_RECV) {
4055 retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
4056 if (retval < 0) {
4057 FMDERR("Failed to Get station params");
4058 return retval;
4059 }
4060 tuner->type = V4L2_TUNER_RADIO;
4061 tuner->rangelow =
4062 radio->recv_conf.band_low_limit * TUNE_PARAM;
4063 tuner->rangehigh =
4064 radio->recv_conf.band_high_limit * TUNE_PARAM;
4065 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
4066 tuner->capability = V4L2_TUNER_CAP_LOW;
4067 tuner->signal = radio->fm_st_rsp.station_rsp.rssi;
4068 tuner->audmode = radio->fm_st_rsp.station_rsp.stereo_prg;
4069 tuner->afc = 0;
4070 } else if (radio->mode == FM_TRANS) {
4071 retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
4072 if (retval < 0) {
4073 FMDERR("get Tx config failed %d\n", retval);
4074 return retval;
4075 } else {
4076 tuner->type = V4L2_TUNER_RADIO;
4077 tuner->rangelow =
4078 radio->trans_conf.band_low_limit * TUNE_PARAM;
4079 tuner->rangehigh =
4080 radio->trans_conf.band_high_limit * TUNE_PARAM;
4081 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004082
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05304083 } else
4084 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004085 return 0;
4086}
4087
4088static int iris_vidioc_s_tuner(struct file *file, void *priv,
4089 struct v4l2_tuner *tuner)
4090{
4091 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Ankur Nandwanid928d542011-08-11 13:15:41 -07004092 int retval = 0;
Ayaz Ahmad53177572013-10-09 16:20:40 +05304093
4094 if (radio == NULL) {
4095 FMDERR(":radio is null");
4096 return -EINVAL;
4097 }
4098
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004099 if (tuner->index > 0)
4100 return -EINVAL;
4101
Ankur Nandwanid928d542011-08-11 13:15:41 -07004102 if (radio->mode == FM_RECV) {
4103 radio->recv_conf.band_low_limit = tuner->rangelow / TUNE_PARAM;
4104 radio->recv_conf.band_high_limit =
4105 tuner->rangehigh / TUNE_PARAM;
4106 if (tuner->audmode == V4L2_TUNER_MODE_MONO) {
4107 radio->stereo_mode.stereo_mode = 0x01;
4108 retval = hci_set_fm_stereo_mode(
4109 &radio->stereo_mode,
4110 radio->fm_hdev);
4111 } else {
4112 radio->stereo_mode.stereo_mode = 0x00;
4113 retval = hci_set_fm_stereo_mode(
4114 &radio->stereo_mode,
4115 radio->fm_hdev);
4116 }
4117 if (retval < 0)
4118 FMDERR(": set tuner failed with %d\n", retval);
4119 return retval;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05304120 } else if (radio->mode == FM_TRANS) {
Ankur Nandwanid928d542011-08-11 13:15:41 -07004121 radio->trans_conf.band_low_limit =
4122 tuner->rangelow / TUNE_PARAM;
4123 radio->trans_conf.band_high_limit =
4124 tuner->rangehigh / TUNE_PARAM;
Srinivasa Rao Uppalac5320c22011-11-28 14:28:51 +05304125 } else
4126 return -EINVAL;
Ankur Nandwanid928d542011-08-11 13:15:41 -07004127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004128 return retval;
4129}
4130
4131static int iris_vidioc_g_frequency(struct file *file, void *priv,
4132 struct v4l2_frequency *freq)
4133{
4134 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Srinivasa Rao Uppalad2ec4682011-12-12 14:02:15 +05304135 if ((freq != NULL) && (radio != NULL)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004136 freq->frequency =
4137 radio->fm_st_rsp.station_rsp.station_freq * TUNE_PARAM;
Srinivasa Rao Uppalad2ec4682011-12-12 14:02:15 +05304138 } else
4139 return -EINVAL;
4140 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004141}
4142
4143static int iris_vidioc_s_frequency(struct file *file, void *priv,
4144 struct v4l2_frequency *freq)
4145{
4146 struct iris_device *radio = video_get_drvdata(video_devdata(file));
4147 int retval = -1;
4148 freq->frequency = freq->frequency / TUNE_PARAM;
4149
Ayaz Ahmad53177572013-10-09 16:20:40 +05304150 if (radio == NULL) {
4151 FMDERR(":radio is null");
4152 return -EINVAL;
4153 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004154 if (freq->type != V4L2_TUNER_RADIO)
4155 return -EINVAL;
4156
Ankur Nandwani8f972e52011-08-24 11:48:32 -07004157 /* We turn off RDS prior to tuning to a new station.
4158 because of a bug in SoC which prevents tuning
4159 during RDS transmission.
4160 */
4161 if (radio->mode == FM_TRANS
4162 && (radio->trans_conf.rds_std == 0 ||
4163 radio->trans_conf.rds_std == 1)) {
4164 radio->prev_trans_rds = radio->trans_conf.rds_std;
4165 radio->trans_conf.rds_std = 2;
4166 hci_set_fm_trans_conf(&radio->trans_conf,
4167 radio->fm_hdev);
4168 }
4169
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004170 retval = iris_set_freq(radio, freq->frequency);
Ankur Nandwani8f972e52011-08-24 11:48:32 -07004171
4172 if (radio->mode == FM_TRANS
4173 && radio->trans_conf.rds_std == 2
4174 && (radio->prev_trans_rds == 1
4175 || radio->prev_trans_rds == 0)) {
4176 radio->trans_conf.rds_std = radio->prev_trans_rds;
4177 hci_set_fm_trans_conf(&radio->trans_conf,
4178 radio->fm_hdev);
4179 }
4180
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004181 if (retval < 0)
4182 FMDERR(" set frequency failed with %d\n", retval);
4183 return retval;
4184}
4185
Venkateshwarlu Domakonda4a15ec72013-02-28 18:03:36 +05304186static int iris_fops_release(struct file *file)
4187{
4188 struct iris_device *radio = video_get_drvdata(video_devdata(file));
4189 int retval = 0;
4190
4191 FMDBG("Enter %s ", __func__);
4192 if (radio == NULL)
4193 return -EINVAL;
4194
4195 if (radio->mode == FM_OFF)
4196 return 0;
4197
Venkateshwarlu Domakondab750fba2013-06-04 15:19:56 +05304198 if (radio->mode == FM_RECV) {
4199 radio->mode = FM_OFF;
Venkateshwarlu Domakonda4a15ec72013-02-28 18:03:36 +05304200 retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
4201 radio->fm_hdev);
Venkateshwarlu Domakondab750fba2013-06-04 15:19:56 +05304202 } else if (radio->mode == FM_TRANS) {
4203 radio->mode = FM_OFF;
Venkateshwarlu Domakonda4a15ec72013-02-28 18:03:36 +05304204 retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
4205 radio->fm_hdev);
Venkateshwarlu Domakondab750fba2013-06-04 15:19:56 +05304206 }
Venkateshwarlu Domakonda4a15ec72013-02-28 18:03:36 +05304207 if (retval < 0)
4208 FMDERR("Err on disable FM %d\n", retval);
4209
Venkateshwarlu Domakonda4a15ec72013-02-28 18:03:36 +05304210 return retval;
4211}
4212
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004213static int iris_vidioc_dqbuf(struct file *file, void *priv,
4214 struct v4l2_buffer *buffer)
4215{
4216 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Venkateshwarlu Domakonda7f095c42012-05-30 15:31:38 +05304217 enum iris_buf_t buf_type = -1;
4218 unsigned char buf_fifo[STD_BUF_SIZE] = {0};
4219 struct kfifo *data_fifo = NULL;
4220 unsigned char *buf = NULL;
4221 unsigned int len = 0, retval = -1;
4222
4223 if ((radio == NULL) || (buffer == NULL)) {
4224 FMDERR("radio/buffer is NULL\n");
4225 return -ENXIO;
4226 }
4227 buf_type = buffer->index;
4228 buf = (unsigned char *)buffer->m.userptr;
4229 len = buffer->length;
4230
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004231 if ((buf_type < IRIS_BUF_MAX) && (buf_type >= 0)) {
4232 data_fifo = &radio->data_buf[buf_type];
4233 if (buf_type == IRIS_BUF_EVENTS)
4234 if (wait_event_interruptible(radio->event_queue,
4235 kfifo_len(data_fifo)) < 0)
4236 return -EINTR;
4237 } else {
4238 FMDERR("invalid buffer type\n");
4239 return -EINVAL;
4240 }
Venkateshwarlu Domakonda7f095c42012-05-30 15:31:38 +05304241 if (len <= STD_BUF_SIZE) {
4242 buffer->bytesused = kfifo_out_locked(data_fifo, &buf_fifo[0],
4243 len, &radio->buf_lock[buf_type]);
4244 } else {
4245 FMDERR("kfifo_out_locked can not use len more than 128\n");
4246 return -EINVAL;
4247 }
4248 retval = copy_to_user(buf, &buf_fifo[0], buffer->bytesused);
4249 if (retval > 0) {
4250 FMDERR("Failed to copy %d bytes of data\n", retval);
4251 return -EAGAIN;
4252 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004253
Venkateshwarlu Domakonda7f095c42012-05-30 15:31:38 +05304254 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004255}
4256
4257static int iris_vidioc_g_fmt_type_private(struct file *file, void *priv,
4258 struct v4l2_format *f)
4259{
4260 return 0;
4261
4262}
4263
4264static int iris_vidioc_s_hw_freq_seek(struct file *file, void *priv,
4265 struct v4l2_hw_freq_seek *seek)
4266{
4267 struct iris_device *radio = video_get_drvdata(video_devdata(file));
Anantha Krishnand7b5a772012-04-30 04:21:03 -07004268 int dir;
4269 if (seek->seek_upward)
4270 dir = SRCH_DIR_UP;
4271 else
4272 dir = SRCH_DIR_DOWN;
4273 return iris_search(radio, CTRL_ON, dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004274}
4275
4276static int iris_vidioc_querycap(struct file *file, void *priv,
4277 struct v4l2_capability *capability)
4278{
4279 struct iris_device *radio;
4280 radio = video_get_drvdata(video_devdata(file));
Ayaz Ahmad53177572013-10-09 16:20:40 +05304281
4282 if (radio == NULL) {
4283 FMDERR(":radio is null");
4284 return -EINVAL;
4285 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004286 strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
4287 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
Venkateshwarlu Domakondac48f59d2013-07-23 16:55:04 +05304288 capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004289 radio->g_cap = capability;
4290 return 0;
4291}
4292
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05304293static int initialise_recv(struct iris_device *radio)
4294{
4295 int retval;
4296
Ayaz Ahmad53177572013-10-09 16:20:40 +05304297 if (radio == NULL) {
4298 FMDERR(":radio is null");
4299 return -EINVAL;
4300 }
4301
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05304302 radio->mute_mode.soft_mute = CTRL_ON;
4303 retval = hci_set_fm_mute_mode(&radio->mute_mode,
4304 radio->fm_hdev);
4305
4306 if (retval < 0) {
4307 FMDERR("Failed to enable Smute\n");
4308 return retval;
4309 }
4310
4311 radio->stereo_mode.stereo_mode = CTRL_OFF;
Sheng Fang8ec3c6f2013-08-12 14:09:14 +08004312 radio->stereo_mode.sig_blend = sig_blend;
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05304313 radio->stereo_mode.intf_blend = CTRL_ON;
4314 radio->stereo_mode.most_switch = CTRL_ON;
4315 retval = hci_set_fm_stereo_mode(&radio->stereo_mode,
4316 radio->fm_hdev);
4317
4318 if (retval < 0) {
4319 FMDERR("Failed to set stereo mode\n");
4320 return retval;
4321 }
4322
4323 radio->event_mask = SIG_LEVEL_INTR | RDS_SYNC_INTR | AUDIO_CTRL_INTR;
4324 retval = hci_conf_event_mask(&radio->event_mask, radio->fm_hdev);
4325 if (retval < 0) {
4326 FMDERR("Enable Async events failed");
4327 return retval;
4328 }
4329
4330 retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD, radio->fm_hdev);
4331 if (retval < 0)
4332 FMDERR("Failed to get the Recv Config\n");
4333 return retval;
4334}
4335
4336static int initialise_trans(struct iris_device *radio)
4337{
4338
Ayaz Ahmad53177572013-10-09 16:20:40 +05304339 int retval;
4340
4341 if (radio == NULL) {
4342 FMDERR(":radio is null");
4343 return -EINVAL;
4344 }
4345
4346 retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05304347 if (retval < 0)
4348 FMDERR("get frequency failed %d\n", retval);
4349
4350 return retval;
4351}
4352
4353static int is_enable_rx_possible(struct iris_device *radio)
4354{
4355 int retval = 1;
4356
Ayaz Ahmad53177572013-10-09 16:20:40 +05304357 if (radio == NULL) {
4358 FMDERR(":radio is null");
4359 return -EINVAL;
4360 }
4361
Ayaz Ahmad64b1e472013-06-04 15:19:56 +05304362 if (radio->mode == FM_OFF || radio->mode == FM_RECV)
4363 retval = 0;
4364
4365 return retval;
4366}
4367
4368static int is_enable_tx_possible(struct iris_device *radio)
4369{
4370 int retval = 1;
4371
4372 if (radio->mode == FM_OFF || radio->mode == FM_TRANS)
4373 retval = 0;
4374
4375 return retval;
4376}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004377
4378static const struct v4l2_ioctl_ops iris_ioctl_ops = {
4379 .vidioc_querycap = iris_vidioc_querycap,
4380 .vidioc_queryctrl = iris_vidioc_queryctrl,
4381 .vidioc_g_ctrl = iris_vidioc_g_ctrl,
4382 .vidioc_s_ctrl = iris_vidioc_s_ctrl,
4383 .vidioc_g_tuner = iris_vidioc_g_tuner,
4384 .vidioc_s_tuner = iris_vidioc_s_tuner,
4385 .vidioc_g_frequency = iris_vidioc_g_frequency,
4386 .vidioc_s_frequency = iris_vidioc_s_frequency,
4387 .vidioc_s_hw_freq_seek = iris_vidioc_s_hw_freq_seek,
4388 .vidioc_dqbuf = iris_vidioc_dqbuf,
4389 .vidioc_g_fmt_type_private = iris_vidioc_g_fmt_type_private,
4390 .vidioc_s_ext_ctrls = iris_vidioc_s_ext_ctrls,
Venkateshwarlu Domakonda787af692011-10-14 21:23:03 +05304391 .vidioc_g_ext_ctrls = iris_vidioc_g_ext_ctrls,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004392};
4393
4394static const struct v4l2_file_operations iris_fops = {
4395 .owner = THIS_MODULE,
4396 .unlocked_ioctl = video_ioctl2,
Venkateshwarlu Domakonda4a15ec72013-02-28 18:03:36 +05304397 .release = iris_fops_release,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004398};
4399
4400static struct video_device iris_viddev_template = {
4401 .fops = &iris_fops,
4402 .ioctl_ops = &iris_ioctl_ops,
4403 .name = DRIVER_NAME,
4404 .release = video_device_release,
4405};
4406
4407static struct video_device *video_get_dev(void)
4408{
4409 return priv_videodev;
4410}
4411
4412static int __init iris_probe(struct platform_device *pdev)
4413{
4414 struct iris_device *radio;
4415 int retval;
4416 int radio_nr = -1;
4417 int i;
4418
4419 if (!pdev) {
4420 FMDERR(": pdev is null\n");
4421 return -ENOMEM;
4422 }
4423
4424 radio = kzalloc(sizeof(struct iris_device), GFP_KERNEL);
4425 if (!radio) {
4426 FMDERR(": Could not allocate radio device\n");
4427 return -ENOMEM;
4428 }
4429
4430 radio->dev = &pdev->dev;
4431 platform_set_drvdata(pdev, radio);
4432
4433 radio->videodev = video_device_alloc();
4434 if (!radio->videodev) {
4435 FMDERR(": Could not allocate V4L device\n");
4436 kfree(radio);
4437 return -ENOMEM;
4438 }
4439
4440 memcpy(radio->videodev, &iris_viddev_template,
4441 sizeof(iris_viddev_template));
4442
4443 for (i = 0; i < IRIS_BUF_MAX; i++) {
4444 int kfifo_alloc_rc = 0;
4445 spin_lock_init(&radio->buf_lock[i]);
4446
Srinivasa Rao Uppala6cc0e322011-08-12 10:54:48 -07004447 if ((i == IRIS_BUF_RAW_RDS) || (i == IRIS_BUF_PEEK))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004448 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
4449 rds_buf*3, GFP_KERNEL);
Srinivasa Rao Uppala69839842012-01-13 18:36:12 +05304450 else if ((i == IRIS_BUF_CAL_DATA) || (i == IRIS_BUF_RT_RDS))
Venkateshwarlu Domakonda3a0b75d2011-11-23 17:03:27 +05304451 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
4452 STD_BUF_SIZE*2, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004453 else
4454 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
4455 STD_BUF_SIZE, GFP_KERNEL);
4456
4457 if (kfifo_alloc_rc != 0) {
4458 FMDERR("failed allocating buffers %d\n",
4459 kfifo_alloc_rc);
4460 for (; i > -1; i--) {
4461 kfifo_free(&radio->data_buf[i]);
4462 kfree(radio);
4463 return -ENOMEM;
4464 }
4465 }
4466 }
4467
4468 mutex_init(&radio->lock);
4469 init_completion(&radio->sync_xfr_start);
4470 radio->tune_req = 0;
Ankur Nandwani8f972e52011-08-24 11:48:32 -07004471 radio->prev_trans_rds = 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004472 init_waitqueue_head(&radio->event_queue);
4473 init_waitqueue_head(&radio->read_queue);
4474
4475 video_set_drvdata(radio->videodev, radio);
4476
4477 if (NULL == video_get_drvdata(radio->videodev))
4478 FMDERR(": video_get_drvdata failed\n");
4479
4480 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
4481 radio_nr);
4482 if (retval) {
4483 FMDERR(": Could not register video device\n");
4484 video_device_release(radio->videodev);
4485 for (; i > -1; i--)
4486 kfifo_free(&radio->data_buf[i]);
4487 kfree(radio);
4488 return retval;
4489 } else {
4490 priv_videodev = kzalloc(sizeof(struct video_device),
4491 GFP_KERNEL);
4492 memcpy(priv_videodev, radio->videodev,
4493 sizeof(struct video_device));
4494 }
4495 return 0;
4496}
4497
4498
4499static int __devexit iris_remove(struct platform_device *pdev)
4500{
4501 int i;
4502 struct iris_device *radio = platform_get_drvdata(pdev);
4503
Ayaz Ahmad53177572013-10-09 16:20:40 +05304504 if (radio == NULL) {
4505 FMDERR(":radio is null");
4506 return -EINVAL;
4507 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004508 video_unregister_device(radio->videodev);
4509
4510 for (i = 0; i < IRIS_BUF_MAX; i++)
4511 kfifo_free(&radio->data_buf[i]);
4512
4513 kfree(radio);
4514
4515 platform_set_drvdata(pdev, NULL);
4516
4517 return 0;
4518}
4519
Venkateshwarlu Domakonda54ec3252013-02-18 21:25:57 +05304520static const struct of_device_id iris_fm_match[] = {
4521 {.compatible = "qcom,iris_fm"},
4522 {}
4523};
4524
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004525static struct platform_driver iris_driver = {
4526 .driver = {
4527 .owner = THIS_MODULE,
4528 .name = "iris_fm",
Venkateshwarlu Domakonda54ec3252013-02-18 21:25:57 +05304529 .of_match_table = iris_fm_match,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004530 },
4531 .remove = __devexit_p(iris_remove),
4532};
4533
4534static int __init iris_radio_init(void)
4535{
4536 return platform_driver_probe(&iris_driver, iris_probe);
4537}
4538module_init(iris_radio_init);
4539
4540static void __exit iris_radio_exit(void)
4541{
4542 platform_driver_unregister(&iris_driver);
4543}
4544module_exit(iris_radio_exit);
4545
4546MODULE_LICENSE("GPL v2");
4547MODULE_AUTHOR(DRIVER_AUTHOR);
4548MODULE_DESCRIPTION(DRIVER_DESC);