blob: 116b7f9187b2aefdc20e045f4267569fe89b26d0 [file] [log] [blame]
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301/* Copyright (c) 2009-2012, Code Aurora Forum. 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/*
14 * Qualcomm Tavarua FM core driver
15 */
16
17/* driver definitions */
18#define DRIVER_AUTHOR "Qualcomm"
19#define DRIVER_NAME "radio-tavarua"
20#define DRIVER_CARD "Qualcomm FM Radio Transceiver"
21#define DRIVER_DESC "I2C radio driver for Qualcomm FM Radio Transceiver "
22#define DRIVER_VERSION "1.0.0"
23
24#include <linux/version.h>
25#include <linux/init.h> /* Initdata */
26#include <linux/delay.h> /* udelay */
27#include <linux/uaccess.h> /* copy to/from user */
28#include <linux/kfifo.h> /* lock free circular buffer */
29#include <linux/param.h>
30#include <linux/i2c.h>
31#include <linux/irq.h>
32#include <linux/interrupt.h>
33
34/* kernel includes */
35#include <linux/kernel.h>
36#include <linux/module.h>
37#include <linux/version.h>
38#include <linux/videodev2.h>
39#include <linux/mutex.h>
40#include <media/v4l2-common.h>
41#include <asm/unaligned.h>
42#include <media/v4l2-ioctl.h>
43#include <linux/unistd.h>
44#include <asm/atomic.h>
45#include <media/tavarua.h>
46#include <linux/mfd/marimba.h>
47#include <linux/platform_device.h>
48#include <linux/workqueue.h>
49#include <linux/slab.h>
50/*
51regional parameters for radio device
52*/
53struct region_params_t {
54 enum tavarua_region_t region;
55 unsigned int band_high;
56 unsigned int band_low;
57 char emphasis;
58 char rds_std;
59 char spacing;
60};
61
62struct srch_params_t {
63 unsigned short srch_pi;
64 unsigned char srch_pty;
65 unsigned int preset_num;
66 int get_list;
67};
68
69/* Main radio device structure,
70acts as a shadow copy of the
71actual tavaura registers */
72struct tavarua_device {
73 struct video_device *videodev;
74 /* driver management */
Anantha Krishnana2f98082011-10-04 20:02:11 +053075 atomic_t users;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070076 /* top level driver data */
77 struct marimba *marimba;
78 struct device *dev;
79 /* platform specific functionality */
80 struct marimba_fm_platform_data *pdata;
81 unsigned int chipID;
82 /*RDS buffers + Radio event buffer*/
83 struct kfifo data_buf[TAVARUA_BUF_MAX];
84 /* search paramters */
85 struct srch_params_t srch_params;
86 /* keep track of pending xfrs */
87 int pending_xfrs[TAVARUA_XFR_MAX];
88 int xfr_bytes_left;
89 int xfr_in_progress;
90 /* Transmit data */
91 enum tavarua_xfr_ctrl_t tx_mode;
92 /* synchrnous xfr data */
93 unsigned char sync_xfr_regs[XFR_REG_NUM];
94 struct completion sync_xfr_start;
Taniya Das9ac855f2012-02-09 18:05:21 +053095 struct completion shutdown_done;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070096 struct completion sync_req_done;
97 int tune_req;
98 /* internal register status */
99 unsigned char registers[RADIO_REGISTERS];
100 /* regional settings */
101 struct region_params_t region_params;
102 /* power mode */
103 int lp_mode;
104 int handle_irq;
105 /* global lock */
106 struct mutex lock;
107 /* buffer locks*/
108 spinlock_t buf_lock[TAVARUA_BUF_MAX];
109 /* work queue */
110 struct workqueue_struct *wqueue;
111 struct delayed_work work;
112 /* wait queue for blocking event read */
113 wait_queue_head_t event_queue;
114 /* wait queue for raw rds read */
115 wait_queue_head_t read_queue;
116 /* PTY for FM Tx */
117 int pty;
118 /* PI for FM TX */
119 int pi;
120 /*PS repeatcount for PS Tx */
121 int ps_repeatcount;
Anantha Krishnan40bcd052011-12-05 15:28:29 +0530122 int enable_optimized_srch_alg;
Anantha Krishnan93eb1762012-06-04 13:41:07 +0530123 unsigned char spur_table_size;
124 struct fm_spur_data spur_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700125};
126
127/**************************************************************************
128 * Module Parameters
129 **************************************************************************/
130
131/* Radio Nr */
132static int radio_nr = -1;
133module_param(radio_nr, int, 0);
134MODULE_PARM_DESC(radio_nr, "Radio Nr");
135static int wait_timeout = WAIT_TIMEOUT;
136/* Bahama's version*/
137static u8 bahama_version;
138/* RDS buffer blocks */
139static unsigned int rds_buf = 100;
140module_param(rds_buf, uint, 0);
141MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
142/* static variables */
143static struct tavarua_device *private_data;
144/* forward declerations */
145static int tavarua_disable_interrupts(struct tavarua_device *radio);
146static int tavarua_setup_interrupts(struct tavarua_device *radio,
147 enum radio_state_t state);
148static int tavarua_start(struct tavarua_device *radio,
149 enum radio_state_t state);
150static int tavarua_request_irq(struct tavarua_device *radio);
151static void start_pending_xfr(struct tavarua_device *radio);
Anantha Krishnan93eb1762012-06-04 13:41:07 +0530152static int update_spur_table(struct tavarua_device *radio);
153static int xfr_rdwr_data(struct tavarua_device *radio, int op, int size,
154 unsigned long offset, unsigned char *buf);
155
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700156/* work function */
157static void read_int_stat(struct work_struct *work);
158
159static int is_bahama(void)
160{
161 int id = 0;
162
163 switch (id = adie_get_detected_connectivity_type()) {
164 case BAHAMA_ID:
165 FMDBG("It is Bahama\n");
166 return 1;
167
168 case MARIMBA_ID:
169 FMDBG("It is Marimba\n");
170 return 0;
171 default:
172 printk(KERN_ERR "%s: unexpected adie connectivity type: %d\n",
173 __func__, id);
174 return -ENODEV;
175 }
176}
177
178static int set_fm_slave_id(struct tavarua_device *radio)
179{
180 int bahama_present = is_bahama();
181
182 if (bahama_present == -ENODEV)
183 return -ENODEV;
184
185 if (bahama_present)
186 radio->marimba->mod_id = SLAVE_ID_BAHAMA_FM;
187 else
188 radio->marimba->mod_id = MARIMBA_SLAVE_ID_FM;
189
190 return 0;
191}
192
193/*=============================================================================
194FUNCTION: tavarua_isr
195=============================================================================*/
196/**
197 This function is called when GPIO is toggled. This functions queues the event
198 to interrupt queue, which is later handled by isr handling funcion.
199 i.e. INIT_DELAYED_WORK(&radio->work, read_int_stat);
200
201 @param irq: irq that is toggled.
202 @param dev_id: structure pointer passed by client.
203
204 @return IRQ_HANDLED.
205*/
206static irqreturn_t tavarua_isr(int irq, void *dev_id)
207{
208 struct tavarua_device *radio = dev_id;
209 /* schedule a tasklet to handle host intr */
210 /* The call to queue_delayed_work ensures that a minimum delay (in jiffies)
211 * passes before the work is actually executed. The return value from the
212 * function is nonzero if the work_struct was actually added to queue
213 * (otherwise, it may have already been there and will not be added a second
214 * time).
215 */
216 queue_delayed_work(radio->wqueue, &radio->work,
217 msecs_to_jiffies(TAVARUA_DELAY));
218 return IRQ_HANDLED;
219}
220
221/**************************************************************************
222 * Interface to radio internal registers over top level marimba driver
223 *************************************************************************/
224
225/*=============================================================================
226FUNCTION: tavarua_read_registers
227=============================================================================*/
228/**
229 This function is called to read a number of bytes from an I2C interface.
230 The bytes read are stored in internal register status (shadow copy).
231
232 @param radio: structure pointer passed by client.
233 @param offset: register offset.
234 @param len: num of bytes.
235
236 @return => 0 if successful.
237 @return < 0 if failure.
238*/
239static int tavarua_read_registers(struct tavarua_device *radio,
240 unsigned char offset, int len)
241{
242 int retval = 0, i = 0;
243 retval = set_fm_slave_id(radio);
244
245 if (retval == -ENODEV)
246 return retval;
247
248 FMDBG_I2C("I2C Slave: %x, Read Offset(%x): Data [",
249 radio->marimba->mod_id,
250 offset);
251
252 retval = marimba_read(radio->marimba, offset,
253 &radio->registers[offset], len);
254
255 if (retval > 0) {
256 for (i = 0; i < len; i++)
257 FMDBG_I2C("%02x ", radio->registers[offset+i]);
258 FMDBG_I2C(" ]\n");
259
260 }
261 return retval;
262}
263
264/*=============================================================================
265FUNCTION: tavarua_write_register
266=============================================================================*/
267/**
268 This function is called to write a byte over the I2C interface.
269 The corresponding shadow copy is stored in internal register status.
270
271 @param radio: structure pointer passed by client.
272 @param offset: register offset.
273 @param value: buffer to be written to the registers.
274
275 @return => 0 if successful.
276 @return < 0 if failure.
277*/
278static int tavarua_write_register(struct tavarua_device *radio,
279 unsigned char offset, unsigned char value)
280{
281 int retval;
282 retval = set_fm_slave_id(radio);
283
284 if (retval == -ENODEV)
285 return retval;
286
287 FMDBG_I2C("I2C Slave: %x, Write Offset(%x): Data[",
288 radio->marimba->mod_id,
289 offset);
290 retval = marimba_write(radio->marimba, offset, &value, 1);
291 if (retval > 0) {
292 if (offset < RADIO_REGISTERS) {
293 radio->registers[offset] = value;
294 FMDBG_I2C("%02x ", radio->registers[offset]);
295 }
296 FMDBG_I2C(" ]\n");
297 }
298 return retval;
299}
300
301/*=============================================================================
302FUNCTION: tavarua_write_registers
303=============================================================================*/
304/**
305 This function is called to write a number of bytes over the I2C interface.
306 The corresponding shadow copy is stored in internal register status.
307
308 @param radio: structure pointer passed by client.
309 @param offset: register offset.
310 @param buf: buffer to be written to the registers.
311 @param len: num of bytes.
312
313 @return => 0 if successful.
314 @return < 0 if failure.
315*/
316static int tavarua_write_registers(struct tavarua_device *radio,
317 unsigned char offset, unsigned char *buf, int len)
318{
319
320 int i;
321 int retval;
322 retval = set_fm_slave_id(radio);
323
324 if (retval == -ENODEV)
325 return retval;
326
327 FMDBG_I2C("I2C Slave: %x, Write Offset(%x): Data[",
328 radio->marimba->mod_id,
329 offset);
330 retval = marimba_write(radio->marimba, offset, buf, len);
331 if (retval > 0) { /* if write successful, update internal state too */
332 for (i = 0; i < len; i++) {
333 if ((offset+i) < RADIO_REGISTERS) {
334 radio->registers[offset+i] = buf[i];
335 FMDBG_I2C("%x ", radio->registers[offset+i]);
336 }
337 }
338 FMDBG_I2C(" ]\n");
339 }
340 return retval;
341}
342
343/*=============================================================================
344FUNCTION: read_data_blocks
345=============================================================================*/
346/**
347 This function reads Raw RDS blocks from Core regs to driver
348 internal regs (shadow copy).
349
350 @param radio: structure pointer passed by client.
351 @param offset: register offset.
352
353 @return => 0 if successful.
354 @return < 0 if failure.
355*/
356static int read_data_blocks(struct tavarua_device *radio, unsigned char offset)
357{
358 /* read all 3 RDS blocks */
359 return tavarua_read_registers(radio, offset, RDS_BLOCK*4);
360}
361
362/*=============================================================================
363FUNCTION: tavarua_rds_read
364=============================================================================*/
365/**
366 This is a rds processing function reads that reads Raw RDS blocks from Core
367 regs to driver internal regs (shadow copy). It then fills the V4L2 RDS buffer,
368 which is read by App using JNI interface.
369
370 @param radio: structure pointer passed by client.
371
372 @return None.
373*/
374static void tavarua_rds_read(struct tavarua_device *radio)
375{
376 struct kfifo *rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
377 unsigned char blocknum;
378 unsigned char tmp[3];
379
380 if (read_data_blocks(radio, RAW_RDS) < 0)
381 return;
382 /* copy all four RDS blocks to internal buffer */
383 for (blocknum = 0; blocknum < RDS_BLOCKS_NUM; blocknum++) {
384 /* Fill the V4L2 RDS buffer */
385 put_unaligned(cpu_to_le16(radio->registers[RAW_RDS +
386 blocknum*RDS_BLOCK]), (unsigned short *) tmp);
387 tmp[2] = blocknum; /* offset name */
388 tmp[2] |= blocknum << 3; /* received offset */
389 tmp[2] |= 0x40; /* corrected error(s) */
390
391 /* copy RDS block to internal buffer */
392 kfifo_in_locked(rds_buf, tmp, 3, &radio->buf_lock[TAVARUA_BUF_RAW_RDS]);
393 }
394 /* wake up read queue */
395 if (kfifo_len(rds_buf))
396 wake_up_interruptible(&radio->read_queue);
397
398}
399
400/*=============================================================================
401FUNCTION: request_read_xfr
402=============================================================================*/
403/**
404 This function sets the desired MODE in the XFRCTRL register and also sets the
405 CTRL field to read.
406 This is an asynchronous way of reading the XFR registers. Client would request
407 by setting the desired mode in the XFRCTRL register and then would initiate
408 the actual data register read by calling copy_from_xfr up on SOC signals
409 success.
410
411 NOTE:
412
413 The Data Transfer (XFR) registers are used to pass various data and
414 configuration parameters between the Core and host processor.
415
416 To read from the XFR registers, the host processor must set the desired MODE
417 in the XFRCTRL register and set the CTRL field to read. The Core will then
418 populate the XFRDAT0 - XFRDAT15 registers with the defined mode bytes. The
419 Core will set the TRANSFER interrupt status bit and interrupt the host if the
420 TRANSFERCTRL interrupt control bit is set. The host can then extract the XFR
421 mode bytes once it detects that the Core has updated the registers.
422
423 @param radio: structure pointer passed by client.
424
425 @return Always returns 0.
426*/
427static int request_read_xfr(struct tavarua_device *radio,
428 enum tavarua_xfr_ctrl_t mode){
429
430 tavarua_write_register(radio, XFRCTRL, mode);
431 msleep(TAVARUA_DELAY);
432 return 0;
433}
434
435/*=============================================================================
436FUNCTION: copy_from_xfr
437=============================================================================*/
438/**
439 This function is used to read XFR mode bytes once it detects that the Core
440 has updated the registers. It also updates XFR regs to the appropriate
441 internal buffer n bytes.
442
443 NOTE:
444
445 This function should be used in conjuction with request_read_xfr. Refer
446 request_read_xfr for XFR mode transaction details.
447
448 @param radio: structure pointer passed by client.
449 @param buf_type: Index into RDS/Radio event buffer to use.
450 @param len: num of bytes.
451
452 @return Always returns 0.
453*/
454static int copy_from_xfr(struct tavarua_device *radio,
455 enum tavarua_buf_t buf_type, unsigned int n){
456
457 struct kfifo *data_fifo = &radio->data_buf[buf_type];
458 unsigned char *xfr_regs = &radio->registers[XFRCTRL+1];
459 kfifo_in_locked(data_fifo, xfr_regs, n, &radio->buf_lock[buf_type]);
460 return 0;
461}
462
463/*=============================================================================
464FUNCTION: write_to_xfr
465=============================================================================*/
466/**
467 This function sets the desired MODE in the XFRCTRL register and it also sets
468 the CTRL field and data to write.
469 This also writes all the XFRDATx registers with the desired input buffer.
470
471 NOTE:
472
473 The Data Transfer (XFR) registers are used to pass various data and
474 configuration parameters between the Core and host processor.
475
476 To write data to the Core, the host processor updates XFRDAT0 - XFRDAT15 with
477 the appropriate mode bytes. The host processor must then set the desired MODE
478 in the XFRCTRL register and set the CTRL field to write. The core will detect
479 that the XFRCTRL register was written to and will read the XFR mode bytes.
480 After reading all the mode bytes, the Core will set the TRANSFER interrupt
481 status bit and interrupt the host if the TRANSFERCTRL interrupt control bit
482 is set.
483
484 @param radio: structure pointer passed by client.
485 @param mode: XFR mode to write in XFRCTRL register.
486 @param buf: buffer to be written to the registers.
487 @param len: num of bytes.
488
489 @return => 0 if successful.
490 @return < 0 if failure.
491*/
492static int write_to_xfr(struct tavarua_device *radio, unsigned char mode,
493 char *buf, int len)
494{
495 char buffer[len+1];
496 memcpy(buffer+1, buf, len);
497 /* buffer[0] corresponds to XFRCTRL register
498 set the CTRL bit to 1 for write mode
499 */
500 buffer[0] = ((1<<7) | mode);
501 return tavarua_write_registers(radio, XFRCTRL, buffer, sizeof(buffer));
502}
503
504/*=============================================================================
505FUNCTION: xfr_intf_own
506=============================================================================*/
507/**
508 This function is used to check if there is any pending XFR mode operation.
509 If yes, wait for it to complete, else update the flag to indicate XFR
510 operation is in progress
511
512 @param radio: structure pointer passed by client.
513
514 @return 0 on success.
515 -ETIME on timeout.
516*/
517static int xfr_intf_own(struct tavarua_device *radio)
518{
519
520 mutex_lock(&radio->lock);
521 if (radio->xfr_in_progress) {
522 radio->pending_xfrs[TAVARUA_XFR_SYNC] = 1;
523 mutex_unlock(&radio->lock);
524 if (!wait_for_completion_timeout(&radio->sync_xfr_start,
525 msecs_to_jiffies(wait_timeout)))
526 return -ETIME;
527 } else {
528 FMDBG("gained ownership of xfr\n");
529 radio->xfr_in_progress = 1;
530 mutex_unlock(&radio->lock);
531 }
532 return 0;
533}
534
535/*=============================================================================
536FUNCTION: sync_read_xfr
537=============================================================================*/
538/**
539 This function is used to do synchronous XFR read operation.
540
541 @param radio: structure pointer passed by client.
542 @param xfr_type: XFR mode to write in XFRCTRL register.
543 @param buf: buffer to be read from the core.
544
545 @return => 0 if successful.
546 @return < 0 if failure.
547*/
548static int sync_read_xfr(struct tavarua_device *radio,
549 enum tavarua_xfr_ctrl_t xfr_type, unsigned char *buf)
550{
551 int retval;
552 retval = xfr_intf_own(radio);
553 if (retval < 0)
554 return retval;
555 retval = tavarua_write_register(radio, XFRCTRL, xfr_type);
556
557 if (retval >= 0) {
558 /* Wait for interrupt i.e. complete
559 (&radio->sync_req_done); call */
560 if (!wait_for_completion_timeout(&radio->sync_req_done,
561 msecs_to_jiffies(wait_timeout)) || (retval < 0)) {
562 retval = -ETIME;
563 } else {
564 memcpy(buf, radio->sync_xfr_regs, XFR_REG_NUM);
565 }
566 }
567 radio->xfr_in_progress = 0;
568 start_pending_xfr(radio);
569 FMDBG("%s: %d\n", __func__, retval);
570 return retval;
571}
572
573/*=============================================================================
574FUNCTION: sync_write_xfr
575=============================================================================*/
576/**
577 This function is used to do synchronous XFR write operation.
578
579 @param radio: structure pointer passed by client.
580 @param xfr_type: XFR mode to write in XFRCTRL register.
581 @param buf: buffer to be written to the core.
582
583 @return => 0 if successful.
584 @return < 0 if failure.
585*/
586static int sync_write_xfr(struct tavarua_device *radio,
587 enum tavarua_xfr_ctrl_t xfr_type, unsigned char *buf)
588{
589 int retval;
590 retval = xfr_intf_own(radio);
591 if (retval < 0)
592 return retval;
593 retval = write_to_xfr(radio, xfr_type, buf, XFR_REG_NUM);
594
595 if (retval >= 0) {
596 /* Wait for interrupt i.e. complete
597 (&radio->sync_req_done); call */
598 if (!wait_for_completion_timeout(&radio->sync_req_done,
599 msecs_to_jiffies(wait_timeout)) || (retval < 0)) {
600 FMDBG("Write xfr timeout");
601 }
602 }
603 radio->xfr_in_progress = 0;
604 start_pending_xfr(radio);
605 FMDBG("%s: %d\n", __func__, retval);
606 return retval;
607}
608
609
610/*=============================================================================
611FUNCTION: start_pending_xfr
612=============================================================================*/
613/**
614 This function checks if their are any pending xfr interrupts and if
615 the interrupts are either RDS PS, RDS RT, RDS AF, SCANNEXT, SEARCH or SYNC
616 then initiates corresponding read operation. Preference is given to RAW RDS
617 data (SYNC) over processed data (PS, RT, AF, etc) from core.
618
619 @param radio: structure pointer passed by client.
620
621 @return None.
622*/
623static void start_pending_xfr(struct tavarua_device *radio)
624{
625 int i;
626 enum tavarua_xfr_t xfr;
627 for (i = 0; i < TAVARUA_XFR_MAX; i++) {
628 if (radio->pending_xfrs[i]) {
629 radio->xfr_in_progress = 1;
630 xfr = (enum tavarua_xfr_t)i;
631 switch (xfr) {
632 /* priority given to synchronous xfrs */
633 case TAVARUA_XFR_SYNC:
634 complete(&radio->sync_xfr_start);
635 break;
636 /* asynchrnous xfrs */
637 case TAVARUA_XFR_SRCH_LIST:
638 request_read_xfr(radio, RX_STATIONS_0);
639 break;
640 case TAVARUA_XFR_RT_RDS:
641 request_read_xfr(radio, RDS_RT_0);
642 break;
643 case TAVARUA_XFR_PS_RDS:
644 request_read_xfr(radio, RDS_PS_0);
645 break;
646 case TAVARUA_XFR_AF_LIST:
647 request_read_xfr(radio, RDS_AF_0);
648 break;
649 default:
650 FMDERR("%s: Unsupported XFR %d\n",
651 __func__, xfr);
652 }
653 radio->pending_xfrs[i] = 0;
654 FMDBG("resurrect xfr %d\n", i);
655 }
656 }
657 return;
658}
659
660/*=============================================================================
661FUNCTION: tavarua_q_event
662=============================================================================*/
663/**
664 This function is called to queue an event for user.
665
666 NOTE:
667 Applications call the VIDIOC_QBUF ioctl to enqueue an empty (capturing) or
668 filled (output) buffer in the driver's incoming queue.
669
670 Pleaes refer tavarua_probe where we register different ioctl's for FM.
671
672 @param radio: structure pointer passed by client.
673 @param event: event to be queued.
674
675 @return None.
676*/
677static void tavarua_q_event(struct tavarua_device *radio,
678 enum tavarua_evt_t event)
679{
680
681 struct kfifo *data_b = &radio->data_buf[TAVARUA_BUF_EVENTS];
682 unsigned char evt = event;
683 FMDBG("updating event_q with event %x\n", event);
684 if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[TAVARUA_BUF_EVENTS]))
685 wake_up_interruptible(&radio->event_queue);
686}
687
688/*=============================================================================
689FUNCTION: tavarua_start_xfr
690=============================================================================*/
691/**
692 This function is called to process interrupts which require multiple XFR
693 operations (RDS search, RDS PS, RDS RT, etc). if any XFR operation is
694 already in progress we store information about pending interrupt, which
695 will be processed in future when current pending operation is done.
696
697 @param radio: structure pointer passed by client.
698 @param pending_id: XFR operation (which requires multiple XFR operations in
699 steps) to start.
700 @param xfr_id: XFR mode to write in XFRCTRL register.
701
702 @return None.
703*/
704static void tavarua_start_xfr(struct tavarua_device *radio,
705 enum tavarua_xfr_t pending_id, enum tavarua_xfr_ctrl_t xfr_id)
706{
707 if (radio->xfr_in_progress)
708 radio->pending_xfrs[pending_id] = 1;
709 else {
710 radio->xfr_in_progress = 1;
711 request_read_xfr(radio, xfr_id);
712 }
713}
714
715/*=============================================================================
716FUNCTION: tavarua_handle_interrupts
717=============================================================================*/
718/**
719 This function processes the interrupts.
720
721 NOTE:
722 tavarua_q_event is used to queue events in App buffer. i.e. App calls the
723 VIDIOC_QBUF ioctl to enqueue an empty (capturing) buffer, which is filled
724 by tavarua_q_event call.
725
726 Any async event that requires multiple steps, i.e. search, RT, PS, etc is
727 handled one at a time. (We preserve other interrupts when processing one).
728 Sync interrupts are given priority.
729
730 @param radio: structure pointer passed by client.
731
732 @return None.
733*/
734static void tavarua_handle_interrupts(struct tavarua_device *radio)
735{
736 int i;
737 int retval;
738 unsigned char xfr_status;
739 if (!radio->handle_irq) {
740 FMDBG("IRQ happend, but I wont handle it\n");
741 return;
742 }
743 mutex_lock(&radio->lock);
744 tavarua_read_registers(radio, STATUS_REG1, STATUS_REG_NUM);
745
746 FMDBG("INTSTAT1 <%x>\n", radio->registers[STATUS_REG1]);
747 FMDBG("INTSTAT2 <%x>\n", radio->registers[STATUS_REG2]);
748 FMDBG("INTSTAT3 <%x>\n", radio->registers[STATUS_REG3]);
749
750 if (radio->registers[STATUS_REG1] & READY) {
751 complete(&radio->sync_req_done);
752 tavarua_q_event(radio, TAVARUA_EVT_RADIO_READY);
753 }
754
755 /* Tune completed */
756 if (radio->registers[STATUS_REG1] & TUNE) {
757 if (radio->tune_req) {
758 complete(&radio->sync_req_done);
759 radio->tune_req = 0;
760 }
761 tavarua_q_event(radio, TAVARUA_EVT_TUNE_SUCC);
762 if (radio->srch_params.get_list) {
763 tavarua_start_xfr(radio, TAVARUA_XFR_SRCH_LIST,
764 RX_STATIONS_0);
765 }
766 radio->srch_params.get_list = 0;
767 radio->xfr_in_progress = 0;
768 radio->xfr_bytes_left = 0;
769 for (i = 0; i < TAVARUA_BUF_MAX; i++) {
770 if (i >= TAVARUA_BUF_RT_RDS)
771 kfifo_reset(&radio->data_buf[i]);
772 }
773 for (i = 0; i < TAVARUA_XFR_MAX; i++) {
774 if (i >= TAVARUA_XFR_RT_RDS)
775 radio->pending_xfrs[i] = 0;
776 }
777 retval = tavarua_read_registers(radio, TUNECTRL, 1);
778 /* send to user station parameters */
779 if (retval > -1) {
780 /* Signal strength */
781 if (!(radio->registers[TUNECTRL] & SIGSTATE))
782 tavarua_q_event(radio, TAVARUA_EVT_BELOW_TH);
783 else
784 tavarua_q_event(radio, TAVARUA_EVT_ABOVE_TH);
785 /* mono/stereo */
786 if ((radio->registers[TUNECTRL] & MOSTSTATE))
787 tavarua_q_event(radio, TAVARUA_EVT_STEREO);
788 else
789 tavarua_q_event(radio, TAVARUA_EVT_MONO);
790 /* is RDS available */
791 if ((radio->registers[TUNECTRL] & RDSSYNC))
792 tavarua_q_event(radio, TAVARUA_EVT_RDS_AVAIL);
793 else
794 tavarua_q_event(radio,
795 TAVARUA_EVT_RDS_NOT_AVAIL);
796 }
797
798 } else {
799 if (radio->tune_req) {
800 FMDERR("Tune INT is pending\n");
801 mutex_unlock(&radio->lock);
802 return;
803 }
804 }
805 /* Search completed (read FREQ) */
806 if (radio->registers[STATUS_REG1] & SEARCH)
807 tavarua_q_event(radio, TAVARUA_EVT_SEEK_COMPLETE);
808
809 /* Scanning for next station */
810 if (radio->registers[STATUS_REG1] & SCANNEXT)
811 tavarua_q_event(radio, TAVARUA_EVT_SCAN_NEXT);
812
813 /* Signal indicator change (read SIGSTATE) */
814 if (radio->registers[STATUS_REG1] & SIGNAL) {
815 retval = tavarua_read_registers(radio, TUNECTRL, 1);
816 if (retval > -1) {
817 if (!(radio->registers[TUNECTRL] & SIGSTATE))
818 tavarua_q_event(radio, TAVARUA_EVT_BELOW_TH);
819 else
820 tavarua_q_event(radio, TAVARUA_EVT_ABOVE_TH);
821 }
822 }
823
824 /* RDS synchronization state change (read RDSSYNC) */
825 if (radio->registers[STATUS_REG1] & SYNC) {
826 retval = tavarua_read_registers(radio, TUNECTRL, 1);
827 if (retval > -1) {
828 if ((radio->registers[TUNECTRL] & RDSSYNC))
829 tavarua_q_event(radio, TAVARUA_EVT_RDS_AVAIL);
830 else
831 tavarua_q_event(radio,
832 TAVARUA_EVT_RDS_NOT_AVAIL);
833 }
834 }
835
836 /* Audio Control indicator (read AUDIOIND) */
837 if (radio->registers[STATUS_REG1] & AUDIO) {
838 retval = tavarua_read_registers(radio, AUDIOIND, 1);
839 if (retval > -1) {
840 if ((radio->registers[AUDIOIND] & 0x01))
841 tavarua_q_event(radio, TAVARUA_EVT_STEREO);
842 else
843 tavarua_q_event(radio, TAVARUA_EVT_MONO);
844 }
845 }
846
847 /* interrupt register 2 */
848
849 /* New unread RDS data group available */
850 if (radio->registers[STATUS_REG2] & RDSDAT) {
851 FMDBG("Raw RDS Available\n");
852 tavarua_rds_read(radio);
853 tavarua_q_event(radio, TAVARUA_EVT_NEW_RAW_RDS);
854 }
855
856 /* New RDS Program Service Table available */
857 if (radio->registers[STATUS_REG2] & RDSPS) {
858 FMDBG("New PS RDS\n");
859 tavarua_start_xfr(radio, TAVARUA_XFR_PS_RDS, RDS_PS_0);
860 }
861
862 /* New RDS Radio Text available */
863 if (radio->registers[STATUS_REG2] & RDSRT) {
864 FMDBG("New RT RDS\n");
865 tavarua_start_xfr(radio, TAVARUA_XFR_RT_RDS, RDS_RT_0);
866 }
867
868 /* New RDS Radio Text available */
869 if (radio->registers[STATUS_REG2] & RDSAF) {
870 FMDBG("New AF RDS\n");
871 tavarua_start_xfr(radio, TAVARUA_XFR_AF_LIST, RDS_AF_0);
872 }
873 /* Trasmitter an RDS Group */
874 if (radio->registers[STATUS_REG2] & TXRDSDAT) {
875 FMDBG("New TXRDSDAT\n");
876 tavarua_q_event(radio, TAVARUA_EVT_TXRDSDAT);
877 }
878
879 /* Complete RDS buffer is available for transmission */
880 if (radio->registers[STATUS_REG2] & TXRDSDONE) {
881 FMDBG("New TXRDSDAT\n");
882 tavarua_q_event(radio, TAVARUA_EVT_TXRDSDONE);
883 }
884 /* interrupt register 3 */
885
886 /* Data transfer (XFR) completed */
887 if (radio->registers[STATUS_REG3] & TRANSFER) {
888 FMDBG("XFR Interrupt\n");
889 tavarua_read_registers(radio, XFRCTRL, XFR_REG_NUM+1);
890 FMDBG("XFRCTRL IS: %x\n", radio->registers[XFRCTRL]);
891 xfr_status = radio->registers[XFRCTRL];
892 switch (xfr_status) {
893 case RDS_PS_0:
894 FMDBG("PS Header\n");
895 copy_from_xfr(radio, TAVARUA_BUF_PS_RDS, 5);
896 radio->xfr_bytes_left = (radio->registers[XFRCTRL+1] &
897 0x0F) * 8;
898 FMDBG("PS RDS Length: %d\n", radio->xfr_bytes_left);
899 if ((radio->xfr_bytes_left > 0) &&
900 (radio->xfr_bytes_left < 97))
901 request_read_xfr(radio, RDS_PS_1);
902 else
903 radio->xfr_in_progress = 0;
904 break;
905 case RDS_PS_1:
906 case RDS_PS_2:
907 case RDS_PS_3:
908 case RDS_PS_4:
909 case RDS_PS_5:
910 case RDS_PS_6:
911 FMDBG("PS Data\n");
912 copy_from_xfr(radio, TAVARUA_BUF_PS_RDS, XFR_REG_NUM);
913 radio->xfr_bytes_left -= XFR_REG_NUM;
914 if (radio->xfr_bytes_left > 0) {
915 if ((xfr_status + 1) > RDS_PS_6)
916 request_read_xfr(radio, RDS_PS_6);
917 else
918 request_read_xfr(radio, xfr_status+1);
919 } else {
920 radio->xfr_in_progress = 0;
921 tavarua_q_event(radio, TAVARUA_EVT_NEW_PS_RDS);
922 }
923 break;
924 case RDS_RT_0:
925 FMDBG("RT Header\n");
926 copy_from_xfr(radio, TAVARUA_BUF_RT_RDS, 5);
927 radio->xfr_bytes_left = radio->registers[XFRCTRL+1]
928 & 0x7F;
929 FMDBG("RT RDS Length: %d\n", radio->xfr_bytes_left);
930 /*RT_1 to RT_4 16 byte registers so 64 bytes */
931 if ((radio->xfr_bytes_left > 0)
932 && (radio->xfr_bytes_left < 65))
933 request_read_xfr(radio, RDS_RT_1);
934 break;
935 case RDS_RT_1:
936 case RDS_RT_2:
937 case RDS_RT_3:
938 case RDS_RT_4:
939 FMDBG("xfr interrupt RT data\n");
940 copy_from_xfr(radio, TAVARUA_BUF_RT_RDS, XFR_REG_NUM);
941 radio->xfr_bytes_left -= XFR_REG_NUM;
942 if (radio->xfr_bytes_left > 0)
943 request_read_xfr(radio, xfr_status+1);
944 else {
945 radio->xfr_in_progress = 0;
946 tavarua_q_event(radio, TAVARUA_EVT_NEW_RT_RDS);
947 }
948 break;
949 case RDS_AF_0:
950 copy_from_xfr(radio, TAVARUA_BUF_AF_LIST,
951 XFR_REG_NUM);
952 radio->xfr_bytes_left = radio->registers[XFRCTRL+5]-11;
953 if (radio->xfr_bytes_left > 0)
954 request_read_xfr(radio, RDS_AF_1);
955 else
956 radio->xfr_in_progress = 0;
957 break;
958 case RDS_AF_1:
959 copy_from_xfr(radio, TAVARUA_BUF_AF_LIST,
960 radio->xfr_bytes_left);
961 tavarua_q_event(radio, TAVARUA_EVT_NEW_AF_LIST);
962 radio->xfr_in_progress = 0;
963 break;
964 case RX_CONFIG:
965 case RADIO_CONFIG:
966 case RDS_CONFIG:
967 memcpy(radio->sync_xfr_regs,
968 &radio->registers[XFRCTRL+1], XFR_REG_NUM);
969 complete(&radio->sync_req_done);
970 break;
971 case RX_STATIONS_0:
972 FMDBG("Search list has %d stations\n",
973 radio->registers[XFRCTRL+1]);
974 radio->xfr_bytes_left = radio->registers[XFRCTRL+1]*2;
975 if (radio->xfr_bytes_left > 14) {
976 copy_from_xfr(radio, TAVARUA_BUF_SRCH_LIST,
977 XFR_REG_NUM);
978 request_read_xfr(radio, RX_STATIONS_1);
979 } else if (radio->xfr_bytes_left) {
980 FMDBG("In else RX_STATIONS_0\n");
981 copy_from_xfr(radio, TAVARUA_BUF_SRCH_LIST,
982 radio->xfr_bytes_left+1);
983 tavarua_q_event(radio,
984 TAVARUA_EVT_NEW_SRCH_LIST);
985 radio->xfr_in_progress = 0;
986 }
987 break;
988 case RX_STATIONS_1:
989 FMDBG("In RX_STATIONS_1");
990 copy_from_xfr(radio, TAVARUA_BUF_SRCH_LIST,
991 radio->xfr_bytes_left);
992 tavarua_q_event(radio, TAVARUA_EVT_NEW_SRCH_LIST);
993 radio->xfr_in_progress = 0;
994 break;
995 case PHY_TXGAIN:
996 FMDBG("read PHY_TXGAIN is successful");
997 complete(&radio->sync_req_done);
998 break;
Ayaz Ahmada0d56b52012-06-26 15:58:41 +0530999 case (XFR_EXT | 0x80):
1000 FMDBG("Set tone generator successful\n");
1001 complete(&radio->sync_req_done);
1002 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001003 case (0x80 | RX_CONFIG):
1004 case (0x80 | RADIO_CONFIG):
1005 case (0x80 | RDS_CONFIG):
1006 case (0x80 | INT_CTRL):
1007 complete(&radio->sync_req_done);
1008 break;
1009 case (0x80 | RDS_RT_0):
1010 FMDBG("RT Header Sent\n");
1011 complete(&radio->sync_req_done);
1012 break;
1013 case (0x80 | RDS_RT_1):
1014 case (0x80 | RDS_RT_2):
1015 case (0x80 | RDS_RT_3):
1016 case (0x80 | RDS_RT_4):
1017 FMDBG("xfr interrupt RT data Sent\n");
1018 complete(&radio->sync_req_done);
1019 break;
1020 /*TX Specific transfer */
1021 case (0x80 | RDS_PS_0):
1022 FMDBG("PS Header Sent\n");
1023 complete(&radio->sync_req_done);
1024 break;
1025 case (0x80 | RDS_PS_1):
1026 case (0x80 | RDS_PS_2):
1027 case (0x80 | RDS_PS_3):
1028 case (0x80 | RDS_PS_4):
1029 case (0x80 | RDS_PS_5):
1030 case (0x80 | RDS_PS_6):
1031 FMDBG("xfr interrupt PS data Sent\n");
1032 complete(&radio->sync_req_done);
1033 break;
1034 case (0x80 | PHY_TXGAIN):
1035 FMDBG("write PHY_TXGAIN is successful");
1036 complete(&radio->sync_req_done);
1037 break;
Anantha Krishnan93eb1762012-06-04 13:41:07 +05301038 case (XFR_POKE_COMPLETE | LSH_DATA(ONE_BYTE, 1)):
1039 case (XFR_POKE_COMPLETE | LSH_DATA(TWO_BYTE, 1)):
1040 case (XFR_POKE_COMPLETE | LSH_DATA(THREE_BYTE, 1)):
1041 case (XFR_POKE_COMPLETE | LSH_DATA(FOUR_BYTE, 1)):
1042 case (XFR_POKE_COMPLETE | LSH_DATA(FIVE_BYTE, 1)):
1043 case (XFR_POKE_COMPLETE | LSH_DATA(SIX_BYTE, 1)):
1044 case (XFR_POKE_COMPLETE | LSH_DATA(SEVEN_BYTE, 1)):
1045 case (XFR_POKE_COMPLETE | LSH_DATA(EIGHT_BYTE, 1)):
1046 case (XFR_POKE_COMPLETE | LSH_DATA(NINE_BYTE, 1)):
1047 case (XFR_POKE_COMPLETE | LSH_DATA(TEN_BYTE, 1)):
1048 case (XFR_POKE_COMPLETE | LSH_DATA(ELEVEN_BYTE, 1)):
1049 case (XFR_POKE_COMPLETE | LSH_DATA(TWELVE_BYTE, 1)):
1050 case (XFR_POKE_COMPLETE | LSH_DATA(THIRTEEN_BYTE, 1)):
1051 case (XFR_PEEK_COMPLETE | LSH_DATA(ONE_BYTE, 1)):
1052 case (XFR_PEEK_COMPLETE | LSH_DATA(TWO_BYTE, 1)):
1053 case (XFR_PEEK_COMPLETE | LSH_DATA(THREE_BYTE, 1)):
1054 case (XFR_PEEK_COMPLETE | LSH_DATA(FOUR_BYTE, 1)):
1055 case (XFR_PEEK_COMPLETE | LSH_DATA(FIVE_BYTE, 1)):
1056 case (XFR_PEEK_COMPLETE | LSH_DATA(SIX_BYTE, 1)):
1057 case (XFR_PEEK_COMPLETE | LSH_DATA(SEVEN_BYTE, 1)):
1058 case (XFR_PEEK_COMPLETE | LSH_DATA(EIGHT_BYTE, 1)):
1059 case (XFR_PEEK_COMPLETE | LSH_DATA(NINE_BYTE, 1)):
1060 case (XFR_PEEK_COMPLETE | LSH_DATA(TEN_BYTE, 1)):
1061 case (XFR_PEEK_COMPLETE | LSH_DATA(ELEVEN_BYTE, 1)):
1062 case (XFR_PEEK_COMPLETE | LSH_DATA(TWELVE_BYTE, 1)):
1063 case (XFR_PEEK_COMPLETE | LSH_DATA(THIRTEEN_BYTE, 1)):
1064 FMDBG("XFR interrupt for PEEK/POKE complete\n");
1065 complete(&radio->sync_req_done);
1066 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001067 default:
1068 FMDERR("UNKNOWN XFR = %d\n", xfr_status);
1069 }
1070 if (!radio->xfr_in_progress)
1071 start_pending_xfr(radio);
1072
1073 }
1074
1075 /* Error occurred. Read ERRCODE to determine cause */
1076 if (radio->registers[STATUS_REG3] & ERROR) {
1077#ifdef FM_DEBUG
1078 unsigned char xfr_buf[XFR_REG_NUM];
1079 int retval = sync_read_xfr(radio, ERROR_CODE, xfr_buf);
1080 FMDBG("retval of ERROR_CODE read : %d\n", retval);
1081#endif
1082 FMDERR("ERROR STATE\n");
1083 }
1084
1085 mutex_unlock(&radio->lock);
1086 FMDBG("Work is done\n");
1087
1088}
1089
1090/*=============================================================================
1091FUNCTION: read_int_stat
1092=============================================================================*/
1093/**
1094 This function is scheduled whenever there is an interrupt pending in interrupt
1095 queue. i.e. kfmradio.
1096
1097 Whenever there is a GPIO interrupt, a delayed work will be queued in to the
1098 'kfmradio' work queue. Upon execution of this work in the queue, a a call
1099 to read_int_stat function will be made , which would in turn handle the
1100 interrupts by reading the INTSTATx registers.
1101 NOTE:
1102 Tasks to be run out of a workqueue need to be packaged in a struct
1103 work_struct structure.
1104
1105 @param work: work_struct structure.
1106
1107 @return None.
1108*/
1109static void read_int_stat(struct work_struct *work)
1110{
1111 struct tavarua_device *radio = container_of(work,
1112 struct tavarua_device, work.work);
1113 tavarua_handle_interrupts(radio);
1114}
1115
Taniya Das9ac855f2012-02-09 18:05:21 +05301116static void fm_shutdown(struct work_struct *work)
1117{
1118 struct tavarua_device *radio = container_of(work,
1119 struct tavarua_device, work.work);
Anantha Krishnan1475c932012-02-16 21:54:03 +05301120 FMDERR("%s: Releasing the FM I2S GPIO\n", __func__);
1121 if (radio->pdata->config_i2s_gpio != NULL)
1122 radio->pdata->config_i2s_gpio(FM_I2S_OFF);
1123 FMDERR("%s: Shutting down FM SOC\n", __func__);
Taniya Das9ac855f2012-02-09 18:05:21 +05301124 radio->pdata->fm_shutdown(radio->pdata);
1125 complete(&radio->shutdown_done);
1126}
1127
1128
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001129/*************************************************************************
1130 * irq helper functions
1131 ************************************************************************/
1132
1133/*=============================================================================
1134FUNCTION: tavarua_request_irq
1135=============================================================================*/
1136/**
1137 This function is called to acquire a FM GPIO and enable FM interrupts.
1138
1139 @param radio: structure pointer passed by client.
1140
1141 @return 0 if success else otherwise.
1142*/
1143static int tavarua_request_irq(struct tavarua_device *radio)
1144{
1145 int retval;
1146 int irq = radio->pdata->irq;
1147 if (radio == NULL)
1148 return -EINVAL;
1149
1150 /* A workqueue created with create_workqueue() will have one worker thread
1151 * for each CPU on the system; create_singlethread_workqueue(), instead,
1152 * creates a workqueue with a single worker process. The name of the queue
1153 * is limited to ten characters; it is only used for generating the "command"
1154 * for the kernel thread(s) (which can be seen in ps or top).
1155 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001156 /* allocate an interrupt line */
1157 /* On success, request_irq() returns 0 if everything goes as
1158 planned. Your interrupt handler will start receiving its
1159 interrupts immediately. On failure, request_irq()
1160 returns:
1161 -EINVAL
1162 The IRQ number you requested was either
1163 invalid or reserved, or your passed a NULL
1164 pointer for the handler() parameter.
1165
1166 -EBUSY The IRQ you requested is already being
1167 handled, and the IRQ cannot be shared.
1168
1169 -ENXIO The m68k returns this value for an invalid
1170 IRQ number.
1171 */
1172 /* Use request_any_context_irq, So that it might work for nested or
1173 nested interrupts. in MSM8x60, FM is connected to PMIC GPIO and it
1174 is a nested interrupt*/
1175 retval = request_any_context_irq(irq, tavarua_isr,
1176 IRQ_TYPE_EDGE_FALLING, "fm interrupt", radio);
1177 if (retval < 0) {
1178 FMDERR("Couldn't acquire FM gpio %d\n", irq);
1179 return retval;
1180 } else {
1181 FMDBG("FM GPIO %d registered\n", irq);
1182 }
1183 retval = enable_irq_wake(irq);
1184 if (retval < 0) {
1185 FMDERR("Could not enable FM interrupt\n ");
1186 free_irq(irq , radio);
1187 }
1188 return retval;
1189}
1190
1191/*=============================================================================
1192FUNCTION: tavarua_disable_irq
1193=============================================================================*/
1194/**
1195 This function is called to disable FM irq and free up FM interrupt handling
1196 resources.
1197
1198 @param radio: structure pointer passed by client.
1199
1200 @return 0 if success else otherwise.
1201*/
1202static int tavarua_disable_irq(struct tavarua_device *radio)
1203{
1204 int irq;
1205 if (!radio)
1206 return -EINVAL;
1207 irq = radio->pdata->irq;
1208 disable_irq_wake(irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209 free_irq(irq, radio);
Anantha Krishnan1475c932012-02-16 21:54:03 +05301210 cancel_delayed_work_sync(&radio->work);
1211 flush_workqueue(radio->wqueue);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001212 return 0;
1213}
1214
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301215static int optimized_search_algorithm(struct tavarua_device *radio,
1216 int region)
1217{
1218 unsigned char adie_type_bahma;
1219 int retval = 0;
1220 unsigned int rdsMask = 0;
Steve Muckle537e4452012-06-25 17:38:29 -07001221 unsigned char value = 0;
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301222
1223 adie_type_bahma = is_bahama();
1224
1225 switch (region) {
1226 case TAVARUA_REGION_US:
1227 /*
1228 Radio band for all the 200KHz channel-spaced regions
1229 coming under EUROPE too, have been set as TAVARUA_REGION_US.
1230 */
1231 FMDBG("%s: The region selected from APP is"
1232 " : TAVARUA_REGION_US", __func__);
1233 break;
1234 case TAVARUA_REGION_EU:
1235 /*
1236 Radio band for all the 50KHz channel-spaced regions
1237 coming under EUROPE, have been set as TAVARUA_REGION_EU.
1238 */
1239 FMDBG("%s: The region selected from APP is : "
1240 "TAVARUA_REGION_EU", __func__);
1241 break;
1242 case TAVARUA_REGION_JAPAN:
1243 /*
1244 Radio band for the 100KHz channel-spaced JAPAN region
1245 has been set as TAVARUA_REGION_JAPAN.
1246 */
1247 FMDBG("%s: The region selected from APP is"
1248 " : TAVARUA_REGION_JAPAN", __func__);
1249 break;
1250 case TAVARUA_REGION_JAPAN_WIDE:
1251 /*
1252 Radio band for the 50KHz channel-spaced JAPAN WIDE region
1253 has been set as TAVARUA_REGION_JAPAN_WIDE.
1254 */
1255 FMDBG("%s: The region selected from APP is"
1256 " : TAVARUA_REGION_JAPAN_WIDE", __func__);
1257 break;
1258 case TAVARUA_REGION_OTHER:
1259 /*
1260 Radio band for all the 100KHz channel-spaced regions
1261 including those coming under EUROPE have been set as
1262 TAVARUA_REGION_OTHER.
1263 */
1264 FMDBG("%s: The region selected from APP is"
1265 " : TAVARUA_REGION_OTHER", __func__);
1266 break;
1267 default:
1268 pr_err("%s: Should not reach here.", __func__);
1269 break;
1270
1271 }
1272
1273 /* Enable or Disable the 200KHz enforcer */
1274 switch (region) {
1275 case TAVARUA_REGION_US:
1276 case TAVARUA_REGION_JAPAN:
1277 case TAVARUA_REGION_OTHER:
1278 /*
1279 These are the 3 bands for which we need to enable the
1280 200KHz enforcer in ADVCTL reg.
1281 */
1282 if (adie_type_bahma) {
1283 FMDBG("Adie type : Bahama\n");
1284 FMDBG("%s: Enabling the 200KHz enforcer for"
1285 " Region : %d", __func__, region);
1286 /*Enable the 200KHz enforcer*/
1287 retval = tavarua_read_registers(radio,
1288 ADVCTRL, 1);
1289 if (retval >= 0) {
1290 rdsMask = radio->registers[ADVCTRL];
1291 SET_REG_FIELD(rdsMask, ENF_SRCH200khz,
1292 SRCH200KHZ_OFFSET, SRCH_MASK);
1293 retval = tavarua_write_register(radio,
1294 ADVCTRL, rdsMask);
1295 } else
1296 return retval;
1297 } /* if Marimba do nothing */
1298 break;
1299 case TAVARUA_REGION_EU:
1300 case TAVARUA_REGION_JAPAN_WIDE:
1301 /*
1302 These are the 2 bands for which we need to disable the
1303 200KHz enforcer in ADVCTL reg.
1304 Radio band for all the 50KHz channel-spaced regions
1305 coming under EUROPE have been set as TAVARUA_REGION_EU.
1306 */
1307 if (adie_type_bahma) {
1308 FMDBG("Adie type : Bahama\n");
1309 FMDBG("%s: Disabling the 200KHz enforcer for"
1310 " Region : %d", __func__, region);
1311 /*
1312 Disable 200KHz enforcer for all 50 KHz
1313 spaced regions.
1314 */
1315 retval = tavarua_read_registers(radio,
1316 ADVCTRL, 1);
1317 if (retval >= 0) {
1318 rdsMask = radio->registers[ADVCTRL];
1319 SET_REG_FIELD(rdsMask, NO_SRCH200khz,
1320 SRCH200KHZ_OFFSET, SRCH_MASK);
1321 retval = tavarua_write_register(radio,
1322 ADVCTRL, rdsMask);
1323 } else
1324 return retval;
1325 } /* if Marimba do nothing */
1326 break;
1327 default:
1328 FMDBG("%s: Defaulting in case of Enabling/Disabling"
1329 "the 200KHz Enforcer", __func__);
1330 break;
1331 }
1332
1333 /* Set channel spacing */
1334 switch (region) {
1335 case TAVARUA_REGION_US:
1336 if (adie_type_bahma) {
1337 FMDBG("Adie type : Bahama\n");
1338 /*
1339 Configuring all 200KHZ spaced regions as 100KHz due to
1340 change in the new Bahma FM SoC search algorithm.
1341 */
1342 value = FM_CH_SPACE_100KHZ;
1343 } else {
1344 FMDBG("Adie type : Marimba\n");
1345 value = FM_CH_SPACE_200KHZ;
1346 }
1347 break;
1348 case TAVARUA_REGION_JAPAN:
1349 case TAVARUA_REGION_OTHER:
1350 if (adie_type_bahma) {
1351 FMDBG("Adie type : Bahama\n");
1352 FMDBG("%s: Configuring the channel-spacing as 50KHz"
1353 "for the Region : %d", __func__, region);
1354 /*
1355 Configuring all 100KHZ spaced regions as 50KHz due to
1356 change in the new Bahma FM SoC search algorithm.
1357 */
1358 value = FM_CH_SPACE_50KHZ;
1359 } else {
1360 FMDBG("Adie type : Marimba\n");
1361 value = FM_CH_SPACE_100KHZ;
1362 }
1363 break;
1364 case TAVARUA_REGION_EU:
1365 case TAVARUA_REGION_JAPAN_WIDE:
1366 value = FM_CH_SPACE_50KHZ;
1367 break;
1368 default:
1369 FMDBG("%s: Defualting in case of Channel-Spacing", __func__);
1370 break;
1371 }
1372
1373 SET_REG_FIELD(radio->registers[RDCTRL], value,
1374 RDCTRL_CHSPACE_OFFSET, RDCTRL_CHSPACE_MASK);
1375
1376 return retval;
1377}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001378/*************************************************************************
1379 * fops/IOCTL helper functions
1380 ************************************************************************/
1381
1382/*=============================================================================
1383FUNCTION: tavarua_search
1384=============================================================================*/
1385/**
1386 This interface sets the search control features.
1387
1388 @param radio: structure pointer passed by client.
1389 @param on: The value of a control.
1390 @param dir: FM search direction.
1391
1392 @return => 0 if successful.
1393 @return < 0 if failure.
1394*/
1395static int tavarua_search(struct tavarua_device *radio, int on, int dir)
1396{
1397 enum search_t srch = radio->registers[SRCHCTRL] & SRCH_MODE;
1398
1399 FMDBG("In tavarua_search\n");
1400 if (on) {
1401 radio->registers[SRCHRDS1] = 0x00;
1402 radio->registers[SRCHRDS2] = 0x00;
1403 /* Set freq band */
1404 switch (srch) {
1405 case SCAN_FOR_STRONG:
1406 case SCAN_FOR_WEAK:
1407 radio->srch_params.get_list = 1;
1408 radio->registers[SRCHRDS2] =
1409 radio->srch_params.preset_num;
1410 break;
1411 case RDS_SEEK_PTY:
1412 case RDS_SCAN_PTY:
1413 radio->registers[SRCHRDS2] =
1414 radio->srch_params.srch_pty;
1415 break;
1416 case RDS_SEEK_PI:
1417 radio->registers[SRCHRDS1] =
1418 (radio->srch_params.srch_pi & 0xFF00) >> 8;
1419 radio->registers[SRCHRDS2] =
1420 (radio->srch_params.srch_pi & 0x00FF);
1421 break;
1422 default:
1423 break;
1424 }
1425 radio->registers[SRCHCTRL] |= SRCH_ON;
1426 } else {
1427 radio->registers[SRCHCTRL] &= ~SRCH_ON;
1428 radio->srch_params.get_list = 0;
1429 }
1430 radio->registers[SRCHCTRL] = (dir << 3) |
1431 (radio->registers[SRCHCTRL] & 0xF7);
1432
1433 FMDBG("SRCHCTRL <%x>\n", radio->registers[SRCHCTRL]);
1434 FMDBG("Search Started\n");
1435 return tavarua_write_registers(radio, SRCHRDS1,
1436 &radio->registers[SRCHRDS1], 3);
1437}
1438
1439/*=============================================================================
1440FUNCTION: tavarua_set_region
1441=============================================================================*/
1442/**
1443 This interface configures the FM radio.
1444
1445 @param radio: structure pointer passed by client.
1446 @param req_region: FM band types. These types defines the FM band minimum and
1447 maximum frequencies in the FM band.
1448
1449 @return => 0 if successful.
1450 @return < 0 if failure.
1451*/
1452static int tavarua_set_region(struct tavarua_device *radio,
1453 int req_region)
1454{
1455 int retval = 0;
Anantha Krishnana02ef212011-06-28 00:57:25 +05301456 unsigned int rdsMask = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001457 unsigned char xfr_buf[XFR_REG_NUM];
1458 unsigned char value;
1459 unsigned int spacing = 0.100 * FREQ_MUL;
1460 unsigned int band_low, band_high;
1461 unsigned int low_band_limit = 76.0 * FREQ_MUL;
1462 enum tavarua_region_t region = req_region;
Anantha Krishnana02ef212011-06-28 00:57:25 +05301463 unsigned char adie_type_bahma;
1464
1465 adie_type_bahma = is_bahama();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001466
1467 /* Set freq band */
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301468 if (region == TAVARUA_REGION_JAPAN)
1469 SET_REG_FIELD(radio->registers[RDCTRL], 1,
1470 RDCTRL_BAND_OFFSET, RDCTRL_BAND_MASK);
1471 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001472 SET_REG_FIELD(radio->registers[RDCTRL], 0,
1473 RDCTRL_BAND_OFFSET, RDCTRL_BAND_MASK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001474
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001475 /* Set De-emphasis and soft band range*/
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301476 SET_REG_FIELD(radio->registers[RDCTRL], radio->region_params.emphasis,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001477 RDCTRL_DEEMPHASIS_OFFSET, RDCTRL_DEEMPHASIS_MASK);
1478
1479 /* set RDS standard */
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301480 SET_REG_FIELD(radio->registers[RDSCTRL], radio->region_params.rds_std,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481 RDSCTRL_STANDARD_OFFSET, RDSCTRL_STANDARD_MASK);
1482
1483 FMDBG("RDSCTRLL %x\n", radio->registers[RDSCTRL]);
1484 retval = tavarua_write_register(radio, RDSCTRL,
1485 radio->registers[RDSCTRL]);
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301486 if (retval < 0) {
1487 FMDERR("Failed to set RDS/RBDS standard\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488 return retval;
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301489 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001490
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301491 /* Set the lower and upper band limits*/
1492 retval = sync_read_xfr(radio, RADIO_CONFIG, xfr_buf);
1493 if (retval < 0) {
1494 FMDERR("failed to get RADIO_CONFIG\n");
1495 return retval;
1496 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301498 band_low = (radio->region_params.band_low -
1499 low_band_limit) / spacing;
1500 band_high = (radio->region_params.band_high -
1501 low_band_limit) / spacing;
1502
1503 xfr_buf[0] = RSH_DATA(band_low, 8);
1504 xfr_buf[1] = GET_ABS_VAL(band_low);
1505 xfr_buf[2] = RSH_DATA(band_high, 8);
1506 xfr_buf[3] = GET_ABS_VAL(band_high);
Venkateshwarlu Domakondab49c2cb2012-04-17 17:44:50 +05301507 xfr_buf[4] = 0; /* Active LOW */
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301508 retval = sync_write_xfr(radio, RADIO_CONFIG, xfr_buf);
1509 if (retval < 0) {
1510 FMDERR("Could not set regional settings\n");
1511 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512 }
1513 radio->region_params.region = region;
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301514
1515 /* Check for the FM Algorithm used */
1516 if (radio->enable_optimized_srch_alg) {
1517 FMDBG("Optimized Srch Algorithm!!!");
1518 optimized_search_algorithm(radio, region);
1519 } else {
1520 FMDBG("Native Srch Algorithm!!!");
1521 /* Enable/Disable the 200KHz enforcer */
1522 switch (region) {
1523 case TAVARUA_REGION_US:
1524 if (adie_type_bahma) {
1525 FMDBG("Adie type : Bahama\n");
1526 /*Enable the 200KHz enforcer*/
1527 retval = tavarua_read_registers(radio,
1528 ADVCTRL, 1);
1529 if (retval >= 0) {
1530 rdsMask = radio->registers[ADVCTRL];
1531 SET_REG_FIELD(rdsMask, ENF_SRCH200khz,
1532 SRCH200KHZ_OFFSET, SRCH_MASK);
1533 retval = tavarua_write_register(radio,
1534 ADVCTRL, rdsMask);
1535 } else
1536 return retval;
1537 } /* if Marimba do nothing */
1538 break;
1539 case TAVARUA_REGION_EU:
1540 case TAVARUA_REGION_JAPAN:
1541 case TAVARUA_REGION_JAPAN_WIDE:
1542 default:
1543 if (adie_type_bahma) {
1544 FMDBG("Adie type : Bahama\n");
1545 /*
1546 Disable 200KHz enforcer for all 100/50 KHz
1547 spaced regions.
1548 */
1549 retval = tavarua_read_registers(radio,
1550 ADVCTRL, 1);
1551 if (retval >= 0) {
1552 rdsMask = radio->registers[ADVCTRL];
1553 SET_REG_FIELD(rdsMask, NO_SRCH200khz,
1554 SRCH200KHZ_OFFSET, SRCH_MASK);
1555 retval = tavarua_write_register(radio,
1556 ADVCTRL, rdsMask);
1557 } else
1558 return retval;
1559 } /* if Marimba do nothing */
1560 break;
1561 }
1562
1563 /* Set channel spacing */
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301564 if (region == TAVARUA_REGION_US) {
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301565 if (adie_type_bahma) {
1566 FMDBG("Adie type : Bahama\n");
1567 /*
1568 Configuring all 200KHZ spaced regions as
1569 100KHz due to change in the new Bahma
1570 FM SoC search algorithm.
1571 */
1572 value = FM_CH_SPACE_100KHZ;
1573 } else {
1574 FMDBG("Adie type : Marimba\n");
1575 value = FM_CH_SPACE_200KHZ;
1576 }
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301577 } else {
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301578 /*
1579 Set the channel spacing as configured from
1580 the upper layers.
1581 */
1582 value = radio->region_params.spacing;
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301583 }
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301584 SET_REG_FIELD(radio->registers[RDCTRL], value,
1585 RDCTRL_CHSPACE_OFFSET, RDCTRL_CHSPACE_MASK);
1586
1587 }
1588
1589 /* Write the config values into RDCTL register */
1590 FMDBG("RDCTRL: %x\n", radio->registers[RDCTRL]);
1591 retval = tavarua_write_register(radio, RDCTRL,
1592 radio->registers[RDCTRL]);
1593 if (retval < 0) {
1594 FMDERR("Could not set region in rdctrl\n");
1595 return retval;
1596 }
1597
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001598 return retval;
1599}
1600
1601/*=============================================================================
1602FUNCTION: tavarua_get_freq
1603=============================================================================*/
1604/**
1605 This interface gets the current frequency.
1606
1607 @param radio: structure pointer passed by client.
1608 @param freq: struct v4l2_frequency. This will be set to the resultant
1609 frequency in units of 62.5 kHz on success.
1610
1611 NOTE:
1612 To get the current tuner or modulator radio frequency applications set the
1613 tuner field of a struct v4l2_frequency to the respective tuner or modulator
1614 number (only input devices have tuners, only output devices have modulators),
1615 zero out the reserved array and call the VIDIOC_G_FREQUENCY ioctl with a
1616 pointer to this structure. The driver stores the current frequency in the
1617 frequency field.
1618
1619 Tuning frequency is in units of 62.5 kHz, or if the struct v4l2_tuner or
1620 struct v4l2_modulator capabilities flag V4L2_TUNER_CAP_LOW is set, in
1621 units of 62.5 Hz.
1622
1623 @return => 0 if successful.
1624 @return < 0 if failure.
1625*/
1626static int tavarua_get_freq(struct tavarua_device *radio,
1627 struct v4l2_frequency *freq)
1628{
1629 int retval;
1630 unsigned short chan;
1631 unsigned int band_bottom;
1632 unsigned int spacing;
1633 band_bottom = radio->region_params.band_low;
1634 spacing = 0.100 * FREQ_MUL;
1635 /* read channel */
1636 retval = tavarua_read_registers(radio, FREQ, 2);
1637 chan = radio->registers[FREQ];
1638
1639 /* Frequency (MHz) = 100 (kHz) x Channel + Bottom of Band (MHz) */
1640 freq->frequency = spacing * chan + band_bottom;
1641 if (radio->registers[TUNECTRL] & ADD_OFFSET)
1642 freq->frequency += 800;
1643 return retval;
1644}
1645
1646/*=============================================================================
1647FUNCTION: tavarua_set_freq
1648=============================================================================*/
1649/**
1650 This interface sets the current frequency.
1651
1652 @param radio: structure pointer passed by client.
1653 @param freq: desired frequency sent by the client in 62.5 kHz units.
1654
1655 NOTE:
1656 To change the current tuner or modulator radio frequency, applications
1657 initialize the tuner, type and frequency fields, and the reserved array of a
1658 struct v4l2_frequency and call the VIDIOC_S_FREQUENCY ioctl with a pointer to
1659 this structure. When the requested frequency is not possible the driver
1660 assumes the closest possible value. However VIDIOC_S_FREQUENCY is a
1661 write-only ioctl, it does not return the actual new frequency.
1662
1663 Tuning frequency is in units of 62.5 kHz, or if the struct v4l2_tuner
1664 or struct v4l2_modulator capabilities flag V4L2_TUNER_CAP_LOW is set,
1665 in units of 62.5 Hz.
1666
1667 @return => 0 if successful.
1668 @return < 0 if failure.
1669*/
1670static int tavarua_set_freq(struct tavarua_device *radio, unsigned int freq)
1671{
1672
1673 unsigned int band_bottom;
1674 unsigned char chan;
1675 unsigned char cmd[] = {0x00, 0x00};
1676 unsigned int spacing;
1677 int retval;
1678 band_bottom = radio->region_params.band_low;
1679 spacing = 0.100 * FREQ_MUL;
1680 if ((freq % 1600) == 800) {
1681 cmd[1] = ADD_OFFSET;
1682 freq -= 800;
1683 }
1684 /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / 100 (kHz) */
1685 chan = (freq - band_bottom) / spacing;
1686
1687 cmd[0] = chan;
1688 cmd[1] |= TUNE_STATION;
1689 radio->tune_req = 1;
1690 retval = tavarua_write_registers(radio, FREQ, cmd, 2);
1691 if (retval < 0)
1692 radio->tune_req = 0;
1693 return retval;
1694
1695}
1696
1697/**************************************************************************
1698 * File Operations Interface
1699 *************************************************************************/
1700
1701/*=============================================================================
1702FUNCTION: tavarua_fops_read
1703=============================================================================*/
1704/**
1705 This function is called when a process, which already opened the dev file,
1706 attempts to read from it.
1707
1708 In case of tavarua driver, it is called to read RDS data.
1709
1710 @param file: file descriptor.
1711 @param buf: The buffer to fill with data.
1712 @param count: The length of the buffer in bytes.
1713 @param ppos: Our offset in the file.
1714
1715 @return The number of bytes put into the buffer on sucess.
1716 -EFAULT if there is no access to user buffer
1717*/
1718static ssize_t tavarua_fops_read(struct file *file, char __user *buf,
1719 size_t count, loff_t *ppos)
1720{
1721 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
1722 struct kfifo *rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
1723
1724 /* block if no new data available */
1725 while (!kfifo_len(rds_buf)) {
1726 if (file->f_flags & O_NONBLOCK)
1727 return -EWOULDBLOCK;
1728 if (wait_event_interruptible(radio->read_queue,
1729 kfifo_len(rds_buf)) < 0)
1730 return -EINTR;
1731 }
1732
1733 /* calculate block count from byte count */
1734 count /= BYTES_PER_BLOCK;
1735
1736
1737 /* check if we can write to the user buffer */
1738 if (!access_ok(VERIFY_WRITE, buf, count*BYTES_PER_BLOCK))
1739 return -EFAULT;
1740
1741 /* copy RDS block out of internal buffer and to user buffer */
1742 return kfifo_out_locked(rds_buf, buf, count*BYTES_PER_BLOCK,
1743 &radio->buf_lock[TAVARUA_BUF_RAW_RDS]);
1744}
1745
1746/*=============================================================================
1747FUNCTION: tavarua_fops_write
1748=============================================================================*/
1749/**
1750 This function is called when a process, which already opened the dev file,
1751 attempts to write to it.
1752
1753 In case of tavarua driver, it is called to write RDS data to host.
1754
1755 @param file: file descriptor.
1756 @param buf: The buffer which has data to write.
1757 @param count: The length of the buffer.
1758 @param ppos: Our offset in the file.
1759
1760 @return The number of bytes written from the buffer.
1761*/
1762static ssize_t tavarua_fops_write(struct file *file, const char __user *data,
1763 size_t count, loff_t *ppos)
1764{
1765 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
1766 int retval = 0;
1767 int bytes_to_copy;
1768 int bytes_copied = 0;
1769 int bytes_left;
1770 int chunk_index = 0;
1771 unsigned char tx_data[XFR_REG_NUM];
1772 /* Disable TX of this type first */
1773 switch (radio->tx_mode) {
1774 case TAVARUA_TX_RT:
1775 bytes_left = min((int)count, MAX_RT_LENGTH);
1776 tx_data[1] = 0;
1777 break;
1778 case TAVARUA_TX_PS:
1779 bytes_left = min((int)count, MAX_PS_LENGTH);
1780 tx_data[4] = 0;
1781 break;
1782 default:
1783 FMDERR("%s: Unknown TX mode\n", __func__);
1784 return -1;
1785 }
1786 retval = sync_write_xfr(radio, radio->tx_mode, tx_data);
1787 if (retval < 0)
1788 return retval;
1789
1790 /* send payload to FM hardware */
1791 while (bytes_left) {
1792 chunk_index++;
1793 bytes_to_copy = min(bytes_left, XFR_REG_NUM);
1794 if (copy_from_user(tx_data, data + bytes_copied, bytes_to_copy))
1795 return -EFAULT;
1796 retval = sync_write_xfr(radio, radio->tx_mode +
1797 chunk_index, tx_data);
1798 if (retval < 0)
1799 return retval;
1800
1801 bytes_copied += bytes_to_copy;
1802 bytes_left -= bytes_to_copy;
1803 }
1804
1805 /* send the header */
1806 switch (radio->tx_mode) {
1807 case TAVARUA_TX_RT:
1808 FMDBG("Writing RT header\n");
1809 tx_data[0] = bytes_copied;
1810 tx_data[1] = TX_ON | 0x03; /* on | PTY */
1811 tx_data[2] = 0x12; /* PI high */
1812 tx_data[3] = 0x34; /* PI low */
1813 break;
1814 case TAVARUA_TX_PS:
1815 FMDBG("Writing PS header\n");
1816 tx_data[0] = chunk_index;
1817 tx_data[1] = 0x03; /* PTY */
1818 tx_data[2] = 0x12; /* PI high */
1819 tx_data[3] = 0x34; /* PI low */
1820 tx_data[4] = TX_ON | 0x01;
1821 break;
1822 default:
1823 FMDERR("%s: Unknown TX mode\n", __func__);
1824 return -1;
1825 }
1826 retval = sync_write_xfr(radio, radio->tx_mode, tx_data);
1827 if (retval < 0)
1828 return retval;
1829 FMDBG("done writing: %d\n", retval);
1830 return bytes_copied;
1831}
1832
1833/*=============================================================================
1834FUNCTION: tavarua_fops_open
1835=============================================================================*/
1836/**
1837 This function is called when a process tries to open the device file, like
1838 "cat /dev/mycharfile"
1839
1840 @param file: file descriptor.
1841
1842 @return => 0 if successful.
1843 @return < 0 if failure.
1844*/
1845static int tavarua_fops_open(struct file *file)
1846{
1847 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
1848 int retval = -ENODEV;
1849 unsigned char value;
1850 /* FM core bring up */
1851 int i = 0;
1852 char fm_ctl0_part1[] = { 0xCA, 0xCE, 0xD6 };
1853 char fm_ctl1[] = { 0x03 };
1854 char fm_ctl0_part2[] = { 0xB6, 0xB7 };
1855 char buffer[] = {0x00, 0x48, 0x8A, 0x8E, 0x97, 0xB7};
1856 int bahama_present = -ENODEV;
1857
Taniya Das9ac855f2012-02-09 18:05:21 +05301858 INIT_DELAYED_WORK(&radio->work, read_int_stat);
Anantha Krishnana2f98082011-10-04 20:02:11 +05301859 if (!atomic_dec_and_test(&radio->users)) {
1860 pr_err("%s: Device already in use."
1861 "Try again later", __func__);
1862 atomic_inc(&radio->users);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001863 return -EBUSY;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001865
1866 /* initial gpio pin config & Power up */
1867 retval = radio->pdata->fm_setup(radio->pdata);
1868 if (retval) {
1869 printk(KERN_ERR "%s: failed config gpio & pmic\n", __func__);
1870 goto open_err_setup;
1871 }
1872 if (radio->pdata->config_i2s_gpio != NULL) {
1873 retval = radio->pdata->config_i2s_gpio(FM_I2S_ON);
1874 if (retval) {
1875 printk(KERN_ERR "%s: failed config gpio\n", __func__);
1876 goto config_i2s_err;
1877 }
1878 }
1879 /* enable irq */
1880 retval = tavarua_request_irq(radio);
1881 if (retval < 0) {
1882 printk(KERN_ERR "%s: failed to request irq\n", __func__);
1883 goto open_err_req_irq;
1884 }
1885 /* call top level marimba interface here to enable FM core */
1886 FMDBG("initializing SoC\n");
1887
1888 bahama_present = is_bahama();
1889
1890 if (bahama_present == -ENODEV)
1891 return -ENODEV;
1892
1893 if (bahama_present)
1894 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
1895 else
1896 radio->marimba->mod_id = MARIMBA_SLAVE_ID_MARIMBA;
1897
1898 value = FM_ENABLE;
1899 retval = marimba_write_bit_mask(radio->marimba,
1900 MARIMBA_XO_BUFF_CNTRL, &value, 1, value);
1901 if (retval < 0) {
1902 printk(KERN_ERR "%s:XO_BUFF_CNTRL write failed\n",
1903 __func__);
1904 goto open_err_all;
1905 }
1906
1907
1908 /* Bring up FM core */
1909 if (bahama_present) {
1910
1911 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
1912 /* Read the Bahama version*/
1913 retval = marimba_read_bit_mask(radio->marimba,
1914 0x00, &bahama_version, 1, 0x1F);
1915 if (retval < 0) {
1916 printk(KERN_ERR "%s: version read failed",
1917 __func__);
1918 goto open_err_all;
1919 }
Rahul Kashyapc88b6e32011-07-07 10:52:16 +05301920
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001921 /* Check for Bahama V2 variant*/
1922 if (bahama_version == 0x09) {
1923
1924 /* In case of Bahama v2, forcefully enable the
1925 * internal analog and digital voltage controllers
1926 */
1927 value = 0x06;
1928 /* value itself used as mask in these writes*/
1929 retval = marimba_write_bit_mask(radio->marimba,
1930 BAHAMA_LDO_DREG_CTL0, &value, 1, value);
1931 if (retval < 0) {
1932 printk(KERN_ERR "%s:0xF0 write failed\n",
1933 __func__);
1934 goto open_err_all;
1935 }
1936 value = 0x86;
1937 retval = marimba_write_bit_mask(radio->marimba,
1938 BAHAMA_LDO_AREG_CTL0, &value, 1, value);
1939 if (retval < 0) {
1940 printk(KERN_ERR "%s:0xF4 write failed\n",
1941 __func__);
1942 goto open_err_all;
1943 }
1944 }
1945
1946 /*write FM mode*/
1947 retval = tavarua_write_register(radio, BAHAMA_FM_MODE_REG,
1948 BAHAMA_FM_MODE_NORMAL);
1949 if (retval < 0) {
1950 printk(KERN_ERR "failed to set the FM mode: %d\n",
1951 retval);
1952 goto open_err_all;
1953 }
1954 /*Write first sequence of bytes to FM_CTL0*/
1955 for (i = 0; i < 3; i++) {
1956 retval = tavarua_write_register(radio,
1957 BAHAMA_FM_CTL0_REG, fm_ctl0_part1[i]);
1958 if (retval < 0) {
1959 printk(KERN_ERR "FM_CTL0:set-1 failure: %d\n",
1960 retval);
1961 goto open_err_all;
1962 }
1963 }
1964 /*Write the FM_CTL1 sequence*/
1965 for (i = 0; i < 1; i++) {
1966 retval = tavarua_write_register(radio,
1967 BAHAMA_FM_CTL1_REG, fm_ctl1[i]);
1968 if (retval < 0) {
1969 printk(KERN_ERR "FM_CTL1 write failure: %d\n",
1970 retval);
1971 goto open_err_all;
1972 }
1973 }
1974 /*Write second sequence of bytes to FM_CTL0*/
1975 for (i = 0; i < 2; i++) {
1976 retval = tavarua_write_register(radio,
1977 BAHAMA_FM_CTL0_REG, fm_ctl0_part2[i]);
1978 if (retval < 0) {
1979 printk(KERN_ERR "FM_CTL0:set-2 failure: %d\n",
1980 retval);
1981 goto open_err_all;
1982 }
1983 }
1984 } else {
1985 retval = tavarua_write_registers(radio, LEAKAGE_CNTRL,
1986 buffer, 6);
1987 if (retval < 0) {
1988 printk(KERN_ERR "%s: failed to bring up FM Core\n",
1989 __func__);
1990 goto open_err_all;
1991 }
1992 }
1993 /* Wait for interrupt i.e. complete(&radio->sync_req_done); call */
1994 /*Initialize the completion variable for
1995 for the proper behavior*/
1996 init_completion(&radio->sync_req_done);
1997 if (!wait_for_completion_timeout(&radio->sync_req_done,
1998 msecs_to_jiffies(wait_timeout))) {
1999 retval = -1;
2000 FMDERR("Timeout waiting for initialization\n");
2001 }
2002
2003 /* get Chip ID */
2004 retval = tavarua_write_register(radio, XFRCTRL, CHIPID);
2005 if (retval < 0)
2006 goto open_err_all;
2007 msleep(TAVARUA_DELAY);
2008 tavarua_read_registers(radio, XFRCTRL, XFR_REG_NUM+1);
2009 if (radio->registers[XFRCTRL] != CHIPID)
2010 goto open_err_all;
2011
2012 radio->chipID = (radio->registers[XFRCTRL+2] << 24) |
2013 (radio->registers[XFRCTRL+5] << 16) |
2014 (radio->registers[XFRCTRL+6] << 8) |
2015 (radio->registers[XFRCTRL+7]);
2016
2017 printk(KERN_WARNING DRIVER_NAME ": Chip ID %x\n", radio->chipID);
2018 if (radio->chipID == MARIMBA_A0) {
2019 printk(KERN_WARNING DRIVER_NAME ": Unsupported hardware: %x\n",
2020 radio->chipID);
2021 retval = -1;
2022 goto open_err_all;
2023 }
2024
2025 radio->handle_irq = 0;
2026 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
2027 marimba_set_fm_status(radio->marimba, true);
2028 return 0;
2029
2030
2031open_err_all:
2032 /*Disable FM in case of error*/
2033 value = 0x00;
2034 marimba_write_bit_mask(radio->marimba, MARIMBA_XO_BUFF_CNTRL,
2035 &value, 1, value);
2036 tavarua_disable_irq(radio);
2037open_err_req_irq:
2038 if (radio->pdata->config_i2s_gpio != NULL)
2039 radio->pdata->config_i2s_gpio(FM_I2S_OFF);
2040config_i2s_err:
2041 radio->pdata->fm_shutdown(radio->pdata);
2042open_err_setup:
2043 radio->handle_irq = 1;
Anantha Krishnana2f98082011-10-04 20:02:11 +05302044 atomic_inc(&radio->users);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002045 return retval;
2046}
2047
2048/*=============================================================================
2049FUNCTION: tavarua_fops_release
2050=============================================================================*/
2051/**
2052 This function is called when a process closes the device file.
2053
2054 @param file: file descriptor.
2055
2056 @return => 0 if successful.
2057 @return < 0 if failure.
2058*/
2059static int tavarua_fops_release(struct file *file)
2060{
2061 int retval;
2062 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2063 unsigned char value;
2064 int i = 0;
2065 /*FM Core shutdown sequence for Bahama*/
2066 char fm_ctl0_part1[] = { 0xB7 };
2067 char fm_ctl1[] = { 0x03 };
2068 char fm_ctl0_part2[] = { 0x9F, 0x48, 0x02 };
2069 int bahama_present = -ENODEV;
2070 /*FM Core shutdown sequence for Marimba*/
2071 char buffer[] = {0x18, 0xB7, 0x48};
2072 bool bt_status = false;
2073 int index;
2074 /* internal regulator controllers DREG_CTL0, AREG_CTL0
2075 * has to be kept in the valid state based on the bt status.
2076 * 1st row is the state when no clients are active,
2077 * and the second when bt is in on state.
2078 */
2079 char internal_vreg_ctl[2][2] = {
2080 { 0x04, 0x84 },
2081 { 0x00, 0x80 }
2082 };
2083
Anantha Krishnana2f98082011-10-04 20:02:11 +05302084 if (!radio) {
2085 pr_err("%s: Radio device not available...", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002086 return -ENODEV;
Anantha Krishnana2f98082011-10-04 20:02:11 +05302087 }
2088
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002089 FMDBG("In %s", __func__);
2090
Anantha Krishnan1475c932012-02-16 21:54:03 +05302091 FMDBG("%s, Disabling the IRQs\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002092 /* disable irq */
2093 retval = tavarua_disable_irq(radio);
2094 if (retval < 0) {
2095 printk(KERN_ERR "%s: failed to disable irq\n", __func__);
2096 return retval;
2097 }
2098
Anantha Krishnan1475c932012-02-16 21:54:03 +05302099 /* disable radio ctrl */
2100 retval = tavarua_write_register(radio, RDCTRL, 0x00);
2101 if (retval < 0) {
2102 printk(KERN_ERR "%s: failed to disable FM\n", __func__);
2103 return retval;
2104 }
2105
Taniya Das9ac855f2012-02-09 18:05:21 +05302106 init_completion(&radio->shutdown_done);
2107
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002108 bahama_present = is_bahama();
2109
2110 if (bahama_present == -ENODEV)
2111 return -ENODEV;
2112
Taniya Das9ac855f2012-02-09 18:05:21 +05302113 INIT_DELAYED_WORK(&radio->work, fm_shutdown);
2114
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002115 if (bahama_present) {
2116 /*Write first sequence of bytes to FM_CTL0*/
2117 for (i = 0; i < 1; i++) {
2118 retval = tavarua_write_register(radio,
2119 BAHAMA_FM_CTL0_REG, fm_ctl0_part1[i]);
2120 if (retval < 0) {
2121 printk(KERN_ERR "FM_CTL0:Set-1 failure: %d\n",
2122 retval);
2123 break;
2124 }
2125 }
2126 /*Write the FM_CTL1 sequence*/
2127 for (i = 0; i < 1; i++) {
2128 retval = tavarua_write_register(radio,
2129 BAHAMA_FM_CTL1_REG, fm_ctl1[i]);
2130 if (retval < 0) {
2131 printk(KERN_ERR "FM_CTL1 failure: %d\n",
2132 retval);
2133 break;
2134 }
2135 }
2136 /*Write second sequence of bytes to FM_CTL0*/
2137 for (i = 0; i < 3; i++) {
2138 retval = tavarua_write_register(radio,
2139 BAHAMA_FM_CTL0_REG, fm_ctl0_part2[i]);
2140 if (retval < 0) {
2141 printk(KERN_ERR "FM_CTL0:Set-2 failure: %d\n",
2142 retval);
2143 break;
2144 }
2145 }
2146 } else {
2147
2148 retval = tavarua_write_registers(radio, FM_CTL0,
2149 buffer, sizeof(buffer)/sizeof(buffer[0]));
2150 if (retval < 0) {
2151 printk(KERN_ERR "%s: failed to bring down the FM Core\n",
2152 __func__);
2153 return retval;
2154 }
2155 }
2156 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
2157 bt_status = marimba_get_bt_status(radio->marimba);
2158 /* Set the index based on the bt status*/
2159 index = bt_status ? 1 : 0;
2160 /* Check for Bahama's existance and Bahama V2 variant*/
2161 if (bahama_present && (bahama_version == 0x09)) {
2162 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
2163 /* actual value itself used as mask*/
2164 retval = marimba_write_bit_mask(radio->marimba,
2165 BAHAMA_LDO_DREG_CTL0, &internal_vreg_ctl[bt_status][0],
2166 1, internal_vreg_ctl[index][0]);
2167 if (retval < 0) {
2168 printk(KERN_ERR "%s:0xF0 write failed\n", __func__);
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302169 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002170 }
2171 /* actual value itself used as mask*/
2172 retval = marimba_write_bit_mask(radio->marimba,
2173 BAHAMA_LDO_AREG_CTL0, &internal_vreg_ctl[bt_status][1],
2174 1, internal_vreg_ctl[index][1]);
2175 if (retval < 0) {
2176 printk(KERN_ERR "%s:0xF4 write failed\n", __func__);
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302177 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002178 }
2179 } else {
2180 /* disable fm core */
2181 radio->marimba->mod_id = MARIMBA_SLAVE_ID_MARIMBA;
2182 }
2183
2184 value = 0x00;
2185 retval = marimba_write_bit_mask(radio->marimba, MARIMBA_XO_BUFF_CNTRL,
2186 &value, 1, FM_ENABLE);
2187 if (retval < 0) {
2188 printk(KERN_ERR "%s:XO_BUFF_CNTRL write failed\n", __func__);
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302189 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002190 }
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302191exit:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002192 FMDBG("%s, Calling fm_shutdown\n", __func__);
Taniya Das9ac855f2012-02-09 18:05:21 +05302193 queue_delayed_work(radio->wqueue, &radio->work,
2194 msecs_to_jiffies(TAVARUA_DELAY/2));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002195 /* teardown gpio and pmic */
Rahul Kashyapc88b6e32011-07-07 10:52:16 +05302196 marimba_set_fm_status(radio->marimba, false);
Taniya Das9ac855f2012-02-09 18:05:21 +05302197 wait_for_completion(&radio->shutdown_done);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002198 radio->handle_irq = 1;
Anantha Krishnanaf2eafc2012-04-04 11:58:28 +05302199 radio->lp_mode = 1;
Anantha Krishnan93eb1762012-06-04 13:41:07 +05302200 radio->spur_table_size = 0;
Anantha Krishnana2f98082011-10-04 20:02:11 +05302201 atomic_inc(&radio->users);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002202 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
Taniya Das9ac855f2012-02-09 18:05:21 +05302203 flush_workqueue(radio->wqueue);
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302204 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002205}
2206
2207/*
2208 * tavarua_fops - file operations interface
2209 */
2210static const struct v4l2_file_operations tavarua_fops = {
2211 .owner = THIS_MODULE,
2212 .read = tavarua_fops_read,
2213 .write = tavarua_fops_write,
2214 .ioctl = video_ioctl2,
2215 .open = tavarua_fops_open,
2216 .release = tavarua_fops_release,
2217};
2218
2219/*************************************************************************
2220 * Video4Linux Interface
2221 *************************************************************************/
2222
2223/*
2224 * tavarua_v4l2_queryctrl - query control
2225 */
2226static struct v4l2_queryctrl tavarua_v4l2_queryctrl[] = {
2227 {
2228 .id = V4L2_CID_AUDIO_VOLUME,
2229 .type = V4L2_CTRL_TYPE_INTEGER,
2230 .name = "Volume",
2231 .minimum = 0,
2232 .maximum = 15,
2233 .step = 1,
2234 .default_value = 15,
2235 },
2236 {
2237 .id = V4L2_CID_AUDIO_BALANCE,
2238 .flags = V4L2_CTRL_FLAG_DISABLED,
2239 },
2240 {
2241 .id = V4L2_CID_AUDIO_BASS,
2242 .flags = V4L2_CTRL_FLAG_DISABLED,
2243 },
2244 {
2245 .id = V4L2_CID_AUDIO_TREBLE,
2246 .flags = V4L2_CTRL_FLAG_DISABLED,
2247 },
2248 {
2249 .id = V4L2_CID_AUDIO_MUTE,
2250 .type = V4L2_CTRL_TYPE_BOOLEAN,
2251 .name = "Mute",
2252 .minimum = 0,
2253 .maximum = 1,
2254 .step = 1,
2255 .default_value = 1,
2256 },
2257 {
2258 .id = V4L2_CID_AUDIO_LOUDNESS,
2259 .flags = V4L2_CTRL_FLAG_DISABLED,
2260 },
2261 {
2262 .id = V4L2_CID_PRIVATE_TAVARUA_SRCHMODE,
2263 .type = V4L2_CTRL_TYPE_INTEGER,
2264 .name = "Search mode",
2265 .minimum = 0,
2266 .maximum = 7,
2267 .step = 1,
2268 .default_value = 0,
2269 },
2270 {
2271 .id = V4L2_CID_PRIVATE_TAVARUA_SCANDWELL,
2272 .type = V4L2_CTRL_TYPE_INTEGER,
2273 .name = "Search dwell time",
2274 .minimum = 0,
2275 .maximum = 7,
2276 .step = 1,
2277 .default_value = 0,
2278 },
2279 {
2280 .id = V4L2_CID_PRIVATE_TAVARUA_SRCHON,
2281 .type = V4L2_CTRL_TYPE_BOOLEAN,
2282 .name = "Search on/off",
2283 .minimum = 0,
2284 .maximum = 1,
2285 .step = 1,
2286 .default_value = 1,
2287
2288 },
2289 {
2290 .id = V4L2_CID_PRIVATE_TAVARUA_STATE,
2291 .type = V4L2_CTRL_TYPE_INTEGER,
2292 .name = "radio 0ff/rx/tx/reset",
2293 .minimum = 0,
2294 .maximum = 3,
2295 .step = 1,
2296 .default_value = 1,
2297
2298 },
2299 {
2300 .id = V4L2_CID_PRIVATE_TAVARUA_REGION,
2301 .type = V4L2_CTRL_TYPE_INTEGER,
2302 .name = "radio standard",
2303 .minimum = 0,
2304 .maximum = 2,
2305 .step = 1,
2306 .default_value = 0,
2307 },
2308 {
2309 .id = V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH,
2310 .type = V4L2_CTRL_TYPE_INTEGER,
2311 .name = "Signal Threshold",
2312 .minimum = 0x80,
2313 .maximum = 0x7F,
2314 .step = 1,
2315 .default_value = 0,
2316 },
2317 {
2318 .id = V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY,
2319 .type = V4L2_CTRL_TYPE_INTEGER,
2320 .name = "Search PTY",
2321 .minimum = 0,
2322 .maximum = 31,
2323 .default_value = 0,
2324 },
2325 {
2326 .id = V4L2_CID_PRIVATE_TAVARUA_SRCH_PI,
2327 .type = V4L2_CTRL_TYPE_INTEGER,
2328 .name = "Search PI",
2329 .minimum = 0,
2330 .maximum = 0xFF,
2331 .default_value = 0,
2332 },
2333 {
2334 .id = V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT,
2335 .type = V4L2_CTRL_TYPE_INTEGER,
2336 .name = "Preset num",
2337 .minimum = 0,
2338 .maximum = 12,
2339 .default_value = 0,
2340 },
2341 {
2342 .id = V4L2_CID_PRIVATE_TAVARUA_EMPHASIS,
2343 .type = V4L2_CTRL_TYPE_BOOLEAN,
2344 .name = "Emphasis",
2345 .minimum = 0,
2346 .maximum = 1,
2347 .default_value = 0,
2348 },
2349 {
2350 .id = V4L2_CID_PRIVATE_TAVARUA_RDS_STD,
2351 .type = V4L2_CTRL_TYPE_BOOLEAN,
2352 .name = "RDS standard",
2353 .minimum = 0,
2354 .maximum = 1,
2355 .default_value = 0,
2356 },
2357 {
2358 .id = V4L2_CID_PRIVATE_TAVARUA_SPACING,
2359 .type = V4L2_CTRL_TYPE_INTEGER,
2360 .name = "Channel spacing",
2361 .minimum = 0,
2362 .maximum = 2,
2363 .default_value = 0,
2364 },
2365 {
2366 .id = V4L2_CID_PRIVATE_TAVARUA_RDSON,
2367 .type = V4L2_CTRL_TYPE_BOOLEAN,
2368 .name = "RDS on/off",
2369 .minimum = 0,
2370 .maximum = 1,
2371 .default_value = 0,
2372 },
2373 {
2374 .id = V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK,
2375 .type = V4L2_CTRL_TYPE_INTEGER,
2376 .name = "RDS group mask",
2377 .minimum = 0,
2378 .maximum = 0xFFFFFFFF,
2379 .default_value = 0,
2380 },
2381 {
2382 .id = V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC,
2383 .type = V4L2_CTRL_TYPE_INTEGER,
2384 .name = "RDS processing",
2385 .minimum = 0,
2386 .maximum = 0xFF,
2387 .default_value = 0,
2388 },
2389 {
2390 .id = V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF,
2391 .type = V4L2_CTRL_TYPE_INTEGER,
2392 .name = "RDS data groups to buffer",
2393 .minimum = 1,
2394 .maximum = 21,
2395 .default_value = 0,
2396 },
2397 {
2398 .id = V4L2_CID_PRIVATE_TAVARUA_PSALL,
2399 .type = V4L2_CTRL_TYPE_BOOLEAN,
2400 .name = "pass all ps strings",
2401 .minimum = 0,
2402 .maximum = 1,
2403 .default_value = 0,
2404 },
2405 {
2406 .id = V4L2_CID_PRIVATE_TAVARUA_LP_MODE,
2407 .type = V4L2_CTRL_TYPE_BOOLEAN,
2408 .name = "Low power mode",
2409 .minimum = 0,
2410 .maximum = 1,
2411 .default_value = 0,
2412 },
2413 {
2414 .id = V4L2_CID_PRIVATE_TAVARUA_ANTENNA,
2415 .type = V4L2_CTRL_TYPE_BOOLEAN,
2416 .name = "headset/internal",
2417 .minimum = 0,
2418 .maximum = 1,
2419 .default_value = 0,
2420 },
2421 /* Private controls for FM TX*/
2422 {
2423 .id = V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT,
2424 .type = V4L2_CTRL_TYPE_INTEGER,
2425 .name = "Set PS REPEATCOUNT",
2426 .minimum = 0,
2427 .maximum = 15,
2428 },
2429 {
2430 .id = V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_PS_NAME,
2431 .type = V4L2_CTRL_TYPE_BOOLEAN,
2432 .name = "Stop PS NAME",
2433 .minimum = 0,
2434 .maximum = 1,
2435 },
2436 {
2437 .id = V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_RT,
2438 .type = V4L2_CTRL_TYPE_BOOLEAN,
2439 .name = "Stop RT",
2440 .minimum = 0,
2441 .maximum = 1,
2442 },
Anantha Krishnan71d6fa62011-12-13 19:30:51 +05302443 { .id = V4L2_CID_PRIVATE_SET_NOTCH_FILTER,
Srinivasa Rao Uppala4e38bfc2011-09-15 16:00:31 +05302444 .type = V4L2_CTRL_TYPE_INTEGER,
2445 .name = "Notch filter",
2446 .minimum = 0,
2447 .maximum = 2,
2448 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002449
2450};
2451
2452/*=============================================================================
2453FUNCTION: tavarua_vidioc_querycap
2454=============================================================================*/
2455/**
2456 This function is called to query device capabilities.
2457
2458 NOTE:
2459 All V4L2 devices support the VIDIOC_QUERYCAP ioctl. It is used to identify
2460 kernel devices compatible with this specification and to obtain information
2461 about driver and hardware capabilities. The ioctl takes a pointer to a struct
2462 v4l2_capability which is filled by the driver. When the driver is not
2463 compatible with this specification the ioctl returns an EINVAL error code.
2464
2465 @param file: File descriptor returned by open().
2466 @param capability: pointer to struct v4l2_capability.
2467
2468 @return On success 0 is returned, else error code.
2469 @return EINVAL: The device is not compatible with this specification.
2470*/
2471static int tavarua_vidioc_querycap(struct file *file, void *priv,
2472 struct v4l2_capability *capability)
2473{
2474 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2475
2476 strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
2477 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
2478 sprintf(capability->bus_info, "I2C");
2479 capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
2480
2481 capability->version = radio->chipID;
2482
2483 return 0;
2484}
2485
2486/*=============================================================================
2487FUNCTION: tavarua_vidioc_queryctrl
2488=============================================================================*/
2489/**
2490 This function is called to query the device and driver for supported video
2491 controls (enumerate control items).
2492
2493 NOTE:
2494 To query the attributes of a control, the applications set the id field of
2495 a struct v4l2_queryctrl and call the VIDIOC_QUERYCTRL ioctl with a pointer
2496 to this structure. The driver fills the rest of the structure or returns an
2497 EINVAL error code when the id is invalid.
2498
2499 @param file: File descriptor returned by open().
2500 @param qc: pointer to struct v4l2_queryctrl.
2501
2502 @return On success 0 is returned, else error code.
2503 @return EINVAL: The struct v4l2_queryctrl id is invalid.
2504*/
2505static int tavarua_vidioc_queryctrl(struct file *file, void *priv,
2506 struct v4l2_queryctrl *qc)
2507{
2508 unsigned char i;
2509 int retval = -EINVAL;
2510
2511 for (i = 0; i < ARRAY_SIZE(tavarua_v4l2_queryctrl); i++) {
2512 if (qc->id && qc->id == tavarua_v4l2_queryctrl[i].id) {
2513 memcpy(qc, &(tavarua_v4l2_queryctrl[i]), sizeof(*qc));
2514 retval = 0;
2515 break;
2516 }
2517 }
2518 if (retval < 0)
2519 printk(KERN_WARNING DRIVER_NAME
2520 ": query conv4ltrol failed with %d\n", retval);
2521
2522 return retval;
2523}
Anantha Krishnan93eb1762012-06-04 13:41:07 +05302524
2525static int update_spur_table(struct tavarua_device *radio)
2526{
2527 unsigned char xfr_buf[XFR_REG_NUM];
2528 unsigned char size = 0, tbl_size = 0;
2529 int index = 0, offset = 0, addr = 0x0, val = 0;
2530 int retval = 0, temp = 0, cnt = 0, j = 0;
2531
2532 memset(xfr_buf, 0x0, XFR_REG_NUM);
2533
2534 /* Read the SPUR Table Size */
2535 retval = xfr_rdwr_data(radio, XFR_READ, 1, SPUR_TABLE_ADDR, &tbl_size);
2536 if (retval < 0) {
2537 FMDERR("%s: Failed to read SPUR table size\n", __func__);
2538 return retval;
2539 }
2540
2541 /* Calculate the new SPUR Register address */
2542 val = addr = (SPUR_TABLE_START_ADDR + (tbl_size * 3));
2543
2544 /* Save the SPUR Table length configured by user*/
2545 temp = radio->spur_table_size;
2546
2547 /* COnfigure the new spur table length */
2548 size = (radio->spur_table_size + tbl_size);
2549 retval = xfr_rdwr_data(radio, XFR_WRITE, 1, SPUR_TABLE_ADDR, &size);
2550 if (retval < 0) {
2551 FMDERR("%s: Failed to configure SPUR table size\n", __func__);
2552 return retval;
2553 }
2554
2555 /* Program the spur table entries */
2556 for (cnt = 0; cnt < (temp / 4); cnt++) {
2557 offset = 0;
2558 for (j = 0; j < 4; j++) {
2559 xfr_buf[offset++] = GET_FREQ(COMPUTE_SPUR(
2560 radio->spur_data.freq[index]), 1);
2561 xfr_buf[offset++] = GET_FREQ(COMPUTE_SPUR(
2562 radio->spur_data.freq[index]), 0);
2563 xfr_buf[offset++] =
2564 radio->spur_data.rmssi[index];
2565 index++;
2566 }
2567 retval = xfr_rdwr_data(radio, XFR_WRITE, (SPUR_DATA_SIZE * 4),
2568 addr, xfr_buf);
2569 if (retval < 0) {
2570 FMDERR("%s: Failed to program SPUR frequencies\n",
2571 __func__);
2572 return retval;
2573 }
2574 addr += (SPUR_DATA_SIZE * 4);
2575 }
2576
2577 /* Program the additional SPUR Frequencies */
2578 temp = radio->spur_table_size;
2579 temp = (temp % 4);
2580 if (temp > 0) {
2581 offset = 0;
2582 for (j = 0; j < temp; j++) {
2583 xfr_buf[offset++] = GET_FREQ(COMPUTE_SPUR(
2584 radio->spur_data.freq[index]), 1);
2585 xfr_buf[offset++] = GET_FREQ(COMPUTE_SPUR(
2586 radio->spur_data.freq[index]), 0);
2587 xfr_buf[offset++] =
2588 radio->spur_data.rmssi[index];
2589 index++;
2590 }
2591 size = (temp * SPUR_DATA_SIZE);
2592 retval = xfr_rdwr_data(radio, XFR_WRITE, size, addr, xfr_buf);
2593 if (retval < 0) {
2594 FMDERR("%s: Failed to program SPUR frequencies\n",
2595 __func__);
2596 return retval;
2597 }
2598 }
2599
2600 return retval;
2601}
2602
2603static int xfr_rdwr_data(struct tavarua_device *radio, int op, int size,
2604 unsigned long offset, unsigned char *buf) {
2605
2606 unsigned char xfr_buf[XFR_REG_NUM];
2607 int retval = 0, temp = 0;
2608
2609 memset(xfr_buf, 0x0, XFR_REG_NUM);
2610 temp = size;
2611
2612 xfr_buf[XFR_MODE_OFFSET] = (size << 1);
2613 xfr_buf[XFR_ADDR_MSB_OFFSET] = GET_FREQ(offset, 1);
2614 xfr_buf[XFR_ADDR_LSB_OFFSET] = GET_FREQ(offset, 0);
2615
2616 if (op == XFR_READ) {
2617 xfr_buf[XFR_MODE_OFFSET] |= (XFR_PEEK_MODE);
2618 size = 3;
2619 } else if (op == XFR_WRITE) {
2620 xfr_buf[XFR_MODE_OFFSET] |= (XFR_POKE_MODE);
2621 memcpy(&xfr_buf[XFR_DATA_OFFSET], buf, size);
2622 size += 3;
2623 }
2624
2625 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, size);
2626 if (retval < 0) {
2627 FMDERR("%s: Failed to performXFR operation\n", __func__);
2628 return retval;
2629 }
2630
2631 size = temp;
2632
2633 /*Wait for the XFR interrupt */
2634 init_completion(&radio->sync_req_done);
2635 if (!wait_for_completion_timeout(&radio->sync_req_done,
2636 msecs_to_jiffies(WAIT_TIMEOUT))) {
2637 FMDERR("Timeout: No XFR interrupt");
2638 }
2639
2640 if (op == XFR_READ) {
2641 retval = tavarua_read_registers(radio, XFRDAT0, size);
2642 if (retval < 0) {
2643 FMDERR("%s: Failed to read the XFR data\n", __func__);
2644 return retval;
2645 }
2646 if (buf != NULL)
2647 memcpy(buf, &radio->registers[XFRDAT0], size);
2648 }
2649
2650 return retval;
2651}
2652
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002653static int peek_MPX_DCC(struct tavarua_device *radio)
2654{
2655 int retval = 0;
2656 unsigned char xfr_buf[XFR_REG_NUM];
2657 int MPX_DCC[] = { 0 };
2658 int DCC = 0;
2659 int ct = 0;
2660 unsigned char size = 0;
2661
2662 /*
2663 Poking the MPX_DCC_BYPASS register to freeze the
2664 value of MPX_DCC from changing while we access it
2665 */
2666
2667 /*Poking the MPX_DCC_BYPASS register : 0x88C0 */
2668 size = 0x01;
2669 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
2670 xfr_buf[1] = MPX_DCC_BYPASS_POKE_MSB;
2671 xfr_buf[2] = MPX_DCC_BYPASS_POKE_LSB;
2672 xfr_buf[3] = 0x01;
2673
2674 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 4);
2675 if (retval < 0) {
2676 FMDBG("Failed to write\n");
2677 return retval;
2678 }
2679 /*Wait for the XFR interrupt */
2680 msleep(TAVARUA_DELAY*15);
2681
2682 for (ct = 0; ct < 5; ct++)
2683 xfr_buf[ct] = 0;
2684
2685 /* Peeking Regs 0x88C2-0x88C4 */
2686 size = 0x03;
2687 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
2688 xfr_buf[1] = MPX_DCC_PEEK_MSB_REG1;
2689 xfr_buf[2] = MPX_DCC_PEEK_LSB_REG1;
2690 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
2691 if (retval < 0) {
2692 FMDBG("Failed to write\n");
2693 return retval;
2694 }
2695 /*Wait for the XFR interrupt */
2696 msleep(TAVARUA_DELAY*10);
2697 retval = tavarua_read_registers(radio, XFRDAT0, 3);
2698 if (retval < 0) {
2699 printk(KERN_INFO "INT_DET: Read failure\n");
2700 return retval;
2701 }
2702 MPX_DCC[0] = (int)radio->registers[XFRDAT0];
2703 MPX_DCC[1] = (int)radio->registers[XFRDAT1];
2704 MPX_DCC[2] = (int)radio->registers[XFRDAT2];
2705
2706 /*
2707 Form the final MPX_DCC parameter
2708 MPX_DCC[0] will form the LSB part
2709 MPX_DCC[1] will be the middle part and 4 bits of
2710 MPX_DCC[2] will be the MSB par of the 20-bit signed MPX_DCC
2711 */
2712
2713 DCC = ((int)MPX_DCC[2] << 16) | ((int)MPX_DCC[1] << 8) |
2714 ((int)MPX_DCC[0]);
2715
2716 /*
2717 if bit-19 is '1',set remaining bits to '1' & make it -tive
2718 */
2719 if (DCC & 0x00080000) {
2720 FMDBG(KERN_INFO "bit-19 is '1'\n");
2721 DCC |= 0xFFF00000;
2722 }
2723
2724 /*
2725 Poking the MPX_DCC_BYPASS register to be back to normal
2726 */
2727
2728 /*Poking the MPX_DCC_BYPASS register : 0x88C0 */
2729 size = 0x01;
2730 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
2731 xfr_buf[1] = MPX_DCC_BYPASS_POKE_MSB;
2732 xfr_buf[2] = MPX_DCC_BYPASS_POKE_LSB;
2733 xfr_buf[3] = 0x00;
2734
2735 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 4);
2736 if (retval < 0) {
2737 FMDBG("Failed to write\n");
2738 return retval;
2739 }
2740 /*Wait for the XFR interrupt */
2741 msleep(TAVARUA_DELAY*10);
2742
2743 return DCC;
2744}
2745/*=============================================================================
2746FUNCTION: tavarua_vidioc_g_ctrl
2747=============================================================================*/
2748/**
2749 This function is called to get the value of a control.
2750
2751 NOTE:
2752 To get the current value of a control, applications initialize the id field
2753 of a struct v4l2_control and call the VIDIOC_G_CTRL ioctl with a pointer to
2754 this structure.
2755
2756 When the id is invalid drivers return an EINVAL error code. When the value is
2757 out of bounds drivers can choose to take the closest valid value or return an
2758 ERANGE error code, whatever seems more appropriate.
2759
2760 @param file: File descriptor returned by open().
2761 @param ctrl: pointer to struct v4l2_control.
2762
2763 @return On success 0 is returned, else error code.
2764 @return EINVAL: The struct v4l2_control id is invalid.
2765 @return ERANGE: The struct v4l2_control value is out of bounds.
2766 @return EBUSY: The control is temporarily not changeable, possibly because
2767 another applications took over control of the device function this control
2768 belongs to.
2769*/
2770static int tavarua_vidioc_g_ctrl(struct file *file, void *priv,
2771 struct v4l2_control *ctrl)
2772{
2773 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2774 int retval = 0;
Anantha Krishnana3dcce42012-01-05 19:27:57 +05302775 int cnt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002776 unsigned char xfr_buf[XFR_REG_NUM];
2777 signed char cRmssiThreshold;
2778 signed char ioc;
2779 unsigned char size = 0;
2780
2781 switch (ctrl->id) {
2782 case V4L2_CID_AUDIO_VOLUME:
2783 break;
2784 case V4L2_CID_AUDIO_MUTE:
2785 ctrl->value = radio->registers[IOCTRL] & 0x03 ;
2786 break;
2787 case V4L2_CID_PRIVATE_TAVARUA_SRCHMODE:
2788 ctrl->value = radio->registers[SRCHCTRL] & SRCH_MODE;
2789 break;
2790 case V4L2_CID_PRIVATE_TAVARUA_SCANDWELL:
2791 ctrl->value = (radio->registers[SRCHCTRL] & SCAN_DWELL) >> 4;
2792 break;
2793 case V4L2_CID_PRIVATE_TAVARUA_SRCHON:
2794 ctrl->value = (radio->registers[SRCHCTRL] & SRCH_ON) >> 7 ;
2795 break;
2796 case V4L2_CID_PRIVATE_TAVARUA_STATE:
2797 ctrl->value = (radio->registers[RDCTRL] & 0x03);
2798 break;
2799 case V4L2_CID_PRIVATE_TAVARUA_IOVERC:
2800 retval = tavarua_read_registers(radio, IOVERC, 1);
2801 if (retval < 0)
2802 return retval;
2803 ioc = radio->registers[IOVERC];
2804 ctrl->value = ioc;
2805 break;
2806 case V4L2_CID_PRIVATE_TAVARUA_INTDET:
2807 size = 0x1;
2808 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
2809 xfr_buf[1] = INTDET_PEEK_MSB;
2810 xfr_buf[2] = INTDET_PEEK_LSB;
2811 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
2812 if (retval < 0) {
2813 FMDBG("Failed to write\n");
2814 return retval;
2815 }
2816 FMDBG("INT_DET:Sync write success\n");
2817 /*Wait for the XFR interrupt */
2818 msleep(TAVARUA_DELAY*10);
2819 /* Read the XFRDAT0 register populated by FM SoC */
2820 retval = tavarua_read_registers(radio, XFRDAT0, 3);
2821 if (retval < 0) {
2822 FMDBG("INT_DET: Read failure\n");
2823 return retval;
2824 }
2825 ctrl->value = radio->registers[XFRDAT0];
2826 break;
2827 case V4L2_CID_PRIVATE_TAVARUA_MPX_DCC:
2828 ctrl->value = peek_MPX_DCC(radio);
2829 break;
2830 case V4L2_CID_PRIVATE_TAVARUA_REGION:
2831 ctrl->value = radio->region_params.region;
2832 break;
2833 case V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH:
2834 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
2835 if (retval < 0) {
2836 FMDBG("[G IOCTL=V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
2837 FMDBG("sync_read_xfr error: [retval=%d]\n", retval);
2838 break;
2839 }
2840 /* Since RMSSI Threshold is signed value */
2841 cRmssiThreshold = (signed char)xfr_buf[0];
2842 ctrl->value = cRmssiThreshold;
2843 FMDBG("cRmssiThreshold: %d\n", cRmssiThreshold);
2844 break;
2845 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY:
2846 ctrl->value = radio->srch_params.srch_pty;
2847 break;
2848 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PI:
2849 ctrl->value = radio->srch_params.srch_pi;
2850 break;
2851 case V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT:
2852 ctrl->value = radio->srch_params.preset_num;
2853 break;
2854 case V4L2_CID_PRIVATE_TAVARUA_EMPHASIS:
2855 ctrl->value = radio->region_params.emphasis;
2856 break;
2857 case V4L2_CID_PRIVATE_TAVARUA_RDS_STD:
2858 ctrl->value = radio->region_params.rds_std;
2859 break;
2860 case V4L2_CID_PRIVATE_TAVARUA_SPACING:
2861 ctrl->value = radio->region_params.spacing;
2862 break;
2863 case V4L2_CID_PRIVATE_TAVARUA_RDSON:
2864 ctrl->value = radio->registers[RDSCTRL] & RDS_ON;
2865 break;
2866 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK:
2867 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
2868 if (retval > -1)
2869 ctrl->value = (xfr_buf[8] << 24) |
2870 (xfr_buf[9] << 16) |
2871 (xfr_buf[10] << 8) |
2872 xfr_buf[11];
2873 break;
2874 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC:
2875 retval = tavarua_read_registers(radio, ADVCTRL, 1);
2876 if (retval > -1)
2877 ctrl->value = radio->registers[ADVCTRL];
Anantha Krishnane46ef6f2011-06-29 23:56:03 +05302878 msleep(TAVARUA_DELAY*5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002879 break;
Anantha Krishnan3be3b262011-09-05 17:22:48 +05302880 case V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA:
2881 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
2882 if (retval < 0) {
2883 FMDERR("V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA]\n");
2884 FMDERR("sync_read_xfr [retval=%d]\n", retval);
2885 break;
2886 }
2887 ctrl->value = (unsigned char)xfr_buf[4];
2888 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002889 case V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF:
2890 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
2891 if (retval > -1)
2892 ctrl->value = xfr_buf[1];
2893 break;
2894 case V4L2_CID_PRIVATE_TAVARUA_PSALL:
2895 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
2896 if (retval > -1)
2897 ctrl->value = xfr_buf[12] & RDS_CONFIG_PSALL;
2898 break;
2899 case V4L2_CID_PRIVATE_TAVARUA_LP_MODE:
2900 ctrl->value = radio->lp_mode;
2901 break;
2902 case V4L2_CID_PRIVATE_TAVARUA_ANTENNA:
2903 ctrl->value = GET_REG_FIELD(radio->registers[IOCTRL],
2904 IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
2905 break;
Anantha Krishnana3dcce42012-01-05 19:27:57 +05302906 case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
2907 size = 0x04;
2908 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
2909 xfr_buf[1] = ON_CHANNEL_TH_MSB;
2910 xfr_buf[2] = ON_CHANNEL_TH_LSB;
2911 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
2912 if (retval < 0) {
2913 pr_err("%s: Failed to write\n", __func__);
2914 return retval;
2915 }
2916 /*Wait for the XFR interrupt */
2917 msleep(TAVARUA_DELAY*10);
2918 retval = tavarua_read_registers(radio, XFRDAT0, 4);
2919 if (retval < 0) {
2920 pr_err("%s: On Ch. DET: Read failure\n", __func__);
2921 return retval;
2922 }
2923 for (cnt = 0; cnt < 4; cnt++)
2924 FMDBG("On-Channel data set is : 0x%x\t",
2925 (int)radio->registers[XFRDAT0+cnt]);
2926
2927 ctrl->value = LSH_DATA(radio->registers[XFRDAT0], 24) |
2928 LSH_DATA(radio->registers[XFRDAT0+1], 16) |
2929 LSH_DATA(radio->registers[XFRDAT0+2], 8) |
2930 (radio->registers[XFRDAT0+3]);
2931 FMDBG("The On Channel Threshold value is : 0x%x", ctrl->value);
2932 break;
2933 case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
2934 size = 0x04;
2935 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
2936 xfr_buf[1] = OFF_CHANNEL_TH_MSB;
2937 xfr_buf[2] = OFF_CHANNEL_TH_LSB;
2938 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
2939 if (retval < 0) {
2940 pr_err("%s: Failed to write\n", __func__);
2941 return retval;
2942 }
2943 /*Wait for the XFR interrupt */
2944 msleep(TAVARUA_DELAY*10);
2945 retval = tavarua_read_registers(radio, XFRDAT0, 4);
2946 if (retval < 0) {
2947 pr_err("%s: Off Ch. DET: Read failure\n", __func__);
2948 return retval;
2949 }
2950 for (cnt = 0; cnt < 4; cnt++)
2951 FMDBG("Off-channel data set is : 0x%x\t",
2952 (int)radio->registers[XFRDAT0+cnt]);
2953
2954 ctrl->value = LSH_DATA(radio->registers[XFRDAT0], 24) |
2955 LSH_DATA(radio->registers[XFRDAT0+1], 16) |
2956 LSH_DATA(radio->registers[XFRDAT0+2], 8) |
2957 (radio->registers[XFRDAT0+3]);
2958 FMDBG("The Off Channel Threshold value is : 0x%x", ctrl->value);
2959 break;
2960 /*
2961 * These IOCTL's are place holders to keep the
2962 * driver compatible with change in frame works for IRIS
2963 */
2964 case V4L2_CID_PRIVATE_SINR_THRESHOLD:
2965 case V4L2_CID_PRIVATE_SINR_SAMPLES:
2966 case V4L2_CID_PRIVATE_IRIS_GET_SINR:
2967 retval = 0;
2968 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002969 default:
2970 retval = -EINVAL;
2971 }
2972 if (retval < 0)
2973 printk(KERN_WARNING DRIVER_NAME
2974 ": get control failed with %d, id: %d\n", retval, ctrl->id);
2975
2976 return retval;
2977}
2978
2979static int tavarua_vidioc_s_ext_ctrls(struct file *file, void *priv,
2980 struct v4l2_ext_controls *ctrl)
2981{
2982 int retval = 0;
2983 int bytes_to_copy;
2984 int bytes_copied = 0;
2985 int bytes_left = 0;
2986 int chunk_index = 0;
2987 char tx_data[XFR_REG_NUM];
2988 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2989 char *data = NULL;
2990 int extra_name_byte = 0;
2991 int name_bytes = 0;
2992
2993 switch ((ctrl->controls[0]).id) {
2994 case V4L2_CID_RDS_TX_PS_NAME: {
2995 FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
2996 /*Pass a sample PS string */
2997
2998 chunk_index = 0;
2999 bytes_copied = 0;
3000 bytes_left = min((int)(ctrl->controls[0]).size,
3001 MAX_PS_LENGTH);
3002 data = (ctrl->controls[0]).string;
3003
3004 /* send payload to FM hardware */
3005 while (bytes_left) {
3006 chunk_index++;
3007 FMDBG("chunk is %d", chunk_index);
3008 bytes_to_copy = min(bytes_left, XFR_REG_NUM);
3009 /*Clear the tx_data */
3010 memset(tx_data, 0, XFR_REG_NUM);
3011 if (copy_from_user(tx_data,
3012 data + bytes_copied, bytes_to_copy))
3013 return -EFAULT;
3014 retval = sync_write_xfr(radio,
3015 RDS_PS_0 + chunk_index, tx_data);
3016 if (retval < 0) {
3017 FMDBG("sync_write_xfr: %d", retval);
3018 return retval;
3019 }
3020 bytes_copied += bytes_to_copy;
3021 bytes_left -= bytes_to_copy;
3022 }
3023 memset(tx_data, 0, XFR_REG_NUM);
3024 /*Write the PS Header*/
3025 FMDBG("Writing PS header\n");
3026 extra_name_byte = (bytes_copied%8) ? 1 : 0;
3027 name_bytes = (bytes_copied/8) + extra_name_byte;
3028 /*8 bytes are grouped as 1 name */
3029 tx_data[0] = (name_bytes) & MASK_TXREPCOUNT;
3030 tx_data[1] = radio->pty & MASK_PTY; /* PTY */
3031 tx_data[2] = ((radio->pi & MASK_PI_MSB) >> 8);
3032 tx_data[3] = radio->pi & MASK_PI_LSB;
3033 /* TX ctrl + repeatCount*/
3034 tx_data[4] = TX_ON |
3035 (radio->ps_repeatcount & MASK_TXREPCOUNT);
3036 retval = sync_write_xfr(radio, RDS_PS_0, tx_data);
3037 if (retval < 0) {
3038 FMDBG("sync_write_xfr returned %d", retval);
3039 return retval;
3040 }
3041 } break;
3042 case V4L2_CID_RDS_TX_RADIO_TEXT: {
3043 chunk_index = 0;
3044 bytes_copied = 0;
3045 FMDBG("In V4L2_CID_RDS_TX_RADIO_TEXT\n");
3046 /*Pass a sample PS string */
3047 FMDBG("Passed RT String : %s\n",
3048 (ctrl->controls[0]).string);
3049 bytes_left =
3050 min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
3051 data = (ctrl->controls[0]).string;
3052 /* send payload to FM hardware */
3053 while (bytes_left) {
3054 chunk_index++;
3055 bytes_to_copy = min(bytes_left, XFR_REG_NUM);
3056 memset(tx_data, 0, XFR_REG_NUM);
3057 if (copy_from_user(tx_data,
3058 data + bytes_copied, bytes_to_copy))
3059 return -EFAULT;
3060 retval = sync_write_xfr(radio,
3061 RDS_RT_0 + chunk_index, tx_data);
3062 if (retval < 0)
3063 return retval;
3064 bytes_copied += bytes_to_copy;
3065 bytes_left -= bytes_to_copy;
3066 }
3067 /*Write the RT Header */
3068 tx_data[0] = bytes_copied;
3069 /* PTY */
3070 tx_data[1] = TX_ON | ((radio->pty & MASK_PTY) >> 8);
3071 /* PI high */
3072 tx_data[2] = ((radio->pi & MASK_PI_MSB) >> 8);
3073 /* PI low */
3074 tx_data[3] = radio->pi & MASK_PI_LSB;
3075 retval = sync_write_xfr(radio, RDS_RT_0 , tx_data);
3076 if (retval < 0)
3077 return retval;
3078 FMDBG("done RT writing: %d\n", retval);
3079 } break;
3080 default:
3081 {
3082 FMDBG("Shouldn't reach here\n");
3083 retval = -1;
3084 }
3085 }
3086 return retval;
3087}
3088
3089/*=============================================================================
3090FUNCTION: tavarua_vidioc_s_ctrl
3091=============================================================================*/
3092/**
3093 This function is called to set the value of a control.
3094
3095 NOTE:
3096 To change the value of a control, applications initialize the id and value
3097 fields of a struct v4l2_control and call the VIDIOC_S_CTRL ioctl.
3098
3099 When the id is invalid drivers return an EINVAL error code. When the value is
3100 out of bounds drivers can choose to take the closest valid value or return an
3101 ERANGE error code, whatever seems more appropriate.
3102
3103 @param file: File descriptor returned by open().
3104 @param ctrl: pointer to struct v4l2_control.
3105
3106 @return On success 0 is returned, else error code.
3107 @return EINVAL: The struct v4l2_control id is invalid.
3108 @return ERANGE: The struct v4l2_control value is out of bounds.
3109 @return EBUSY: The control is temporarily not changeable, possibly because
3110 another applications took over control of the device function this control
3111 belongs to.
3112*/
3113static int tavarua_vidioc_s_ctrl(struct file *file, void *priv,
3114 struct v4l2_control *ctrl)
3115{
3116 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3117 int retval = 0;
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303118 int size = 0, cnt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003119 unsigned char value;
3120 unsigned char xfr_buf[XFR_REG_NUM];
3121 unsigned char tx_data[XFR_REG_NUM];
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05303122 unsigned char dis_buf[XFR_REG_NUM];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003123
3124 switch (ctrl->id) {
3125 case V4L2_CID_AUDIO_VOLUME:
3126 break;
3127 case V4L2_CID_AUDIO_MUTE:
3128 value = (radio->registers[IOCTRL] & ~IOC_HRD_MUTE) |
3129 (ctrl->value & 0x03);
3130 retval = tavarua_write_register(radio, IOCTRL, value);
3131 break;
3132 case V4L2_CID_PRIVATE_TAVARUA_SRCHMODE:
3133 value = (radio->registers[SRCHCTRL] & ~SRCH_MODE) |
3134 ctrl->value;
3135 radio->registers[SRCHCTRL] = value;
3136 break;
3137 case V4L2_CID_PRIVATE_TAVARUA_SCANDWELL:
3138 value = (radio->registers[SRCHCTRL] & ~SCAN_DWELL) |
3139 (ctrl->value << 4);
3140 radio->registers[SRCHCTRL] = value;
3141 break;
3142 /* start/stop search */
3143 case V4L2_CID_PRIVATE_TAVARUA_SRCHON:
3144 FMDBG("starting search\n");
3145 tavarua_search(radio, ctrl->value, SRCH_DIR_UP);
3146 break;
3147 case V4L2_CID_PRIVATE_TAVARUA_STATE:
3148 /* check if already on */
3149 radio->handle_irq = 1;
3150 if (((ctrl->value == FM_RECV) || (ctrl->value == FM_TRANS))
3151 && !(radio->registers[RDCTRL] &
3152 ctrl->value)) {
3153 FMDBG("clearing flags\n");
3154 init_completion(&radio->sync_xfr_start);
3155 init_completion(&radio->sync_req_done);
3156 radio->xfr_in_progress = 0;
3157 radio->xfr_bytes_left = 0;
3158 FMDBG("turning on ..\n");
3159 retval = tavarua_start(radio, ctrl->value);
3160 if (retval >= 0) {
Anantha Krishnanc72725a2011-09-06 09:28:22 +05303161 /* Enabling 'SoftMute' & 'SignalBlending' */
3162 value = (radio->registers[IOCTRL] |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003163 IOC_SFT_MUTE | IOC_SIG_BLND);
Anantha Krishnanc72725a2011-09-06 09:28:22 +05303164 retval = tavarua_write_register(radio,
3165 IOCTRL, value);
3166 if (retval < 0)
3167 FMDBG("SMute and SBlending"
3168 "not enabled\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003169 }
3170 }
3171 /* check if off */
3172 else if ((ctrl->value == FM_OFF) && radio->registers[RDCTRL]) {
Anantha Krishnan93eb1762012-06-04 13:41:07 +05303173 radio->spur_table_size = 0;
Anantha Krishnan1475c932012-02-16 21:54:03 +05303174 FMDBG("%s: turning off...\n", __func__);
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05303175 tavarua_write_register(radio, RDCTRL, ctrl->value);
3176 /* flush the event and work queues */
3177 kfifo_reset(&radio->data_buf[TAVARUA_BUF_EVENTS]);
3178 flush_workqueue(radio->wqueue);
3179 /*
3180 * queue the READY event from the host side
3181 * in case of FM off
3182 */
Ayaz Ahmad0fa19842012-03-14 22:54:53 +05303183 tavarua_q_event(radio, TAVARUA_EVT_RADIO_DISABLED);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003184
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05303185 FMDBG("%s, Disable All Interrupts\n", __func__);
3186 /* disable irq */
3187 dis_buf[STATUS_REG1] = 0x00;
3188 dis_buf[STATUS_REG2] = 0x00;
3189 dis_buf[STATUS_REG3] = TRANSFER;
3190 retval = sync_write_xfr(radio, INT_CTRL, dis_buf);
3191 if (retval < 0) {
3192 pr_err("%s: failed to disable"
3193 "Interrupts\n", __func__);
3194 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003195 }
3196 }
3197 break;
Anantha Krishnanc72725a2011-09-06 09:28:22 +05303198 case V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH:
3199 FMDBG("Setting audio path ...\n");
3200 if (ctrl->value == FM_DIGITAL_PATH) {
3201 FMDBG("Digital audio path enabled ...\n");
3202 retval = tavarua_set_audio_path(
3203 TAVARUA_AUDIO_OUT_DIGITAL_ON,
3204 TAVARUA_AUDIO_OUT_ANALOG_OFF);
3205 if (retval < 0) {
3206 FMDERR("Error in tavarua_set_audio_path"
3207 " %d\n", retval);
3208 }
3209 } else if (ctrl->value == FM_ANALOG_PATH) {
3210 FMDBG("Analog audio path enabled ...\n");
3211 retval = tavarua_set_audio_path(
Venkateshwarlu Domakondab49c2cb2012-04-17 17:44:50 +05303212 TAVARUA_AUDIO_OUT_DIGITAL_OFF,
3213 TAVARUA_AUDIO_OUT_ANALOG_ON);
Anantha Krishnanc72725a2011-09-06 09:28:22 +05303214 if (retval < 0) {
3215 FMDERR("Error in tavarua_set_audio_path"
3216 " %d\n", retval);
3217 }
3218 }
3219 break;
Anantha Krishnan40bcd052011-12-05 15:28:29 +05303220 case V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM:
3221 radio->enable_optimized_srch_alg = ctrl->value;
3222 FMDBG("V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM : %d",
3223 radio->enable_optimized_srch_alg);
3224 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003225 case V4L2_CID_PRIVATE_TAVARUA_REGION:
3226 retval = tavarua_set_region(radio, ctrl->value);
3227 break;
3228 case V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH:
3229 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
3230 if (retval < 0) {
3231 FMDERR("V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
3232 FMDERR("sync_read_xfr [retval=%d]\n", retval);
3233 break;
3234 }
3235 /* RMSSI Threshold is a signed 8 bit value */
3236 xfr_buf[0] = (unsigned char)ctrl->value;
3237 xfr_buf[1] = (unsigned char)ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003238 retval = sync_write_xfr(radio, RX_CONFIG, xfr_buf);
3239 if (retval < 0) {
3240 FMDERR("V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
3241 FMDERR("sync_write_xfr [retval=%d]\n", retval);
3242 break;
3243 }
3244 break;
3245 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY:
3246 radio->srch_params.srch_pty = ctrl->value;
3247 break;
3248 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PI:
3249 radio->srch_params.srch_pi = ctrl->value;
3250 break;
3251 case V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT:
3252 radio->srch_params.preset_num = ctrl->value;
3253 break;
3254 case V4L2_CID_PRIVATE_TAVARUA_EMPHASIS:
3255 radio->region_params.emphasis = ctrl->value;
3256 break;
3257 case V4L2_CID_PRIVATE_TAVARUA_RDS_STD:
3258 radio->region_params.rds_std = ctrl->value;
3259 break;
3260 case V4L2_CID_PRIVATE_TAVARUA_SPACING:
3261 radio->region_params.spacing = ctrl->value;
3262 break;
3263 case V4L2_CID_PRIVATE_TAVARUA_RDSON:
3264 retval = 0;
3265 if (ctrl->value != (radio->registers[RDSCTRL] & RDS_ON)) {
3266 value = radio->registers[RDSCTRL] | ctrl->value;
3267 retval = tavarua_write_register(radio, RDSCTRL, value);
3268 }
3269 break;
3270 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK:
3271 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
3272 if (retval < 0)
3273 break;
3274 xfr_buf[8] = (ctrl->value & 0xFF000000) >> 24;
3275 xfr_buf[9] = (ctrl->value & 0x00FF0000) >> 16;
3276 xfr_buf[10] = (ctrl->value & 0x0000FF00) >> 8;
3277 xfr_buf[11] = (ctrl->value & 0x000000FF);
3278 retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
3279 break;
3280 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC:
Anantha Krishnane46ef6f2011-06-29 23:56:03 +05303281 value = radio->registers[ADVCTRL] | ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003282 retval = tavarua_write_register(radio, ADVCTRL, value);
3283 break;
Anantha Krishnane46ef6f2011-06-29 23:56:03 +05303284 case V4L2_CID_PRIVATE_TAVARUA_AF_JUMP:
3285 retval = tavarua_read_registers(radio, ADVCTRL, 1);
3286 SET_REG_FIELD(radio->registers[ADVCTRL], ctrl->value,
3287 RDSAF_OFFSET, RDSAF_MASK);
3288 msleep(TAVARUA_DELAY*5);
3289 retval = tavarua_write_register(radio,
3290 ADVCTRL, radio->registers[ADVCTRL]);
3291 msleep(TAVARUA_DELAY*5);
3292 break;
Anantha Krishnan3b44cd42011-07-06 12:36:15 +05303293 case V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA:
3294 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
3295 if (retval < 0) {
3296 FMDERR("V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA]\n");
3297 FMDERR("sync_read_xfr [retval=%d]\n", retval);
3298 break;
3299 }
3300 xfr_buf[4] = (unsigned char)ctrl->value;
3301 retval = sync_write_xfr(radio, RX_CONFIG, xfr_buf);
3302 if (retval < 0) {
3303 FMDERR("V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA]\n");
3304 FMDERR("sync_write_xfr [retval=%d]\n", retval);
3305 break;
3306 }
3307 break;
Anantha Krishnanf2258602011-06-30 01:32:09 +05303308 case V4L2_CID_PRIVATE_TAVARUA_HLSI:
3309 retval = tavarua_read_registers(radio, RDCTRL, 1);
3310 SET_REG_FIELD(radio->registers[RDCTRL], ctrl->value,
3311 RDCTRL_HLSI_OFFSET, RDCTRL_HLSI_MASK);
3312 retval = tavarua_write_register(radio, RDCTRL,
3313 radio->registers[RDCTRL]);
3314 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003315 case V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF:
3316 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
3317 if (retval < 0)
3318 break;
3319 xfr_buf[1] = ctrl->value;
3320 retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
3321 break;
3322 case V4L2_CID_PRIVATE_TAVARUA_PSALL:
3323 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
3324 value = ctrl->value & RDS_CONFIG_PSALL;
3325 if (retval < 0)
3326 break;
3327 xfr_buf[12] &= ~RDS_CONFIG_PSALL;
3328 xfr_buf[12] |= value;
3329 retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
3330 break;
3331 case V4L2_CID_PRIVATE_TAVARUA_LP_MODE:
3332 retval = 0;
3333 if (ctrl->value == radio->lp_mode)
3334 break;
3335 if (ctrl->value) {
3336 FMDBG("going into low power mode\n");
3337 retval = tavarua_disable_interrupts(radio);
3338 } else {
3339 FMDBG("going into normal power mode\n");
3340 tavarua_setup_interrupts(radio,
3341 (radio->registers[RDCTRL] & 0x03));
3342 }
3343 break;
3344 case V4L2_CID_PRIVATE_TAVARUA_ANTENNA:
3345 SET_REG_FIELD(radio->registers[IOCTRL], ctrl->value,
3346 IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
3347 break;
Anantha Krishnana3dcce42012-01-05 19:27:57 +05303348 case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303349 size = 0x04;
3350 /* Poking the value of ON Channel Threshold value */
3351 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
3352 xfr_buf[1] = ON_CHANNEL_TH_MSB;
3353 xfr_buf[2] = ON_CHANNEL_TH_LSB;
3354 /* Data to be poked into the register */
3355 xfr_buf[3] = (ctrl->value & 0xFF000000) >> 24;
3356 xfr_buf[4] = (ctrl->value & 0x00FF0000) >> 16;
3357 xfr_buf[5] = (ctrl->value & 0x0000FF00) >> 8;
3358 xfr_buf[6] = (ctrl->value & 0x000000FF);
3359
3360 for (cnt = 3; cnt < 7; cnt++) {
3361 FMDBG("On-channel data to be poked is : %d",
3362 (int)xfr_buf[cnt]);
3363 }
3364
3365 retval = tavarua_write_registers(radio, XFRCTRL,
3366 xfr_buf, size+3);
3367 if (retval < 0) {
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303368 pr_err("%s: Failed to write\n", __func__);
3369 return retval;
3370 }
3371 /*Wait for the XFR interrupt */
3372 msleep(TAVARUA_DELAY*10);
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303373 break;
Anantha Krishnana3dcce42012-01-05 19:27:57 +05303374 case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303375 size = 0x04;
3376 /* Poking the value of OFF Channel Threshold value */
3377 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
3378 xfr_buf[1] = OFF_CHANNEL_TH_MSB;
3379 xfr_buf[2] = OFF_CHANNEL_TH_LSB;
3380 /* Data to be poked into the register */
3381 xfr_buf[3] = (ctrl->value & 0xFF000000) >> 24;
3382 xfr_buf[4] = (ctrl->value & 0x00FF0000) >> 16;
3383 xfr_buf[5] = (ctrl->value & 0x0000FF00) >> 8;
3384 xfr_buf[6] = (ctrl->value & 0x000000FF);
3385
3386 for (cnt = 3; cnt < 7; cnt++) {
3387 FMDBG("Off-channel data to be poked is : %d",
3388 (int)xfr_buf[cnt]);
3389 }
3390
3391 retval = tavarua_write_registers(radio, XFRCTRL,
3392 xfr_buf, size+3);
3393 if (retval < 0) {
3394 pr_err("%s: Failed to write\n", __func__);
3395 return retval;
3396 }
3397 /*Wait for the XFR interrupt */
3398 msleep(TAVARUA_DELAY*10);
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303399 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003400 /* TX Controls */
3401
3402 case V4L2_CID_RDS_TX_PTY: {
3403 radio->pty = ctrl->value;
3404 } break;
3405 case V4L2_CID_RDS_TX_PI: {
3406 radio->pi = ctrl->value;
3407 } break;
3408 case V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_PS_NAME: {
3409 FMDBG("In STOP_RDS_TX_PS_NAME\n");
3410 /*Pass a sample PS string */
3411 memset(tx_data, '0', XFR_REG_NUM);
3412 FMDBG("Writing PS header\n");
3413 retval = sync_write_xfr(radio, RDS_PS_0, tx_data);
3414 FMDBG("retval of PS Header write: %d", retval);
3415
3416 } break;
3417
3418 case V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_RT: {
3419 memset(tx_data, '0', XFR_REG_NUM);
3420 FMDBG("Writing RT header\n");
3421 retval = sync_write_xfr(radio, RDS_RT_0, tx_data);
3422 FMDBG("retval of Header write: %d", retval);
3423
3424 } break;
3425
3426 case V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT: {
3427 radio->ps_repeatcount = ctrl->value;
3428 } break;
3429 case V4L2_CID_TUNE_POWER_LEVEL: {
3430 unsigned char tx_power_lvl_config[FM_TX_PWR_LVL_MAX+1] = {
3431 0x85, /* tx_da<5:3> = 0 lpf<2:0> = 5*/
3432 0x95, /* tx_da<5:3> = 2 lpf<2:0> = 5*/
3433 0x9D, /* tx_da<5:3> = 3 lpf<2:0> = 5*/
3434 0xA5, /* tx_da<5:3> = 4 lpf<2:0> = 5*/
3435 0xAD, /* tx_da<5:3> = 5 lpf<2:0> = 5*/
3436 0xB5, /* tx_da<5:3> = 6 lpf<2:0> = 5*/
3437 0xBD, /* tx_da<5:3> = 7 lpf<2:0> = 5*/
3438 0xBF /* tx_da<5:3> = 7 lpf<2:0> = 7*/
3439 };
3440 if (ctrl->value > FM_TX_PWR_LVL_MAX)
3441 ctrl->value = FM_TX_PWR_LVL_MAX;
3442 if (ctrl->value < FM_TX_PWR_LVL_0)
3443 ctrl->value = FM_TX_PWR_LVL_0;
3444 retval = sync_read_xfr(radio, PHY_TXGAIN, xfr_buf);
3445 FMDBG("return for PHY_TXGAIN is %d", retval);
3446 if (retval < 0) {
3447 FMDBG("read failed");
3448 break;
3449 }
3450 xfr_buf[2] = tx_power_lvl_config[ctrl->value];
3451 retval = sync_write_xfr(radio, PHY_TXGAIN, xfr_buf);
3452 FMDBG("return for write PHY_TXGAIN is %d", retval);
3453 if (retval < 0)
3454 FMDBG("write failed");
3455 } break;
Venkateshwarlu Domakonda9efd5c92012-05-11 21:18:45 +05303456 case V4L2_CID_PRIVATE_SOFT_MUTE:
3457 radio->registers[IOCTRL] &= ~(IOC_SFT_MUTE);
3458 if (ctrl->value)
3459 radio->registers[IOCTRL] |= IOC_SFT_MUTE;
3460 retval = tavarua_write_register(radio, IOCTRL,
3461 radio->registers[IOCTRL]);
3462 if (retval < 0)
3463 FMDERR("Failed to enable/disable SMute\n");
3464 break;
Anantha Krishnan71d6fa62011-12-13 19:30:51 +05303465 /*These IOCTL's are place holders to keep the
Srinivasa Rao Uppala4e38bfc2011-09-15 16:00:31 +05303466 driver compatible with change in frame works for IRIS */
Anantha Krishnan71d6fa62011-12-13 19:30:51 +05303467 case V4L2_CID_PRIVATE_RIVA_ACCS_ADDR:
3468 case V4L2_CID_PRIVATE_RIVA_ACCS_LEN:
3469 case V4L2_CID_PRIVATE_RIVA_PEEK:
3470 case V4L2_CID_PRIVATE_RIVA_POKE:
3471 case V4L2_CID_PRIVATE_SSBI_ACCS_ADDR:
3472 case V4L2_CID_PRIVATE_SSBI_PEEK:
3473 case V4L2_CID_PRIVATE_SSBI_POKE:
Anantha Krishnan71d6fa62011-12-13 19:30:51 +05303474 case V4L2_CID_PRIVATE_RDS_GRP_COUNTERS:
3475 case V4L2_CID_PRIVATE_SET_NOTCH_FILTER:
3476 case V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION:
Anantha Krishnana3dcce42012-01-05 19:27:57 +05303477 case V4L2_CID_PRIVATE_SINR_THRESHOLD:
3478 case V4L2_CID_PRIVATE_SINR_SAMPLES:
Anantha Krishnan93eb1762012-06-04 13:41:07 +05303479 case V4L2_CID_PRIVATE_SPUR_SELECTION:
Srinivasa Rao Uppala4e38bfc2011-09-15 16:00:31 +05303480 retval = 0;
3481 break;
Anantha Krishnan93eb1762012-06-04 13:41:07 +05303482 case V4L2_CID_PRIVATE_SPUR_FREQ:
3483 radio->spur_data.freq[radio->spur_table_size] =
3484 ctrl->value;
3485 break;
3486 case V4L2_CID_PRIVATE_SPUR_FREQ_RMSSI:
3487 radio->spur_data.rmssi[radio->spur_table_size++] =
3488 ctrl->value;
3489 break;
3490 case V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE:
3491 retval = update_spur_table(radio);
3492 break;
Ayaz Ahmada0d56b52012-06-26 15:58:41 +05303493 case V4L2_CID_PRIVATE_TX_TONE:
3494 retval = 0;
3495 memset(xfr_buf, 0, sizeof(xfr_buf));
3496 switch (ctrl->value) {
3497 case ONE_KHZ_LR_EQUA_0DBFS:
3498 xfr_buf[TONE_CHANNEL_EN_AND_SCALING_BYTE]
3499 = TONE_LEFT_RIGHT_CH_ENABLED;
3500 xfr_buf[TONE_LEFT_FREQ_BYTE] = 0x01;
3501 xfr_buf[TONE_RIGHT_FREQ_BYTE] = 0x01;
3502 break;
3503 case ONE_KHZ_LEFTONLY_EQUA_0DBFS:
3504 xfr_buf[TONE_CHANNEL_EN_AND_SCALING_BYTE]
3505 = TONE_LEFT_CH_ENABLED;
3506 xfr_buf[TONE_LEFT_FREQ_BYTE] = 0x01;
3507 break;
3508 case ONE_KHZ_RIGHTONLY_EQUA_0DBFS:
3509 xfr_buf[TONE_CHANNEL_EN_AND_SCALING_BYTE]
3510 = TONE_RIGHT_CH_ENABLED;
3511 xfr_buf[TONE_RIGHT_FREQ_BYTE] = 0x01;
3512 break;
3513 case ONE_KHZ_LR_EQUA_l8DBFS:
3514 xfr_buf[TONE_CHANNEL_EN_AND_SCALING_BYTE]
3515 = (LSH_DATA(TONE_SCALE_IND_12,
3516 TONE_SCALING_SHIFT)
3517 | TONE_LEFT_RIGHT_CH_ENABLED);
3518 xfr_buf[TONE_LEFT_FREQ_BYTE] = 0x01;
3519 xfr_buf[TONE_RIGHT_FREQ_BYTE] = 0x01;
3520 break;
3521 case FIFTEEN_KHZ_LR_EQUA_l8DBFS:
3522 xfr_buf[TONE_CHANNEL_EN_AND_SCALING_BYTE]
3523 = (LSH_DATA(TONE_SCALE_IND_12,
3524 TONE_SCALING_SHIFT)
3525 | TONE_LEFT_RIGHT_CH_ENABLED);
3526 xfr_buf[TONE_LEFT_FREQ_BYTE] = 0x0F;
3527 xfr_buf[TONE_RIGHT_FREQ_BYTE] = 0x0F;
3528 break;
3529 default:
3530 retval = -1;
3531 FMDERR("tone generator value not valid\n");
3532 break;
3533 }
3534 if (retval >= 0) {
3535 xfr_buf[TONE_GEN_CTRL_BYTE] = 0x01;
3536 retval = sync_write_xfr(radio, XFR_EXT, xfr_buf);
3537 }
3538 if (retval < 0)
3539 FMDERR("Tone generator failed\n");
3540 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003541 default:
3542 retval = -EINVAL;
3543 }
3544 if (retval < 0)
3545 printk(KERN_WARNING DRIVER_NAME
3546 ": set control failed with %d, id : %d\n", retval, ctrl->id);
3547
3548 return retval;
3549}
3550
3551/*=============================================================================
3552FUNCTION: tavarua_vidioc_g_tuner
3553=============================================================================*/
3554/**
3555 This function is called to get tuner attributes.
3556
3557 NOTE:
3558 To query the attributes of a tuner, applications initialize the index field
3559 and zero out the reserved array of a struct v4l2_tuner and call the
3560 VIDIOC_G_TUNER ioctl with a pointer to this structure. Drivers fill the rest
3561 of the structure or return an EINVAL error code when the index is out of
3562 bounds. To enumerate all tuners applications shall begin at index zero,
3563 incrementing by one until the driver returns EINVAL.
3564
3565 @param file: File descriptor returned by open().
3566 @param tuner: pointer to struct v4l2_tuner.
3567
3568 @return On success 0 is returned, else error code.
3569 @return EINVAL: The struct v4l2_tuner index is out of bounds.
3570*/
3571static int tavarua_vidioc_g_tuner(struct file *file, void *priv,
3572 struct v4l2_tuner *tuner)
3573{
3574 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3575 int retval;
3576 unsigned char xfr_buf[XFR_REG_NUM];
3577 char rmssi = 0;
3578 unsigned char size = 0;
3579
3580 if (tuner->index > 0)
3581 return -EINVAL;
3582
3583 /* read status rssi */
3584 retval = tavarua_read_registers(radio, IOCTRL, 1);
3585 if (retval < 0)
3586 return retval;
3587 /* read RMSSI */
3588 size = 0x1;
3589 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
3590 xfr_buf[1] = RMSSI_PEEK_MSB;
3591 xfr_buf[2] = RMSSI_PEEK_LSB;
3592 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
3593 msleep(TAVARUA_DELAY*10);
3594 retval = tavarua_read_registers(radio, XFRDAT0, 3);
3595 rmssi = radio->registers[XFRDAT0];
3596 tuner->signal = rmssi;
3597
3598 strcpy(tuner->name, "FM");
3599 tuner->type = V4L2_TUNER_RADIO;
3600 tuner->rangelow = radio->region_params.band_low;
3601 tuner->rangehigh = radio->region_params.band_high;
3602 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
3603 tuner->capability = V4L2_TUNER_CAP_LOW;
3604
3605 /* Stereo indicator == Stereo (instead of Mono) */
3606 if (radio->registers[IOCTRL] & IOC_MON_STR)
3607 tuner->audmode = V4L2_TUNER_MODE_STEREO;
3608 else
3609 tuner->audmode = V4L2_TUNER_MODE_MONO;
3610
3611 /* automatic frequency control: -1: freq to low, 1 freq to high */
3612 tuner->afc = 0;
3613
3614 return 0;
3615}
3616
3617/*=============================================================================
3618FUNCTION: tavarua_vidioc_s_tuner
3619=============================================================================*/
3620/**
3621 This function is called to set tuner attributes. Used to set mono/stereo mode.
3622
3623 NOTE:
3624 Tuners have two writable properties, the audio mode and the radio frequency.
3625 To change the audio mode, applications initialize the index, audmode and
3626 reserved fields and call the VIDIOC_S_TUNER ioctl. This will not change the
3627 current tuner, which is determined by the current video input. Drivers may
3628 choose a different audio mode if the requested mode is invalid or unsupported.
3629 Since this is a write-only ioctl, it does not return the actually selected
3630 audio mode.
3631
3632 To change the radio frequency the VIDIOC_S_FREQUENCY ioctl is available.
3633
3634 @param file: File descriptor returned by open().
3635 @param tuner: pointer to struct v4l2_tuner.
3636
3637 @return On success 0 is returned, else error code.
3638 @return -EINVAL: The struct v4l2_tuner index is out of bounds.
3639*/
3640static int tavarua_vidioc_s_tuner(struct file *file, void *priv,
3641 struct v4l2_tuner *tuner)
3642{
3643 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3644 int retval;
3645 int audmode;
3646 if (tuner->index > 0)
3647 return -EINVAL;
3648
3649 FMDBG("%s: set low to %d\n", __func__, tuner->rangelow);
3650 radio->region_params.band_low = tuner->rangelow;
3651 radio->region_params.band_high = tuner->rangehigh;
3652 if (tuner->audmode == V4L2_TUNER_MODE_MONO)
3653 /* Mono */
3654 audmode = (radio->registers[IOCTRL] | IOC_MON_STR);
3655 else
3656 /* Stereo */
3657 audmode = (radio->registers[IOCTRL] & ~IOC_MON_STR);
3658 retval = tavarua_write_register(radio, IOCTRL, audmode);
3659 if (retval < 0)
3660 printk(KERN_WARNING DRIVER_NAME
3661 ": set tuner failed with %d\n", retval);
3662
3663 return retval;
3664}
3665
3666/*=============================================================================
3667FUNCTION: tavarua_vidioc_g_frequency
3668=============================================================================*/
3669/**
3670 This function is called to get tuner or modulator radio frequency.
3671
3672 NOTE:
3673 To get the current tuner or modulator radio frequency applications set the
3674 tuner field of a struct v4l2_frequency to the respective tuner or modulator
3675 number (only input devices have tuners, only output devices have modulators),
3676 zero out the reserved array and call the VIDIOC_G_FREQUENCY ioctl with a
3677 pointer to this structure. The driver stores the current frequency in the
3678 frequency field.
3679
3680 @param file: File descriptor returned by open().
3681 @param freq: pointer to struct v4l2_frequency. This will be set to the
3682 resultant
3683 frequency in 62.5 khz on success.
3684
3685 @return On success 0 is returned, else error code.
3686 @return EINVAL: The tuner index is out of bounds or the value in the type
3687 field is wrong.
3688*/
3689static int tavarua_vidioc_g_frequency(struct file *file, void *priv,
3690 struct v4l2_frequency *freq)
3691{
3692 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3693 freq->type = V4L2_TUNER_RADIO;
3694 return tavarua_get_freq(radio, freq);
3695
3696}
3697
3698/*=============================================================================
3699FUNCTION: tavarua_vidioc_s_frequency
3700=============================================================================*/
3701/**
3702 This function is called to set tuner or modulator radio frequency.
3703
3704 NOTE:
3705 To change the current tuner or modulator radio frequency applications
3706 initialize the tuner, type and frequency fields, and the reserved array of
3707 a struct v4l2_frequency and call the VIDIOC_S_FREQUENCY ioctl with a pointer
3708 to this structure. When the requested frequency is not possible the driver
3709 assumes the closest possible value. However VIDIOC_S_FREQUENCY is a
3710 write-only ioctl, it does not return the actual new frequency.
3711
3712 @param file: File descriptor returned by open().
3713 @param freq: pointer to struct v4l2_frequency.
3714
3715 @return On success 0 is returned, else error code.
3716 @return EINVAL: The tuner index is out of bounds or the value in the type
3717 field is wrong.
3718*/
3719static int tavarua_vidioc_s_frequency(struct file *file, void *priv,
3720 struct v4l2_frequency *freq)
3721{
3722 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3723 int retval = -1;
3724 struct v4l2_frequency getFreq;
3725
3726 FMDBG("%s\n", __func__);
3727
3728 if (freq->type != V4L2_TUNER_RADIO)
3729 return -EINVAL;
3730
3731 FMDBG("Calling tavarua_set_freq\n");
3732
3733 INIT_COMPLETION(radio->sync_req_done);
3734 retval = tavarua_set_freq(radio, freq->frequency);
3735 if (retval < 0) {
3736 printk(KERN_WARNING DRIVER_NAME
3737 ": set frequency failed with %d\n", retval);
3738 } else {
3739 /* Wait for interrupt i.e. complete
3740 (&radio->sync_req_done); call */
3741 if (!wait_for_completion_timeout(&radio->sync_req_done,
3742 msecs_to_jiffies(wait_timeout))) {
3743 FMDERR("Timeout: No Tune response");
3744 retval = tavarua_get_freq(radio, &getFreq);
3745 radio->tune_req = 0;
3746 if (retval > 0) {
3747 if (getFreq.frequency == freq->frequency) {
3748 /** This is success, queut the event*/
3749 tavarua_q_event(radio,
3750 TAVARUA_EVT_TUNE_SUCC);
3751 return 0;
3752 } else {
3753 return -EIO;
3754 }
3755 }
3756 }
3757 }
3758 radio->tune_req = 0;
3759 return retval;
3760}
3761
3762/*=============================================================================
3763FUNCTION: tavarua_vidioc_dqbuf
3764=============================================================================*/
3765/**
3766 This function is called to exchange a buffer with the driver.
3767 This is main buffer function, in essense its equivalent to a blocking
3768 read call.
3769
3770 Applications call the VIDIOC_DQBUF ioctl to dequeue a filled (capturing) or
3771 displayed (output) buffer from the driver's outgoing queue. They just set
3772 the type and memory fields of a struct v4l2_buffer as above, when VIDIOC_DQBUF
3773 is called with a pointer to this structure the driver fills the remaining
3774 fields or returns an error code.
3775
3776 NOTE:
3777 By default VIDIOC_DQBUF blocks when no buffer is in the outgoing queue.
3778 When the O_NONBLOCK flag was given to the open() function, VIDIOC_DQBUF
3779 returns immediately with an EAGAIN error code when no buffer is available.
3780
3781 @param file: File descriptor returned by open().
3782 @param buffer: pointer to struct v4l2_buffer.
3783
3784 @return On success 0 is returned, else error code.
3785 @return EAGAIN: Non-blocking I/O has been selected using O_NONBLOCK and no
3786 buffer was in the outgoing queue.
3787 @return EINVAL: The buffer type is not supported, or the index is out of
3788 bounds, or no buffers have been allocated yet, or the userptr or length are
3789 invalid.
3790 @return ENOMEM: Not enough physical or virtual memory was available to enqueue
3791 a user pointer buffer.
3792 @return EIO: VIDIOC_DQBUF failed due to an internal error. Can also indicate
3793 temporary problems like signal loss. Note the driver might dequeue an (empty)
3794 buffer despite returning an error, or even stop capturing.
3795*/
3796static int tavarua_vidioc_dqbuf(struct file *file, void *priv,
3797 struct v4l2_buffer *buffer)
3798{
3799
3800 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
Venkateshwarlu Domakonda00c882d2012-04-12 10:50:53 +05303801 enum tavarua_buf_t buf_type = -1;
3802 unsigned char buf_fifo[STD_BUF_SIZE] = {0};
3803 struct kfifo *data_fifo = NULL;
3804 unsigned char *buf = NULL;
3805 unsigned int len = 0, retval = -1;
3806
3807 if ((radio == NULL) || (buffer == NULL)) {
3808 FMDERR("radio/buffer is NULL\n");
3809 return -ENXIO;
3810 }
3811 buf_type = buffer->index;
3812 buf = (unsigned char *)buffer->m.userptr;
3813 len = buffer->length;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003814 FMDBG("%s: requesting buffer %d\n", __func__, buf_type);
Venkateshwarlu Domakonda00c882d2012-04-12 10:50:53 +05303815
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003816 if ((buf_type < TAVARUA_BUF_MAX) && (buf_type >= 0)) {
3817 data_fifo = &radio->data_buf[buf_type];
3818 if (buf_type == TAVARUA_BUF_EVENTS) {
3819 if (wait_event_interruptible(radio->event_queue,
3820 kfifo_len(data_fifo)) < 0) {
3821 return -EINTR;
3822 }
3823 }
3824 } else {
3825 FMDERR("invalid buffer type\n");
3826 return -EINVAL;
3827 }
Venkateshwarlu Domakonda00c882d2012-04-12 10:50:53 +05303828 if (len <= STD_BUF_SIZE) {
3829 buffer->bytesused = kfifo_out_locked(data_fifo, &buf_fifo[0],
3830 len, &radio->buf_lock[buf_type]);
3831 } else {
3832 FMDERR("kfifo_out_locked can not use len more than 128\n");
3833 return -EINVAL;
3834 }
3835 retval = copy_to_user(buf, &buf_fifo[0], buffer->bytesused);
3836 if (retval > 0) {
3837 FMDERR("Failed to copy %d bytes of data\n", retval);
3838 return -EAGAIN;
3839 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003840
Venkateshwarlu Domakonda00c882d2012-04-12 10:50:53 +05303841 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003842}
3843
3844/*=============================================================================
3845FUNCTION: tavarua_vidioc_g_fmt_type_private
3846=============================================================================*/
3847/**
3848 This function is here to make the v4l2 framework happy.
3849 We cannot use private buffers without it.
3850
3851 @param file: File descriptor returned by open().
3852 @param f: pointer to struct v4l2_format.
3853
3854 @return On success 0 is returned, else error code.
3855 @return EINVAL: The tuner index is out of bounds or the value in the type
3856 field is wrong.
3857*/
3858static int tavarua_vidioc_g_fmt_type_private(struct file *file, void *priv,
3859 struct v4l2_format *f)
3860{
3861 return 0;
3862
3863}
3864
3865/*=============================================================================
3866FUNCTION: tavarua_vidioc_s_hw_freq_seek
3867=============================================================================*/
3868/**
3869 This function is called to perform a hardware frequency seek.
3870
3871 Start a hardware frequency seek from the current frequency. To do this
3872 applications initialize the tuner, type, seek_upward and wrap_around fields,
3873 and zero out the reserved array of a struct v4l2_hw_freq_seek and call the
3874 VIDIOC_S_HW_FREQ_SEEK ioctl with a pointer to this structure.
3875
3876 This ioctl is supported if the V4L2_CAP_HW_FREQ_SEEK capability is set.
3877
3878 @param file: File descriptor returned by open().
3879 @param seek: pointer to struct v4l2_hw_freq_seek.
3880
3881 @return On success 0 is returned, else error code.
3882 @return EINVAL: The tuner index is out of bounds or the value in the type
3883 field is wrong.
3884 @return EAGAIN: The ioctl timed-out. Try again.
3885*/
3886static int tavarua_vidioc_s_hw_freq_seek(struct file *file, void *priv,
3887 struct v4l2_hw_freq_seek *seek)
3888{
3889 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
Anantha Krishnan6be56602012-04-30 04:08:01 -07003890 int dir;
3891 if (seek->seek_upward)
3892 dir = SRCH_DIR_UP;
3893 else
3894 dir = SRCH_DIR_DOWN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003895 FMDBG("starting search\n");
Anantha Krishnan6be56602012-04-30 04:08:01 -07003896 return tavarua_search(radio, CTRL_ON, dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003897}
3898
3899/*
3900 * tavarua_viddev_tamples - video device interface
3901 */
3902static const struct v4l2_ioctl_ops tavarua_ioctl_ops = {
3903 .vidioc_querycap = tavarua_vidioc_querycap,
3904 .vidioc_queryctrl = tavarua_vidioc_queryctrl,
3905 .vidioc_g_ctrl = tavarua_vidioc_g_ctrl,
3906 .vidioc_s_ctrl = tavarua_vidioc_s_ctrl,
3907 .vidioc_g_tuner = tavarua_vidioc_g_tuner,
3908 .vidioc_s_tuner = tavarua_vidioc_s_tuner,
3909 .vidioc_g_frequency = tavarua_vidioc_g_frequency,
3910 .vidioc_s_frequency = tavarua_vidioc_s_frequency,
3911 .vidioc_s_hw_freq_seek = tavarua_vidioc_s_hw_freq_seek,
3912 .vidioc_dqbuf = tavarua_vidioc_dqbuf,
3913 .vidioc_g_fmt_type_private = tavarua_vidioc_g_fmt_type_private,
3914 .vidioc_s_ext_ctrls = tavarua_vidioc_s_ext_ctrls,
3915};
3916
3917static struct video_device tavarua_viddev_template = {
3918 .fops = &tavarua_fops,
3919 .ioctl_ops = &tavarua_ioctl_ops,
3920 .name = DRIVER_NAME,
3921 .release = video_device_release,
3922};
3923
3924/*==============================================================
3925FUNCTION: FmQSocCom_EnableInterrupts
3926==============================================================*/
3927/**
3928 This function enable interrupts.
3929
3930 @param radio: structure pointer passed by client.
3931 @param state: FM radio state (receiver/transmitter/off/reset).
3932
3933 @return => 0 if successful.
3934 @return < 0 if failure.
3935*/
3936static int tavarua_setup_interrupts(struct tavarua_device *radio,
3937 enum radio_state_t state)
3938{
3939 int retval;
3940 unsigned char int_ctrl[XFR_REG_NUM];
3941
3942 if (!radio->lp_mode)
3943 return 0;
3944
3945 int_ctrl[STATUS_REG1] = READY | TUNE | SEARCH | SCANNEXT |
3946 SIGNAL | INTF | SYNC | AUDIO;
3947 if (state == FM_RECV)
3948 int_ctrl[STATUS_REG2] = RDSDAT | RDSRT | RDSPS | RDSAF;
3949 else
3950 int_ctrl[STATUS_REG2] = TXRDSDAT | TXRDSDONE;
3951
3952 int_ctrl[STATUS_REG3] = TRANSFER | ERROR;
3953
3954 /* use xfr for interrupt setup */
3955 if (radio->chipID == MARIMBA_2_1 || radio->chipID == BAHAMA_1_0
3956 || radio->chipID == BAHAMA_2_0) {
3957 FMDBG("Setting interrupts\n");
3958 retval = sync_write_xfr(radio, INT_CTRL, int_ctrl);
3959 /* use register write to setup interrupts */
3960 } else {
3961 retval = tavarua_write_register(radio,
3962 STATUS_REG1, int_ctrl[STATUS_REG1]);
3963 if (retval < 0)
3964 return retval;
3965
3966 retval = tavarua_write_register(radio,
3967 STATUS_REG2, int_ctrl[STATUS_REG2]);
3968 if (retval < 0)
3969 return retval;
3970
3971 retval = tavarua_write_register(radio,
3972 STATUS_REG3, int_ctrl[STATUS_REG3]);
3973 if (retval < 0)
3974 return retval;
3975 }
3976
3977 radio->lp_mode = 0;
3978 /* tavarua_handle_interrupts force reads all the interrupt status
3979 * registers and it is not valid for MBA 2.1
3980 */
3981 if ((radio->chipID != MARIMBA_2_1) && (radio->chipID != BAHAMA_1_0)
3982 && (radio->chipID != BAHAMA_2_0))
3983 tavarua_handle_interrupts(radio);
3984
3985 return retval;
3986
3987}
3988
3989/*==============================================================
3990FUNCTION: tavarua_disable_interrupts
3991==============================================================*/
3992/**
3993 This function disables interrupts.
3994
3995 @param radio: structure pointer passed by client.
3996
3997 @return => 0 if successful.
3998 @return < 0 if failure.
3999*/
4000static int tavarua_disable_interrupts(struct tavarua_device *radio)
4001{
4002 unsigned char lpm_buf[XFR_REG_NUM];
4003 int retval;
4004 if (radio->lp_mode)
4005 return 0;
4006 FMDBG("%s\n", __func__);
4007 /* In Low power mode, disable all the interrupts that are not being
4008 waited by the Application */
4009 lpm_buf[STATUS_REG1] = TUNE | SEARCH | SCANNEXT;
4010 lpm_buf[STATUS_REG2] = 0x00;
4011 lpm_buf[STATUS_REG3] = TRANSFER;
4012 /* use xfr for interrupt setup */
4013 wait_timeout = 100;
4014 if (radio->chipID == MARIMBA_2_1 || radio->chipID == BAHAMA_1_0
4015 || radio->chipID == BAHAMA_2_0)
4016 retval = sync_write_xfr(radio, INT_CTRL, lpm_buf);
4017 /* use register write to setup interrupts */
4018 else
4019 retval = tavarua_write_registers(radio, STATUS_REG1, lpm_buf,
4020 ARRAY_SIZE(lpm_buf));
4021
4022 /*INT_CTL writes may fail with TIME_OUT as all the
4023 interrupts have been disabled
4024 */
4025 if (retval > -1 || retval == -ETIME) {
4026 radio->lp_mode = 1;
4027 /*Consider timeout as a valid case here*/
4028 retval = 0;
4029 }
4030 wait_timeout = WAIT_TIMEOUT;
4031 return retval;
4032
4033}
4034
4035/*==============================================================
4036FUNCTION: tavarua_start
4037==============================================================*/
4038/**
4039 Starts/enables the device (FM radio).
4040
4041 @param radio: structure pointer passed by client.
4042 @param state: FM radio state (receiver/transmitter/off/reset).
4043
4044 @return On success 0 is returned, else error code.
4045*/
4046static int tavarua_start(struct tavarua_device *radio,
4047 enum radio_state_t state)
4048{
4049
4050 int retval;
4051 FMDBG("%s <%d>\n", __func__, state);
4052 /* set geographic region */
4053 radio->region_params.region = TAVARUA_REGION_US;
4054
4055 /* set radio mode */
4056 retval = tavarua_write_register(radio, RDCTRL, state);
4057 if (retval < 0)
4058 return retval;
4059 /* wait for radio to init */
4060 msleep(RADIO_INIT_TIME);
4061 /* enable interrupts */
4062 tavarua_setup_interrupts(radio, state);
4063 /* default region is US */
4064 radio->region_params.band_low = US_LOW_BAND * FREQ_MUL;
4065 radio->region_params.band_high = US_HIGH_BAND * FREQ_MUL;
4066
4067 return 0;
4068}
4069
4070/*==============================================================
4071FUNCTION: tavarua_suspend
4072==============================================================*/
4073/**
4074 Save state and stop all devices in system.
4075
4076 @param pdev: platform device to be suspended.
4077 @param state: Power state to put each device in.
4078
4079 @return On success 0 is returned, else error code.
4080*/
4081static int tavarua_suspend(struct platform_device *pdev, pm_message_t state)
4082{
4083 struct tavarua_device *radio = platform_get_drvdata(pdev);
4084 int retval;
4085 int users = 0;
4086 printk(KERN_INFO DRIVER_NAME "%s: radio suspend\n\n", __func__);
4087 if (radio) {
Anantha Krishnana2f98082011-10-04 20:02:11 +05304088 users = atomic_read(&radio->users);
Anantha Krishnan71bea3c2011-11-15 07:36:49 +05304089 if (!users) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004090 retval = tavarua_disable_interrupts(radio);
4091 if (retval < 0) {
4092 printk(KERN_INFO DRIVER_NAME
4093 "tavarua_suspend error %d\n", retval);
4094 return -EIO;
4095 }
4096 }
4097 }
4098 return 0;
4099}
4100
4101/*==============================================================
4102FUNCTION: tavarua_resume
4103==============================================================*/
4104/**
4105 Restore state of each device in system.
4106
4107 @param pdev: platform device to be resumed.
4108
4109 @return On success 0 is returned, else error code.
4110*/
4111static int tavarua_resume(struct platform_device *pdev)
4112{
4113
4114 struct tavarua_device *radio = platform_get_drvdata(pdev);
4115 int retval;
4116 int users = 0;
4117 printk(KERN_INFO DRIVER_NAME "%s: radio resume\n\n", __func__);
4118 if (radio) {
Anantha Krishnana2f98082011-10-04 20:02:11 +05304119 users = atomic_read(&radio->users);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004120
Anantha Krishnan71bea3c2011-11-15 07:36:49 +05304121 if (!users) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004122 retval = tavarua_setup_interrupts(radio,
4123 (radio->registers[RDCTRL] & 0x03));
4124 if (retval < 0) {
4125 printk(KERN_INFO DRIVER_NAME "Error in \
4126 tavarua_resume %d\n", retval);
4127 return -EIO;
4128 }
4129 }
4130 }
4131 return 0;
4132}
4133
4134/*==============================================================
4135FUNCTION: tavarua_set_audio_path
4136==============================================================*/
4137/**
4138 This function will configure the audio path to and from the
4139 FM core.
4140
4141 This interface is expected to be called from the multimedia
4142 driver's thread. This interface should only be called when
4143 the FM hardware is enabled. If the FM hardware is not
4144 currently enabled, this interface will return an error.
4145
4146 @param digital_on: Digital audio from the FM core should be enabled/disbled.
4147 @param analog_on: Analog audio from the FM core should be enabled/disbled.
4148
4149 @return On success 0 is returned, else error code.
4150*/
4151int tavarua_set_audio_path(int digital_on, int analog_on)
4152{
4153 struct tavarua_device *radio = private_data;
4154 int rx_on = radio->registers[RDCTRL] & FM_RECV;
Venkateshwarlu Domakondab49c2cb2012-04-17 17:44:50 +05304155 int retval = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004156 if (!radio)
4157 return -ENOMEM;
4158 /* RX */
4159 FMDBG("%s: digital: %d analog: %d\n", __func__, digital_on, analog_on);
Venkateshwarlu Domakondab49c2cb2012-04-17 17:44:50 +05304160 if ((radio->pdata != NULL) && (radio->pdata->config_i2s_gpio != NULL)) {
4161 if (digital_on) {
4162 retval = radio->pdata->config_i2s_gpio(FM_I2S_ON);
4163 if (retval) {
4164 pr_err("%s: config_i2s_gpio failed\n",
4165 __func__);
4166 }
4167 } else {
4168 retval = radio->pdata->config_i2s_gpio(FM_I2S_OFF);
4169 if (retval) {
4170 pr_err("%s: config_i2s_gpio failed\n",
4171 __func__);
4172 }
4173 }
4174 }
4175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004176 SET_REG_FIELD(radio->registers[AUDIOCTRL],
4177 ((rx_on && analog_on) ? 1 : 0),
4178 AUDIORX_ANALOG_OFFSET,
4179 AUDIORX_ANALOG_MASK);
4180 SET_REG_FIELD(radio->registers[AUDIOCTRL],
4181 ((rx_on && digital_on) ? 1 : 0),
4182 AUDIORX_DIGITAL_OFFSET,
4183 AUDIORX_DIGITAL_MASK);
4184 SET_REG_FIELD(radio->registers[AUDIOCTRL],
4185 (rx_on ? 0 : 1),
4186 AUDIOTX_OFFSET,
4187 AUDIOTX_MASK);
4188 /*
4189
4190 I2S Master/Slave configuration:
4191 Setting the FM SoC as I2S Master/Slave
4192 'false' - FM SoC is I2S Slave
4193 'true' - FM SoC is I2S Master
4194
4195 We get this infomation from the respective target's board file :
4196 MSM7x30 - FM SoC is I2S Slave
4197 MSM8x60 - FM SoC is I2S Slave
4198 MSM7x27A - FM SoC is I2S Master
4199 */
4200
4201 if (!radio->pdata->is_fm_soc_i2s_master) {
4202 FMDBG("FM SoC is I2S Slave\n");
4203 SET_REG_FIELD(radio->registers[AUDIOCTRL],
4204 (0),
4205 I2SCTRL_OFFSET,
4206 I2SCTRL_MASK);
4207 } else {
4208 FMDBG("FM SoC is I2S Master\n");
4209 SET_REG_FIELD(radio->registers[AUDIOCTRL],
4210 (1),
4211 I2SCTRL_OFFSET,
4212 I2SCTRL_MASK);
4213 }
4214 FMDBG("%s: %x\n", __func__, radio->registers[AUDIOCTRL]);
4215 return tavarua_write_register(radio, AUDIOCTRL,
4216 radio->registers[AUDIOCTRL]);
4217
4218}
4219
4220/*==============================================================
4221FUNCTION: tavarua_probe
4222==============================================================*/
4223/**
4224 Once called this functions initiates, allocates resources and registers video
4225 tuner device with the v4l2 framework.
4226
4227 NOTE:
4228 probe() should verify that the specified device hardware
4229 actually exists; sometimes platform setup code can't be sure. The probing
4230 can use device resources, including clocks, and device platform_data.
4231
4232 @param pdev: platform device to be probed.
4233
4234 @return On success 0 is returned, else error code.
4235 -ENOMEM in low memory cases
4236*/
4237static int __init tavarua_probe(struct platform_device *pdev)
4238{
4239
4240 struct marimba_fm_platform_data *tavarua_pdata;
4241 struct tavarua_device *radio;
4242 int retval;
4243 int i;
4244 FMDBG("%s: probe called\n", __func__);
4245 /* private data allocation */
4246 radio = kzalloc(sizeof(struct tavarua_device), GFP_KERNEL);
4247 if (!radio) {
4248 retval = -ENOMEM;
4249 goto err_initial;
4250 }
4251
4252 radio->marimba = platform_get_drvdata(pdev);
4253 tavarua_pdata = pdev->dev.platform_data;
4254 radio->pdata = tavarua_pdata;
4255 radio->dev = &pdev->dev;
4256 platform_set_drvdata(pdev, radio);
4257
4258 /* video device allocation */
4259 radio->videodev = video_device_alloc();
4260 if (!radio->videodev)
4261 goto err_radio;
4262
4263 /* initial configuration */
4264 memcpy(radio->videodev, &tavarua_viddev_template,
4265 sizeof(tavarua_viddev_template));
4266
4267 /*allocate internal buffers for decoded rds and event buffer*/
4268 for (i = 0; i < TAVARUA_BUF_MAX; i++) {
4269 int kfifo_alloc_rc=0;
4270 spin_lock_init(&radio->buf_lock[i]);
4271
4272 if (i == TAVARUA_BUF_RAW_RDS)
4273 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
4274 rds_buf*3, GFP_KERNEL);
Srinivasa Rao Uppalad09f24a2012-01-13 19:10:39 +05304275 else if (i == TAVARUA_BUF_RT_RDS)
4276 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
4277 STD_BUF_SIZE * 2, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004278 else
4279 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
4280 STD_BUF_SIZE, GFP_KERNEL);
4281
4282 if (kfifo_alloc_rc!=0) {
4283 printk(KERN_ERR "%s: failed allocating buffers %d\n",
4284 __func__, kfifo_alloc_rc);
4285 goto err_bufs;
4286 }
4287 }
Anantha Krishnana2f98082011-10-04 20:02:11 +05304288 /* initializing the device count */
4289 atomic_set(&radio->users, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004290 radio->xfr_in_progress = 0;
4291 radio->xfr_bytes_left = 0;
4292 for (i = 0; i < TAVARUA_XFR_MAX; i++)
4293 radio->pending_xfrs[i] = 0;
4294
4295 /* init transmit data */
4296 radio->tx_mode = TAVARUA_TX_RT;
4297 /* Init RT and PS Tx datas*/
4298 radio->pty = 0;
4299 radio->pi = 0;
4300 radio->ps_repeatcount = 0;
4301 /* init search params */
4302 radio->srch_params.srch_pty = 0;
4303 radio->srch_params.srch_pi = 0;
4304 radio->srch_params.preset_num = 0;
4305 radio->srch_params.get_list = 0;
4306 /* radio initializes to low power mode */
4307 radio->lp_mode = 1;
4308 radio->handle_irq = 1;
4309 /* init lock */
4310 mutex_init(&radio->lock);
4311 /* init completion flags */
4312 init_completion(&radio->sync_xfr_start);
4313 init_completion(&radio->sync_req_done);
4314 radio->tune_req = 0;
4315 /* initialize wait queue for event read */
4316 init_waitqueue_head(&radio->event_queue);
4317 /* initialize wait queue for raw rds read */
4318 init_waitqueue_head(&radio->read_queue);
4319
4320 video_set_drvdata(radio->videodev, radio);
4321 /*Start the worker thread for event handling and register read_int_stat
4322 as worker function*/
Taniya Das9ac855f2012-02-09 18:05:21 +05304323 radio->wqueue = create_singlethread_workqueue("kfmradio");
4324 if (!radio->wqueue)
4325 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004326
4327 /* register video device */
4328 if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
4329 printk(KERN_WARNING DRIVER_NAME
4330 ": Could not register video device\n");
4331 goto err_all;
4332 }
4333 private_data = radio;
4334 return 0;
4335
4336err_all:
4337 video_device_release(radio->videodev);
4338err_bufs:
4339 for (; i > -1; i--)
4340 kfifo_free(&radio->data_buf[i]);
4341err_radio:
4342 kfree(radio);
4343err_initial:
4344 return retval;
4345}
4346
4347/*==============================================================
4348FUNCTION: tavarua_remove
4349==============================================================*/
4350/**
4351 Removes the device.
4352
4353 @param pdev: platform device to be removed.
4354
4355 @return On success 0 is returned, else error code.
4356*/
4357static int __devexit tavarua_remove(struct platform_device *pdev)
4358{
4359 int i;
4360 struct tavarua_device *radio = platform_get_drvdata(pdev);
4361
4362 /* disable irq */
4363 tavarua_disable_irq(radio);
4364
Taniya Das9ac855f2012-02-09 18:05:21 +05304365 destroy_workqueue(radio->wqueue);
4366
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004367 video_unregister_device(radio->videodev);
4368
4369 /* free internal buffers */
4370 for (i = 0; i < TAVARUA_BUF_MAX; i++)
4371 kfifo_free(&radio->data_buf[i]);
4372
4373 /* free state struct */
4374 kfree(radio);
4375
4376 platform_set_drvdata(pdev, NULL);
4377
4378 return 0;
4379}
4380
4381/*
4382 Platform drivers follow the standard driver model convention, where
4383 discovery/enumeration is handled outside the drivers, and drivers
4384 provide probe() and remove() methods. They support power management
4385 and shutdown notifications using the standard conventions.
4386*/
4387static struct platform_driver tavarua_driver = {
4388 .driver = {
4389 .owner = THIS_MODULE,
4390 .name = "marimba_fm",
4391 },
4392 .remove = __devexit_p(tavarua_remove),
4393 .suspend = tavarua_suspend,
4394 .resume = tavarua_resume,
4395}; /* platform device we're adding */
4396
4397
4398/*************************************************************************
4399 * Module Interface
4400 ************************************************************************/
4401
4402/*==============================================================
4403FUNCTION: radio_module_init
4404==============================================================*/
4405/**
4406 Module entry - add a platform-level device.
4407
4408 @return Returns zero if the driver registered and bound to a device, else
4409 returns a negative error code when the driver not registered.
4410*/
4411static int __init radio_module_init(void)
4412{
4413 printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n");
4414 return platform_driver_probe(&tavarua_driver, tavarua_probe);
4415}
4416
4417/*==============================================================
4418FUNCTION: radio_module_exit
4419==============================================================*/
4420/**
4421 Module exit - removes a platform-level device.
4422
4423 NOTE:
4424 Note that this function will also release all memory- and port-based
4425 resources owned by the device (dev->resource).
4426
4427 @return none.
4428*/
4429static void __exit radio_module_exit(void)
4430{
4431 platform_driver_unregister(&tavarua_driver);
4432}
4433
4434MODULE_LICENSE("GPL v2");
4435MODULE_AUTHOR(DRIVER_AUTHOR);
4436MODULE_DESCRIPTION(DRIVER_DESC);
4437MODULE_VERSION(DRIVER_VERSION);
4438
4439module_init(radio_module_init);
4440module_exit(radio_module_exit);
4441