blob: 971cf107e3d330a16a641d957ac56e8f6093e0db [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;
999 case (0x80 | RX_CONFIG):
1000 case (0x80 | RADIO_CONFIG):
1001 case (0x80 | RDS_CONFIG):
1002 case (0x80 | INT_CTRL):
1003 complete(&radio->sync_req_done);
1004 break;
1005 case (0x80 | RDS_RT_0):
1006 FMDBG("RT Header Sent\n");
1007 complete(&radio->sync_req_done);
1008 break;
1009 case (0x80 | RDS_RT_1):
1010 case (0x80 | RDS_RT_2):
1011 case (0x80 | RDS_RT_3):
1012 case (0x80 | RDS_RT_4):
1013 FMDBG("xfr interrupt RT data Sent\n");
1014 complete(&radio->sync_req_done);
1015 break;
1016 /*TX Specific transfer */
1017 case (0x80 | RDS_PS_0):
1018 FMDBG("PS Header Sent\n");
1019 complete(&radio->sync_req_done);
1020 break;
1021 case (0x80 | RDS_PS_1):
1022 case (0x80 | RDS_PS_2):
1023 case (0x80 | RDS_PS_3):
1024 case (0x80 | RDS_PS_4):
1025 case (0x80 | RDS_PS_5):
1026 case (0x80 | RDS_PS_6):
1027 FMDBG("xfr interrupt PS data Sent\n");
1028 complete(&radio->sync_req_done);
1029 break;
1030 case (0x80 | PHY_TXGAIN):
1031 FMDBG("write PHY_TXGAIN is successful");
1032 complete(&radio->sync_req_done);
1033 break;
Anantha Krishnan93eb1762012-06-04 13:41:07 +05301034 case (XFR_POKE_COMPLETE | LSH_DATA(ONE_BYTE, 1)):
1035 case (XFR_POKE_COMPLETE | LSH_DATA(TWO_BYTE, 1)):
1036 case (XFR_POKE_COMPLETE | LSH_DATA(THREE_BYTE, 1)):
1037 case (XFR_POKE_COMPLETE | LSH_DATA(FOUR_BYTE, 1)):
1038 case (XFR_POKE_COMPLETE | LSH_DATA(FIVE_BYTE, 1)):
1039 case (XFR_POKE_COMPLETE | LSH_DATA(SIX_BYTE, 1)):
1040 case (XFR_POKE_COMPLETE | LSH_DATA(SEVEN_BYTE, 1)):
1041 case (XFR_POKE_COMPLETE | LSH_DATA(EIGHT_BYTE, 1)):
1042 case (XFR_POKE_COMPLETE | LSH_DATA(NINE_BYTE, 1)):
1043 case (XFR_POKE_COMPLETE | LSH_DATA(TEN_BYTE, 1)):
1044 case (XFR_POKE_COMPLETE | LSH_DATA(ELEVEN_BYTE, 1)):
1045 case (XFR_POKE_COMPLETE | LSH_DATA(TWELVE_BYTE, 1)):
1046 case (XFR_POKE_COMPLETE | LSH_DATA(THIRTEEN_BYTE, 1)):
1047 case (XFR_PEEK_COMPLETE | LSH_DATA(ONE_BYTE, 1)):
1048 case (XFR_PEEK_COMPLETE | LSH_DATA(TWO_BYTE, 1)):
1049 case (XFR_PEEK_COMPLETE | LSH_DATA(THREE_BYTE, 1)):
1050 case (XFR_PEEK_COMPLETE | LSH_DATA(FOUR_BYTE, 1)):
1051 case (XFR_PEEK_COMPLETE | LSH_DATA(FIVE_BYTE, 1)):
1052 case (XFR_PEEK_COMPLETE | LSH_DATA(SIX_BYTE, 1)):
1053 case (XFR_PEEK_COMPLETE | LSH_DATA(SEVEN_BYTE, 1)):
1054 case (XFR_PEEK_COMPLETE | LSH_DATA(EIGHT_BYTE, 1)):
1055 case (XFR_PEEK_COMPLETE | LSH_DATA(NINE_BYTE, 1)):
1056 case (XFR_PEEK_COMPLETE | LSH_DATA(TEN_BYTE, 1)):
1057 case (XFR_PEEK_COMPLETE | LSH_DATA(ELEVEN_BYTE, 1)):
1058 case (XFR_PEEK_COMPLETE | LSH_DATA(TWELVE_BYTE, 1)):
1059 case (XFR_PEEK_COMPLETE | LSH_DATA(THIRTEEN_BYTE, 1)):
1060 FMDBG("XFR interrupt for PEEK/POKE complete\n");
1061 complete(&radio->sync_req_done);
1062 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001063 default:
1064 FMDERR("UNKNOWN XFR = %d\n", xfr_status);
1065 }
1066 if (!radio->xfr_in_progress)
1067 start_pending_xfr(radio);
1068
1069 }
1070
1071 /* Error occurred. Read ERRCODE to determine cause */
1072 if (radio->registers[STATUS_REG3] & ERROR) {
1073#ifdef FM_DEBUG
1074 unsigned char xfr_buf[XFR_REG_NUM];
1075 int retval = sync_read_xfr(radio, ERROR_CODE, xfr_buf);
1076 FMDBG("retval of ERROR_CODE read : %d\n", retval);
1077#endif
1078 FMDERR("ERROR STATE\n");
1079 }
1080
1081 mutex_unlock(&radio->lock);
1082 FMDBG("Work is done\n");
1083
1084}
1085
1086/*=============================================================================
1087FUNCTION: read_int_stat
1088=============================================================================*/
1089/**
1090 This function is scheduled whenever there is an interrupt pending in interrupt
1091 queue. i.e. kfmradio.
1092
1093 Whenever there is a GPIO interrupt, a delayed work will be queued in to the
1094 'kfmradio' work queue. Upon execution of this work in the queue, a a call
1095 to read_int_stat function will be made , which would in turn handle the
1096 interrupts by reading the INTSTATx registers.
1097 NOTE:
1098 Tasks to be run out of a workqueue need to be packaged in a struct
1099 work_struct structure.
1100
1101 @param work: work_struct structure.
1102
1103 @return None.
1104*/
1105static void read_int_stat(struct work_struct *work)
1106{
1107 struct tavarua_device *radio = container_of(work,
1108 struct tavarua_device, work.work);
1109 tavarua_handle_interrupts(radio);
1110}
1111
Taniya Das9ac855f2012-02-09 18:05:21 +05301112static void fm_shutdown(struct work_struct *work)
1113{
1114 struct tavarua_device *radio = container_of(work,
1115 struct tavarua_device, work.work);
Anantha Krishnan1475c932012-02-16 21:54:03 +05301116 FMDERR("%s: Releasing the FM I2S GPIO\n", __func__);
1117 if (radio->pdata->config_i2s_gpio != NULL)
1118 radio->pdata->config_i2s_gpio(FM_I2S_OFF);
1119 FMDERR("%s: Shutting down FM SOC\n", __func__);
Taniya Das9ac855f2012-02-09 18:05:21 +05301120 radio->pdata->fm_shutdown(radio->pdata);
1121 complete(&radio->shutdown_done);
1122}
1123
1124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125/*************************************************************************
1126 * irq helper functions
1127 ************************************************************************/
1128
1129/*=============================================================================
1130FUNCTION: tavarua_request_irq
1131=============================================================================*/
1132/**
1133 This function is called to acquire a FM GPIO and enable FM interrupts.
1134
1135 @param radio: structure pointer passed by client.
1136
1137 @return 0 if success else otherwise.
1138*/
1139static int tavarua_request_irq(struct tavarua_device *radio)
1140{
1141 int retval;
1142 int irq = radio->pdata->irq;
1143 if (radio == NULL)
1144 return -EINVAL;
1145
1146 /* A workqueue created with create_workqueue() will have one worker thread
1147 * for each CPU on the system; create_singlethread_workqueue(), instead,
1148 * creates a workqueue with a single worker process. The name of the queue
1149 * is limited to ten characters; it is only used for generating the "command"
1150 * for the kernel thread(s) (which can be seen in ps or top).
1151 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001152 /* allocate an interrupt line */
1153 /* On success, request_irq() returns 0 if everything goes as
1154 planned. Your interrupt handler will start receiving its
1155 interrupts immediately. On failure, request_irq()
1156 returns:
1157 -EINVAL
1158 The IRQ number you requested was either
1159 invalid or reserved, or your passed a NULL
1160 pointer for the handler() parameter.
1161
1162 -EBUSY The IRQ you requested is already being
1163 handled, and the IRQ cannot be shared.
1164
1165 -ENXIO The m68k returns this value for an invalid
1166 IRQ number.
1167 */
1168 /* Use request_any_context_irq, So that it might work for nested or
1169 nested interrupts. in MSM8x60, FM is connected to PMIC GPIO and it
1170 is a nested interrupt*/
1171 retval = request_any_context_irq(irq, tavarua_isr,
1172 IRQ_TYPE_EDGE_FALLING, "fm interrupt", radio);
1173 if (retval < 0) {
1174 FMDERR("Couldn't acquire FM gpio %d\n", irq);
1175 return retval;
1176 } else {
1177 FMDBG("FM GPIO %d registered\n", irq);
1178 }
1179 retval = enable_irq_wake(irq);
1180 if (retval < 0) {
1181 FMDERR("Could not enable FM interrupt\n ");
1182 free_irq(irq , radio);
1183 }
1184 return retval;
1185}
1186
1187/*=============================================================================
1188FUNCTION: tavarua_disable_irq
1189=============================================================================*/
1190/**
1191 This function is called to disable FM irq and free up FM interrupt handling
1192 resources.
1193
1194 @param radio: structure pointer passed by client.
1195
1196 @return 0 if success else otherwise.
1197*/
1198static int tavarua_disable_irq(struct tavarua_device *radio)
1199{
1200 int irq;
1201 if (!radio)
1202 return -EINVAL;
1203 irq = radio->pdata->irq;
1204 disable_irq_wake(irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205 free_irq(irq, radio);
Anantha Krishnan1475c932012-02-16 21:54:03 +05301206 cancel_delayed_work_sync(&radio->work);
1207 flush_workqueue(radio->wqueue);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208 return 0;
1209}
1210
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301211static int optimized_search_algorithm(struct tavarua_device *radio,
1212 int region)
1213{
1214 unsigned char adie_type_bahma;
1215 int retval = 0;
1216 unsigned int rdsMask = 0;
1217 unsigned char value;
1218
1219 adie_type_bahma = is_bahama();
1220
1221 switch (region) {
1222 case TAVARUA_REGION_US:
1223 /*
1224 Radio band for all the 200KHz channel-spaced regions
1225 coming under EUROPE too, have been set as TAVARUA_REGION_US.
1226 */
1227 FMDBG("%s: The region selected from APP is"
1228 " : TAVARUA_REGION_US", __func__);
1229 break;
1230 case TAVARUA_REGION_EU:
1231 /*
1232 Radio band for all the 50KHz channel-spaced regions
1233 coming under EUROPE, have been set as TAVARUA_REGION_EU.
1234 */
1235 FMDBG("%s: The region selected from APP is : "
1236 "TAVARUA_REGION_EU", __func__);
1237 break;
1238 case TAVARUA_REGION_JAPAN:
1239 /*
1240 Radio band for the 100KHz channel-spaced JAPAN region
1241 has been set as TAVARUA_REGION_JAPAN.
1242 */
1243 FMDBG("%s: The region selected from APP is"
1244 " : TAVARUA_REGION_JAPAN", __func__);
1245 break;
1246 case TAVARUA_REGION_JAPAN_WIDE:
1247 /*
1248 Radio band for the 50KHz channel-spaced JAPAN WIDE region
1249 has been set as TAVARUA_REGION_JAPAN_WIDE.
1250 */
1251 FMDBG("%s: The region selected from APP is"
1252 " : TAVARUA_REGION_JAPAN_WIDE", __func__);
1253 break;
1254 case TAVARUA_REGION_OTHER:
1255 /*
1256 Radio band for all the 100KHz channel-spaced regions
1257 including those coming under EUROPE have been set as
1258 TAVARUA_REGION_OTHER.
1259 */
1260 FMDBG("%s: The region selected from APP is"
1261 " : TAVARUA_REGION_OTHER", __func__);
1262 break;
1263 default:
1264 pr_err("%s: Should not reach here.", __func__);
1265 break;
1266
1267 }
1268
1269 /* Enable or Disable the 200KHz enforcer */
1270 switch (region) {
1271 case TAVARUA_REGION_US:
1272 case TAVARUA_REGION_JAPAN:
1273 case TAVARUA_REGION_OTHER:
1274 /*
1275 These are the 3 bands for which we need to enable the
1276 200KHz enforcer in ADVCTL reg.
1277 */
1278 if (adie_type_bahma) {
1279 FMDBG("Adie type : Bahama\n");
1280 FMDBG("%s: Enabling the 200KHz enforcer for"
1281 " Region : %d", __func__, region);
1282 /*Enable the 200KHz enforcer*/
1283 retval = tavarua_read_registers(radio,
1284 ADVCTRL, 1);
1285 if (retval >= 0) {
1286 rdsMask = radio->registers[ADVCTRL];
1287 SET_REG_FIELD(rdsMask, ENF_SRCH200khz,
1288 SRCH200KHZ_OFFSET, SRCH_MASK);
1289 retval = tavarua_write_register(radio,
1290 ADVCTRL, rdsMask);
1291 } else
1292 return retval;
1293 } /* if Marimba do nothing */
1294 break;
1295 case TAVARUA_REGION_EU:
1296 case TAVARUA_REGION_JAPAN_WIDE:
1297 /*
1298 These are the 2 bands for which we need to disable the
1299 200KHz enforcer in ADVCTL reg.
1300 Radio band for all the 50KHz channel-spaced regions
1301 coming under EUROPE have been set as TAVARUA_REGION_EU.
1302 */
1303 if (adie_type_bahma) {
1304 FMDBG("Adie type : Bahama\n");
1305 FMDBG("%s: Disabling the 200KHz enforcer for"
1306 " Region : %d", __func__, region);
1307 /*
1308 Disable 200KHz enforcer for all 50 KHz
1309 spaced regions.
1310 */
1311 retval = tavarua_read_registers(radio,
1312 ADVCTRL, 1);
1313 if (retval >= 0) {
1314 rdsMask = radio->registers[ADVCTRL];
1315 SET_REG_FIELD(rdsMask, NO_SRCH200khz,
1316 SRCH200KHZ_OFFSET, SRCH_MASK);
1317 retval = tavarua_write_register(radio,
1318 ADVCTRL, rdsMask);
1319 } else
1320 return retval;
1321 } /* if Marimba do nothing */
1322 break;
1323 default:
1324 FMDBG("%s: Defaulting in case of Enabling/Disabling"
1325 "the 200KHz Enforcer", __func__);
1326 break;
1327 }
1328
1329 /* Set channel spacing */
1330 switch (region) {
1331 case TAVARUA_REGION_US:
1332 if (adie_type_bahma) {
1333 FMDBG("Adie type : Bahama\n");
1334 /*
1335 Configuring all 200KHZ spaced regions as 100KHz due to
1336 change in the new Bahma FM SoC search algorithm.
1337 */
1338 value = FM_CH_SPACE_100KHZ;
1339 } else {
1340 FMDBG("Adie type : Marimba\n");
1341 value = FM_CH_SPACE_200KHZ;
1342 }
1343 break;
1344 case TAVARUA_REGION_JAPAN:
1345 case TAVARUA_REGION_OTHER:
1346 if (adie_type_bahma) {
1347 FMDBG("Adie type : Bahama\n");
1348 FMDBG("%s: Configuring the channel-spacing as 50KHz"
1349 "for the Region : %d", __func__, region);
1350 /*
1351 Configuring all 100KHZ spaced regions as 50KHz due to
1352 change in the new Bahma FM SoC search algorithm.
1353 */
1354 value = FM_CH_SPACE_50KHZ;
1355 } else {
1356 FMDBG("Adie type : Marimba\n");
1357 value = FM_CH_SPACE_100KHZ;
1358 }
1359 break;
1360 case TAVARUA_REGION_EU:
1361 case TAVARUA_REGION_JAPAN_WIDE:
1362 value = FM_CH_SPACE_50KHZ;
1363 break;
1364 default:
1365 FMDBG("%s: Defualting in case of Channel-Spacing", __func__);
1366 break;
1367 }
1368
1369 SET_REG_FIELD(radio->registers[RDCTRL], value,
1370 RDCTRL_CHSPACE_OFFSET, RDCTRL_CHSPACE_MASK);
1371
1372 return retval;
1373}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374/*************************************************************************
1375 * fops/IOCTL helper functions
1376 ************************************************************************/
1377
1378/*=============================================================================
1379FUNCTION: tavarua_search
1380=============================================================================*/
1381/**
1382 This interface sets the search control features.
1383
1384 @param radio: structure pointer passed by client.
1385 @param on: The value of a control.
1386 @param dir: FM search direction.
1387
1388 @return => 0 if successful.
1389 @return < 0 if failure.
1390*/
1391static int tavarua_search(struct tavarua_device *radio, int on, int dir)
1392{
1393 enum search_t srch = radio->registers[SRCHCTRL] & SRCH_MODE;
1394
1395 FMDBG("In tavarua_search\n");
1396 if (on) {
1397 radio->registers[SRCHRDS1] = 0x00;
1398 radio->registers[SRCHRDS2] = 0x00;
1399 /* Set freq band */
1400 switch (srch) {
1401 case SCAN_FOR_STRONG:
1402 case SCAN_FOR_WEAK:
1403 radio->srch_params.get_list = 1;
1404 radio->registers[SRCHRDS2] =
1405 radio->srch_params.preset_num;
1406 break;
1407 case RDS_SEEK_PTY:
1408 case RDS_SCAN_PTY:
1409 radio->registers[SRCHRDS2] =
1410 radio->srch_params.srch_pty;
1411 break;
1412 case RDS_SEEK_PI:
1413 radio->registers[SRCHRDS1] =
1414 (radio->srch_params.srch_pi & 0xFF00) >> 8;
1415 radio->registers[SRCHRDS2] =
1416 (radio->srch_params.srch_pi & 0x00FF);
1417 break;
1418 default:
1419 break;
1420 }
1421 radio->registers[SRCHCTRL] |= SRCH_ON;
1422 } else {
1423 radio->registers[SRCHCTRL] &= ~SRCH_ON;
1424 radio->srch_params.get_list = 0;
1425 }
1426 radio->registers[SRCHCTRL] = (dir << 3) |
1427 (radio->registers[SRCHCTRL] & 0xF7);
1428
1429 FMDBG("SRCHCTRL <%x>\n", radio->registers[SRCHCTRL]);
1430 FMDBG("Search Started\n");
1431 return tavarua_write_registers(radio, SRCHRDS1,
1432 &radio->registers[SRCHRDS1], 3);
1433}
1434
1435/*=============================================================================
1436FUNCTION: tavarua_set_region
1437=============================================================================*/
1438/**
1439 This interface configures the FM radio.
1440
1441 @param radio: structure pointer passed by client.
1442 @param req_region: FM band types. These types defines the FM band minimum and
1443 maximum frequencies in the FM band.
1444
1445 @return => 0 if successful.
1446 @return < 0 if failure.
1447*/
1448static int tavarua_set_region(struct tavarua_device *radio,
1449 int req_region)
1450{
1451 int retval = 0;
Anantha Krishnana02ef212011-06-28 00:57:25 +05301452 unsigned int rdsMask = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453 unsigned char xfr_buf[XFR_REG_NUM];
1454 unsigned char value;
1455 unsigned int spacing = 0.100 * FREQ_MUL;
1456 unsigned int band_low, band_high;
1457 unsigned int low_band_limit = 76.0 * FREQ_MUL;
1458 enum tavarua_region_t region = req_region;
Anantha Krishnana02ef212011-06-28 00:57:25 +05301459 unsigned char adie_type_bahma;
1460
1461 adie_type_bahma = is_bahama();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001462
1463 /* Set freq band */
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301464 if (region == TAVARUA_REGION_JAPAN)
1465 SET_REG_FIELD(radio->registers[RDCTRL], 1,
1466 RDCTRL_BAND_OFFSET, RDCTRL_BAND_MASK);
1467 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001468 SET_REG_FIELD(radio->registers[RDCTRL], 0,
1469 RDCTRL_BAND_OFFSET, RDCTRL_BAND_MASK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001470
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001471 /* Set De-emphasis and soft band range*/
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301472 SET_REG_FIELD(radio->registers[RDCTRL], radio->region_params.emphasis,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 RDCTRL_DEEMPHASIS_OFFSET, RDCTRL_DEEMPHASIS_MASK);
1474
1475 /* set RDS standard */
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301476 SET_REG_FIELD(radio->registers[RDSCTRL], radio->region_params.rds_std,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001477 RDSCTRL_STANDARD_OFFSET, RDSCTRL_STANDARD_MASK);
1478
1479 FMDBG("RDSCTRLL %x\n", radio->registers[RDSCTRL]);
1480 retval = tavarua_write_register(radio, RDSCTRL,
1481 radio->registers[RDSCTRL]);
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301482 if (retval < 0) {
1483 FMDERR("Failed to set RDS/RBDS standard\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484 return retval;
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301485 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001486
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301487 /* Set the lower and upper band limits*/
1488 retval = sync_read_xfr(radio, RADIO_CONFIG, xfr_buf);
1489 if (retval < 0) {
1490 FMDERR("failed to get RADIO_CONFIG\n");
1491 return retval;
1492 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001493
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301494 band_low = (radio->region_params.band_low -
1495 low_band_limit) / spacing;
1496 band_high = (radio->region_params.band_high -
1497 low_band_limit) / spacing;
1498
1499 xfr_buf[0] = RSH_DATA(band_low, 8);
1500 xfr_buf[1] = GET_ABS_VAL(band_low);
1501 xfr_buf[2] = RSH_DATA(band_high, 8);
1502 xfr_buf[3] = GET_ABS_VAL(band_high);
Venkateshwarlu Domakondab49c2cb2012-04-17 17:44:50 +05301503 xfr_buf[4] = 0; /* Active LOW */
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301504 retval = sync_write_xfr(radio, RADIO_CONFIG, xfr_buf);
1505 if (retval < 0) {
1506 FMDERR("Could not set regional settings\n");
1507 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001508 }
1509 radio->region_params.region = region;
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301510
1511 /* Check for the FM Algorithm used */
1512 if (radio->enable_optimized_srch_alg) {
1513 FMDBG("Optimized Srch Algorithm!!!");
1514 optimized_search_algorithm(radio, region);
1515 } else {
1516 FMDBG("Native Srch Algorithm!!!");
1517 /* Enable/Disable the 200KHz enforcer */
1518 switch (region) {
1519 case TAVARUA_REGION_US:
1520 if (adie_type_bahma) {
1521 FMDBG("Adie type : Bahama\n");
1522 /*Enable the 200KHz enforcer*/
1523 retval = tavarua_read_registers(radio,
1524 ADVCTRL, 1);
1525 if (retval >= 0) {
1526 rdsMask = radio->registers[ADVCTRL];
1527 SET_REG_FIELD(rdsMask, ENF_SRCH200khz,
1528 SRCH200KHZ_OFFSET, SRCH_MASK);
1529 retval = tavarua_write_register(radio,
1530 ADVCTRL, rdsMask);
1531 } else
1532 return retval;
1533 } /* if Marimba do nothing */
1534 break;
1535 case TAVARUA_REGION_EU:
1536 case TAVARUA_REGION_JAPAN:
1537 case TAVARUA_REGION_JAPAN_WIDE:
1538 default:
1539 if (adie_type_bahma) {
1540 FMDBG("Adie type : Bahama\n");
1541 /*
1542 Disable 200KHz enforcer for all 100/50 KHz
1543 spaced regions.
1544 */
1545 retval = tavarua_read_registers(radio,
1546 ADVCTRL, 1);
1547 if (retval >= 0) {
1548 rdsMask = radio->registers[ADVCTRL];
1549 SET_REG_FIELD(rdsMask, NO_SRCH200khz,
1550 SRCH200KHZ_OFFSET, SRCH_MASK);
1551 retval = tavarua_write_register(radio,
1552 ADVCTRL, rdsMask);
1553 } else
1554 return retval;
1555 } /* if Marimba do nothing */
1556 break;
1557 }
1558
1559 /* Set channel spacing */
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301560 if (region == TAVARUA_REGION_US) {
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301561 if (adie_type_bahma) {
1562 FMDBG("Adie type : Bahama\n");
1563 /*
1564 Configuring all 200KHZ spaced regions as
1565 100KHz due to change in the new Bahma
1566 FM SoC search algorithm.
1567 */
1568 value = FM_CH_SPACE_100KHZ;
1569 } else {
1570 FMDBG("Adie type : Marimba\n");
1571 value = FM_CH_SPACE_200KHZ;
1572 }
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301573 } else {
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301574 /*
1575 Set the channel spacing as configured from
1576 the upper layers.
1577 */
1578 value = radio->region_params.spacing;
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301579 }
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301580 SET_REG_FIELD(radio->registers[RDCTRL], value,
1581 RDCTRL_CHSPACE_OFFSET, RDCTRL_CHSPACE_MASK);
1582
1583 }
1584
1585 /* Write the config values into RDCTL register */
1586 FMDBG("RDCTRL: %x\n", radio->registers[RDCTRL]);
1587 retval = tavarua_write_register(radio, RDCTRL,
1588 radio->registers[RDCTRL]);
1589 if (retval < 0) {
1590 FMDERR("Could not set region in rdctrl\n");
1591 return retval;
1592 }
1593
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001594 return retval;
1595}
1596
1597/*=============================================================================
1598FUNCTION: tavarua_get_freq
1599=============================================================================*/
1600/**
1601 This interface gets the current frequency.
1602
1603 @param radio: structure pointer passed by client.
1604 @param freq: struct v4l2_frequency. This will be set to the resultant
1605 frequency in units of 62.5 kHz on success.
1606
1607 NOTE:
1608 To get the current tuner or modulator radio frequency applications set the
1609 tuner field of a struct v4l2_frequency to the respective tuner or modulator
1610 number (only input devices have tuners, only output devices have modulators),
1611 zero out the reserved array and call the VIDIOC_G_FREQUENCY ioctl with a
1612 pointer to this structure. The driver stores the current frequency in the
1613 frequency field.
1614
1615 Tuning frequency is in units of 62.5 kHz, or if the struct v4l2_tuner or
1616 struct v4l2_modulator capabilities flag V4L2_TUNER_CAP_LOW is set, in
1617 units of 62.5 Hz.
1618
1619 @return => 0 if successful.
1620 @return < 0 if failure.
1621*/
1622static int tavarua_get_freq(struct tavarua_device *radio,
1623 struct v4l2_frequency *freq)
1624{
1625 int retval;
1626 unsigned short chan;
1627 unsigned int band_bottom;
1628 unsigned int spacing;
1629 band_bottom = radio->region_params.band_low;
1630 spacing = 0.100 * FREQ_MUL;
1631 /* read channel */
1632 retval = tavarua_read_registers(radio, FREQ, 2);
1633 chan = radio->registers[FREQ];
1634
1635 /* Frequency (MHz) = 100 (kHz) x Channel + Bottom of Band (MHz) */
1636 freq->frequency = spacing * chan + band_bottom;
1637 if (radio->registers[TUNECTRL] & ADD_OFFSET)
1638 freq->frequency += 800;
1639 return retval;
1640}
1641
1642/*=============================================================================
1643FUNCTION: tavarua_set_freq
1644=============================================================================*/
1645/**
1646 This interface sets the current frequency.
1647
1648 @param radio: structure pointer passed by client.
1649 @param freq: desired frequency sent by the client in 62.5 kHz units.
1650
1651 NOTE:
1652 To change the current tuner or modulator radio frequency, applications
1653 initialize the tuner, type and frequency fields, and the reserved array of a
1654 struct v4l2_frequency and call the VIDIOC_S_FREQUENCY ioctl with a pointer to
1655 this structure. When the requested frequency is not possible the driver
1656 assumes the closest possible value. However VIDIOC_S_FREQUENCY is a
1657 write-only ioctl, it does not return the actual new frequency.
1658
1659 Tuning frequency is in units of 62.5 kHz, or if the struct v4l2_tuner
1660 or struct v4l2_modulator capabilities flag V4L2_TUNER_CAP_LOW is set,
1661 in units of 62.5 Hz.
1662
1663 @return => 0 if successful.
1664 @return < 0 if failure.
1665*/
1666static int tavarua_set_freq(struct tavarua_device *radio, unsigned int freq)
1667{
1668
1669 unsigned int band_bottom;
1670 unsigned char chan;
1671 unsigned char cmd[] = {0x00, 0x00};
1672 unsigned int spacing;
1673 int retval;
1674 band_bottom = radio->region_params.band_low;
1675 spacing = 0.100 * FREQ_MUL;
1676 if ((freq % 1600) == 800) {
1677 cmd[1] = ADD_OFFSET;
1678 freq -= 800;
1679 }
1680 /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / 100 (kHz) */
1681 chan = (freq - band_bottom) / spacing;
1682
1683 cmd[0] = chan;
1684 cmd[1] |= TUNE_STATION;
1685 radio->tune_req = 1;
1686 retval = tavarua_write_registers(radio, FREQ, cmd, 2);
1687 if (retval < 0)
1688 radio->tune_req = 0;
1689 return retval;
1690
1691}
1692
1693/**************************************************************************
1694 * File Operations Interface
1695 *************************************************************************/
1696
1697/*=============================================================================
1698FUNCTION: tavarua_fops_read
1699=============================================================================*/
1700/**
1701 This function is called when a process, which already opened the dev file,
1702 attempts to read from it.
1703
1704 In case of tavarua driver, it is called to read RDS data.
1705
1706 @param file: file descriptor.
1707 @param buf: The buffer to fill with data.
1708 @param count: The length of the buffer in bytes.
1709 @param ppos: Our offset in the file.
1710
1711 @return The number of bytes put into the buffer on sucess.
1712 -EFAULT if there is no access to user buffer
1713*/
1714static ssize_t tavarua_fops_read(struct file *file, char __user *buf,
1715 size_t count, loff_t *ppos)
1716{
1717 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
1718 struct kfifo *rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
1719
1720 /* block if no new data available */
1721 while (!kfifo_len(rds_buf)) {
1722 if (file->f_flags & O_NONBLOCK)
1723 return -EWOULDBLOCK;
1724 if (wait_event_interruptible(radio->read_queue,
1725 kfifo_len(rds_buf)) < 0)
1726 return -EINTR;
1727 }
1728
1729 /* calculate block count from byte count */
1730 count /= BYTES_PER_BLOCK;
1731
1732
1733 /* check if we can write to the user buffer */
1734 if (!access_ok(VERIFY_WRITE, buf, count*BYTES_PER_BLOCK))
1735 return -EFAULT;
1736
1737 /* copy RDS block out of internal buffer and to user buffer */
1738 return kfifo_out_locked(rds_buf, buf, count*BYTES_PER_BLOCK,
1739 &radio->buf_lock[TAVARUA_BUF_RAW_RDS]);
1740}
1741
1742/*=============================================================================
1743FUNCTION: tavarua_fops_write
1744=============================================================================*/
1745/**
1746 This function is called when a process, which already opened the dev file,
1747 attempts to write to it.
1748
1749 In case of tavarua driver, it is called to write RDS data to host.
1750
1751 @param file: file descriptor.
1752 @param buf: The buffer which has data to write.
1753 @param count: The length of the buffer.
1754 @param ppos: Our offset in the file.
1755
1756 @return The number of bytes written from the buffer.
1757*/
1758static ssize_t tavarua_fops_write(struct file *file, const char __user *data,
1759 size_t count, loff_t *ppos)
1760{
1761 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
1762 int retval = 0;
1763 int bytes_to_copy;
1764 int bytes_copied = 0;
1765 int bytes_left;
1766 int chunk_index = 0;
1767 unsigned char tx_data[XFR_REG_NUM];
1768 /* Disable TX of this type first */
1769 switch (radio->tx_mode) {
1770 case TAVARUA_TX_RT:
1771 bytes_left = min((int)count, MAX_RT_LENGTH);
1772 tx_data[1] = 0;
1773 break;
1774 case TAVARUA_TX_PS:
1775 bytes_left = min((int)count, MAX_PS_LENGTH);
1776 tx_data[4] = 0;
1777 break;
1778 default:
1779 FMDERR("%s: Unknown TX mode\n", __func__);
1780 return -1;
1781 }
1782 retval = sync_write_xfr(radio, radio->tx_mode, tx_data);
1783 if (retval < 0)
1784 return retval;
1785
1786 /* send payload to FM hardware */
1787 while (bytes_left) {
1788 chunk_index++;
1789 bytes_to_copy = min(bytes_left, XFR_REG_NUM);
1790 if (copy_from_user(tx_data, data + bytes_copied, bytes_to_copy))
1791 return -EFAULT;
1792 retval = sync_write_xfr(radio, radio->tx_mode +
1793 chunk_index, tx_data);
1794 if (retval < 0)
1795 return retval;
1796
1797 bytes_copied += bytes_to_copy;
1798 bytes_left -= bytes_to_copy;
1799 }
1800
1801 /* send the header */
1802 switch (radio->tx_mode) {
1803 case TAVARUA_TX_RT:
1804 FMDBG("Writing RT header\n");
1805 tx_data[0] = bytes_copied;
1806 tx_data[1] = TX_ON | 0x03; /* on | PTY */
1807 tx_data[2] = 0x12; /* PI high */
1808 tx_data[3] = 0x34; /* PI low */
1809 break;
1810 case TAVARUA_TX_PS:
1811 FMDBG("Writing PS header\n");
1812 tx_data[0] = chunk_index;
1813 tx_data[1] = 0x03; /* PTY */
1814 tx_data[2] = 0x12; /* PI high */
1815 tx_data[3] = 0x34; /* PI low */
1816 tx_data[4] = TX_ON | 0x01;
1817 break;
1818 default:
1819 FMDERR("%s: Unknown TX mode\n", __func__);
1820 return -1;
1821 }
1822 retval = sync_write_xfr(radio, radio->tx_mode, tx_data);
1823 if (retval < 0)
1824 return retval;
1825 FMDBG("done writing: %d\n", retval);
1826 return bytes_copied;
1827}
1828
1829/*=============================================================================
1830FUNCTION: tavarua_fops_open
1831=============================================================================*/
1832/**
1833 This function is called when a process tries to open the device file, like
1834 "cat /dev/mycharfile"
1835
1836 @param file: file descriptor.
1837
1838 @return => 0 if successful.
1839 @return < 0 if failure.
1840*/
1841static int tavarua_fops_open(struct file *file)
1842{
1843 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
1844 int retval = -ENODEV;
1845 unsigned char value;
1846 /* FM core bring up */
1847 int i = 0;
1848 char fm_ctl0_part1[] = { 0xCA, 0xCE, 0xD6 };
1849 char fm_ctl1[] = { 0x03 };
1850 char fm_ctl0_part2[] = { 0xB6, 0xB7 };
1851 char buffer[] = {0x00, 0x48, 0x8A, 0x8E, 0x97, 0xB7};
1852 int bahama_present = -ENODEV;
1853
Taniya Das9ac855f2012-02-09 18:05:21 +05301854 INIT_DELAYED_WORK(&radio->work, read_int_stat);
Anantha Krishnana2f98082011-10-04 20:02:11 +05301855 if (!atomic_dec_and_test(&radio->users)) {
1856 pr_err("%s: Device already in use."
1857 "Try again later", __func__);
1858 atomic_inc(&radio->users);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001859 return -EBUSY;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001860 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001861
1862 /* initial gpio pin config & Power up */
1863 retval = radio->pdata->fm_setup(radio->pdata);
1864 if (retval) {
1865 printk(KERN_ERR "%s: failed config gpio & pmic\n", __func__);
1866 goto open_err_setup;
1867 }
1868 if (radio->pdata->config_i2s_gpio != NULL) {
1869 retval = radio->pdata->config_i2s_gpio(FM_I2S_ON);
1870 if (retval) {
1871 printk(KERN_ERR "%s: failed config gpio\n", __func__);
1872 goto config_i2s_err;
1873 }
1874 }
1875 /* enable irq */
1876 retval = tavarua_request_irq(radio);
1877 if (retval < 0) {
1878 printk(KERN_ERR "%s: failed to request irq\n", __func__);
1879 goto open_err_req_irq;
1880 }
1881 /* call top level marimba interface here to enable FM core */
1882 FMDBG("initializing SoC\n");
1883
1884 bahama_present = is_bahama();
1885
1886 if (bahama_present == -ENODEV)
1887 return -ENODEV;
1888
1889 if (bahama_present)
1890 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
1891 else
1892 radio->marimba->mod_id = MARIMBA_SLAVE_ID_MARIMBA;
1893
1894 value = FM_ENABLE;
1895 retval = marimba_write_bit_mask(radio->marimba,
1896 MARIMBA_XO_BUFF_CNTRL, &value, 1, value);
1897 if (retval < 0) {
1898 printk(KERN_ERR "%s:XO_BUFF_CNTRL write failed\n",
1899 __func__);
1900 goto open_err_all;
1901 }
1902
1903
1904 /* Bring up FM core */
1905 if (bahama_present) {
1906
1907 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
1908 /* Read the Bahama version*/
1909 retval = marimba_read_bit_mask(radio->marimba,
1910 0x00, &bahama_version, 1, 0x1F);
1911 if (retval < 0) {
1912 printk(KERN_ERR "%s: version read failed",
1913 __func__);
1914 goto open_err_all;
1915 }
Rahul Kashyapc88b6e32011-07-07 10:52:16 +05301916
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001917 /* Check for Bahama V2 variant*/
1918 if (bahama_version == 0x09) {
1919
1920 /* In case of Bahama v2, forcefully enable the
1921 * internal analog and digital voltage controllers
1922 */
1923 value = 0x06;
1924 /* value itself used as mask in these writes*/
1925 retval = marimba_write_bit_mask(radio->marimba,
1926 BAHAMA_LDO_DREG_CTL0, &value, 1, value);
1927 if (retval < 0) {
1928 printk(KERN_ERR "%s:0xF0 write failed\n",
1929 __func__);
1930 goto open_err_all;
1931 }
1932 value = 0x86;
1933 retval = marimba_write_bit_mask(radio->marimba,
1934 BAHAMA_LDO_AREG_CTL0, &value, 1, value);
1935 if (retval < 0) {
1936 printk(KERN_ERR "%s:0xF4 write failed\n",
1937 __func__);
1938 goto open_err_all;
1939 }
1940 }
1941
1942 /*write FM mode*/
1943 retval = tavarua_write_register(radio, BAHAMA_FM_MODE_REG,
1944 BAHAMA_FM_MODE_NORMAL);
1945 if (retval < 0) {
1946 printk(KERN_ERR "failed to set the FM mode: %d\n",
1947 retval);
1948 goto open_err_all;
1949 }
1950 /*Write first sequence of bytes to FM_CTL0*/
1951 for (i = 0; i < 3; i++) {
1952 retval = tavarua_write_register(radio,
1953 BAHAMA_FM_CTL0_REG, fm_ctl0_part1[i]);
1954 if (retval < 0) {
1955 printk(KERN_ERR "FM_CTL0:set-1 failure: %d\n",
1956 retval);
1957 goto open_err_all;
1958 }
1959 }
1960 /*Write the FM_CTL1 sequence*/
1961 for (i = 0; i < 1; i++) {
1962 retval = tavarua_write_register(radio,
1963 BAHAMA_FM_CTL1_REG, fm_ctl1[i]);
1964 if (retval < 0) {
1965 printk(KERN_ERR "FM_CTL1 write failure: %d\n",
1966 retval);
1967 goto open_err_all;
1968 }
1969 }
1970 /*Write second sequence of bytes to FM_CTL0*/
1971 for (i = 0; i < 2; i++) {
1972 retval = tavarua_write_register(radio,
1973 BAHAMA_FM_CTL0_REG, fm_ctl0_part2[i]);
1974 if (retval < 0) {
1975 printk(KERN_ERR "FM_CTL0:set-2 failure: %d\n",
1976 retval);
1977 goto open_err_all;
1978 }
1979 }
1980 } else {
1981 retval = tavarua_write_registers(radio, LEAKAGE_CNTRL,
1982 buffer, 6);
1983 if (retval < 0) {
1984 printk(KERN_ERR "%s: failed to bring up FM Core\n",
1985 __func__);
1986 goto open_err_all;
1987 }
1988 }
1989 /* Wait for interrupt i.e. complete(&radio->sync_req_done); call */
1990 /*Initialize the completion variable for
1991 for the proper behavior*/
1992 init_completion(&radio->sync_req_done);
1993 if (!wait_for_completion_timeout(&radio->sync_req_done,
1994 msecs_to_jiffies(wait_timeout))) {
1995 retval = -1;
1996 FMDERR("Timeout waiting for initialization\n");
1997 }
1998
1999 /* get Chip ID */
2000 retval = tavarua_write_register(radio, XFRCTRL, CHIPID);
2001 if (retval < 0)
2002 goto open_err_all;
2003 msleep(TAVARUA_DELAY);
2004 tavarua_read_registers(radio, XFRCTRL, XFR_REG_NUM+1);
2005 if (radio->registers[XFRCTRL] != CHIPID)
2006 goto open_err_all;
2007
2008 radio->chipID = (radio->registers[XFRCTRL+2] << 24) |
2009 (radio->registers[XFRCTRL+5] << 16) |
2010 (radio->registers[XFRCTRL+6] << 8) |
2011 (radio->registers[XFRCTRL+7]);
2012
2013 printk(KERN_WARNING DRIVER_NAME ": Chip ID %x\n", radio->chipID);
2014 if (radio->chipID == MARIMBA_A0) {
2015 printk(KERN_WARNING DRIVER_NAME ": Unsupported hardware: %x\n",
2016 radio->chipID);
2017 retval = -1;
2018 goto open_err_all;
2019 }
2020
2021 radio->handle_irq = 0;
2022 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
2023 marimba_set_fm_status(radio->marimba, true);
2024 return 0;
2025
2026
2027open_err_all:
2028 /*Disable FM in case of error*/
2029 value = 0x00;
2030 marimba_write_bit_mask(radio->marimba, MARIMBA_XO_BUFF_CNTRL,
2031 &value, 1, value);
2032 tavarua_disable_irq(radio);
2033open_err_req_irq:
2034 if (radio->pdata->config_i2s_gpio != NULL)
2035 radio->pdata->config_i2s_gpio(FM_I2S_OFF);
2036config_i2s_err:
2037 radio->pdata->fm_shutdown(radio->pdata);
2038open_err_setup:
2039 radio->handle_irq = 1;
Anantha Krishnana2f98082011-10-04 20:02:11 +05302040 atomic_inc(&radio->users);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002041 return retval;
2042}
2043
2044/*=============================================================================
2045FUNCTION: tavarua_fops_release
2046=============================================================================*/
2047/**
2048 This function is called when a process closes the device file.
2049
2050 @param file: file descriptor.
2051
2052 @return => 0 if successful.
2053 @return < 0 if failure.
2054*/
2055static int tavarua_fops_release(struct file *file)
2056{
2057 int retval;
2058 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2059 unsigned char value;
2060 int i = 0;
2061 /*FM Core shutdown sequence for Bahama*/
2062 char fm_ctl0_part1[] = { 0xB7 };
2063 char fm_ctl1[] = { 0x03 };
2064 char fm_ctl0_part2[] = { 0x9F, 0x48, 0x02 };
2065 int bahama_present = -ENODEV;
2066 /*FM Core shutdown sequence for Marimba*/
2067 char buffer[] = {0x18, 0xB7, 0x48};
2068 bool bt_status = false;
2069 int index;
2070 /* internal regulator controllers DREG_CTL0, AREG_CTL0
2071 * has to be kept in the valid state based on the bt status.
2072 * 1st row is the state when no clients are active,
2073 * and the second when bt is in on state.
2074 */
2075 char internal_vreg_ctl[2][2] = {
2076 { 0x04, 0x84 },
2077 { 0x00, 0x80 }
2078 };
2079
Anantha Krishnana2f98082011-10-04 20:02:11 +05302080 if (!radio) {
2081 pr_err("%s: Radio device not available...", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002082 return -ENODEV;
Anantha Krishnana2f98082011-10-04 20:02:11 +05302083 }
2084
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002085 FMDBG("In %s", __func__);
2086
Anantha Krishnan1475c932012-02-16 21:54:03 +05302087 FMDBG("%s, Disabling the IRQs\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002088 /* disable irq */
2089 retval = tavarua_disable_irq(radio);
2090 if (retval < 0) {
2091 printk(KERN_ERR "%s: failed to disable irq\n", __func__);
2092 return retval;
2093 }
2094
Anantha Krishnan1475c932012-02-16 21:54:03 +05302095 /* disable radio ctrl */
2096 retval = tavarua_write_register(radio, RDCTRL, 0x00);
2097 if (retval < 0) {
2098 printk(KERN_ERR "%s: failed to disable FM\n", __func__);
2099 return retval;
2100 }
2101
Taniya Das9ac855f2012-02-09 18:05:21 +05302102 init_completion(&radio->shutdown_done);
2103
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002104 bahama_present = is_bahama();
2105
2106 if (bahama_present == -ENODEV)
2107 return -ENODEV;
2108
Taniya Das9ac855f2012-02-09 18:05:21 +05302109 INIT_DELAYED_WORK(&radio->work, fm_shutdown);
2110
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002111 if (bahama_present) {
2112 /*Write first sequence of bytes to FM_CTL0*/
2113 for (i = 0; i < 1; i++) {
2114 retval = tavarua_write_register(radio,
2115 BAHAMA_FM_CTL0_REG, fm_ctl0_part1[i]);
2116 if (retval < 0) {
2117 printk(KERN_ERR "FM_CTL0:Set-1 failure: %d\n",
2118 retval);
2119 break;
2120 }
2121 }
2122 /*Write the FM_CTL1 sequence*/
2123 for (i = 0; i < 1; i++) {
2124 retval = tavarua_write_register(radio,
2125 BAHAMA_FM_CTL1_REG, fm_ctl1[i]);
2126 if (retval < 0) {
2127 printk(KERN_ERR "FM_CTL1 failure: %d\n",
2128 retval);
2129 break;
2130 }
2131 }
2132 /*Write second sequence of bytes to FM_CTL0*/
2133 for (i = 0; i < 3; i++) {
2134 retval = tavarua_write_register(radio,
2135 BAHAMA_FM_CTL0_REG, fm_ctl0_part2[i]);
2136 if (retval < 0) {
2137 printk(KERN_ERR "FM_CTL0:Set-2 failure: %d\n",
2138 retval);
2139 break;
2140 }
2141 }
2142 } else {
2143
2144 retval = tavarua_write_registers(radio, FM_CTL0,
2145 buffer, sizeof(buffer)/sizeof(buffer[0]));
2146 if (retval < 0) {
2147 printk(KERN_ERR "%s: failed to bring down the FM Core\n",
2148 __func__);
2149 return retval;
2150 }
2151 }
2152 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
2153 bt_status = marimba_get_bt_status(radio->marimba);
2154 /* Set the index based on the bt status*/
2155 index = bt_status ? 1 : 0;
2156 /* Check for Bahama's existance and Bahama V2 variant*/
2157 if (bahama_present && (bahama_version == 0x09)) {
2158 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
2159 /* actual value itself used as mask*/
2160 retval = marimba_write_bit_mask(radio->marimba,
2161 BAHAMA_LDO_DREG_CTL0, &internal_vreg_ctl[bt_status][0],
2162 1, internal_vreg_ctl[index][0]);
2163 if (retval < 0) {
2164 printk(KERN_ERR "%s:0xF0 write failed\n", __func__);
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302165 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002166 }
2167 /* actual value itself used as mask*/
2168 retval = marimba_write_bit_mask(radio->marimba,
2169 BAHAMA_LDO_AREG_CTL0, &internal_vreg_ctl[bt_status][1],
2170 1, internal_vreg_ctl[index][1]);
2171 if (retval < 0) {
2172 printk(KERN_ERR "%s:0xF4 write failed\n", __func__);
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302173 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002174 }
2175 } else {
2176 /* disable fm core */
2177 radio->marimba->mod_id = MARIMBA_SLAVE_ID_MARIMBA;
2178 }
2179
2180 value = 0x00;
2181 retval = marimba_write_bit_mask(radio->marimba, MARIMBA_XO_BUFF_CNTRL,
2182 &value, 1, FM_ENABLE);
2183 if (retval < 0) {
2184 printk(KERN_ERR "%s:XO_BUFF_CNTRL write failed\n", __func__);
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302185 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002186 }
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302187exit:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002188 FMDBG("%s, Calling fm_shutdown\n", __func__);
Taniya Das9ac855f2012-02-09 18:05:21 +05302189 queue_delayed_work(radio->wqueue, &radio->work,
2190 msecs_to_jiffies(TAVARUA_DELAY/2));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002191 /* teardown gpio and pmic */
Rahul Kashyapc88b6e32011-07-07 10:52:16 +05302192 marimba_set_fm_status(radio->marimba, false);
Taniya Das9ac855f2012-02-09 18:05:21 +05302193 wait_for_completion(&radio->shutdown_done);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002194 radio->handle_irq = 1;
Anantha Krishnanaf2eafc2012-04-04 11:58:28 +05302195 radio->lp_mode = 1;
Anantha Krishnan93eb1762012-06-04 13:41:07 +05302196 radio->spur_table_size = 0;
Anantha Krishnana2f98082011-10-04 20:02:11 +05302197 atomic_inc(&radio->users);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002198 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
Taniya Das9ac855f2012-02-09 18:05:21 +05302199 flush_workqueue(radio->wqueue);
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302200 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002201}
2202
2203/*
2204 * tavarua_fops - file operations interface
2205 */
2206static const struct v4l2_file_operations tavarua_fops = {
2207 .owner = THIS_MODULE,
2208 .read = tavarua_fops_read,
2209 .write = tavarua_fops_write,
2210 .ioctl = video_ioctl2,
2211 .open = tavarua_fops_open,
2212 .release = tavarua_fops_release,
2213};
2214
2215/*************************************************************************
2216 * Video4Linux Interface
2217 *************************************************************************/
2218
2219/*
2220 * tavarua_v4l2_queryctrl - query control
2221 */
2222static struct v4l2_queryctrl tavarua_v4l2_queryctrl[] = {
2223 {
2224 .id = V4L2_CID_AUDIO_VOLUME,
2225 .type = V4L2_CTRL_TYPE_INTEGER,
2226 .name = "Volume",
2227 .minimum = 0,
2228 .maximum = 15,
2229 .step = 1,
2230 .default_value = 15,
2231 },
2232 {
2233 .id = V4L2_CID_AUDIO_BALANCE,
2234 .flags = V4L2_CTRL_FLAG_DISABLED,
2235 },
2236 {
2237 .id = V4L2_CID_AUDIO_BASS,
2238 .flags = V4L2_CTRL_FLAG_DISABLED,
2239 },
2240 {
2241 .id = V4L2_CID_AUDIO_TREBLE,
2242 .flags = V4L2_CTRL_FLAG_DISABLED,
2243 },
2244 {
2245 .id = V4L2_CID_AUDIO_MUTE,
2246 .type = V4L2_CTRL_TYPE_BOOLEAN,
2247 .name = "Mute",
2248 .minimum = 0,
2249 .maximum = 1,
2250 .step = 1,
2251 .default_value = 1,
2252 },
2253 {
2254 .id = V4L2_CID_AUDIO_LOUDNESS,
2255 .flags = V4L2_CTRL_FLAG_DISABLED,
2256 },
2257 {
2258 .id = V4L2_CID_PRIVATE_TAVARUA_SRCHMODE,
2259 .type = V4L2_CTRL_TYPE_INTEGER,
2260 .name = "Search mode",
2261 .minimum = 0,
2262 .maximum = 7,
2263 .step = 1,
2264 .default_value = 0,
2265 },
2266 {
2267 .id = V4L2_CID_PRIVATE_TAVARUA_SCANDWELL,
2268 .type = V4L2_CTRL_TYPE_INTEGER,
2269 .name = "Search dwell time",
2270 .minimum = 0,
2271 .maximum = 7,
2272 .step = 1,
2273 .default_value = 0,
2274 },
2275 {
2276 .id = V4L2_CID_PRIVATE_TAVARUA_SRCHON,
2277 .type = V4L2_CTRL_TYPE_BOOLEAN,
2278 .name = "Search on/off",
2279 .minimum = 0,
2280 .maximum = 1,
2281 .step = 1,
2282 .default_value = 1,
2283
2284 },
2285 {
2286 .id = V4L2_CID_PRIVATE_TAVARUA_STATE,
2287 .type = V4L2_CTRL_TYPE_INTEGER,
2288 .name = "radio 0ff/rx/tx/reset",
2289 .minimum = 0,
2290 .maximum = 3,
2291 .step = 1,
2292 .default_value = 1,
2293
2294 },
2295 {
2296 .id = V4L2_CID_PRIVATE_TAVARUA_REGION,
2297 .type = V4L2_CTRL_TYPE_INTEGER,
2298 .name = "radio standard",
2299 .minimum = 0,
2300 .maximum = 2,
2301 .step = 1,
2302 .default_value = 0,
2303 },
2304 {
2305 .id = V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH,
2306 .type = V4L2_CTRL_TYPE_INTEGER,
2307 .name = "Signal Threshold",
2308 .minimum = 0x80,
2309 .maximum = 0x7F,
2310 .step = 1,
2311 .default_value = 0,
2312 },
2313 {
2314 .id = V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY,
2315 .type = V4L2_CTRL_TYPE_INTEGER,
2316 .name = "Search PTY",
2317 .minimum = 0,
2318 .maximum = 31,
2319 .default_value = 0,
2320 },
2321 {
2322 .id = V4L2_CID_PRIVATE_TAVARUA_SRCH_PI,
2323 .type = V4L2_CTRL_TYPE_INTEGER,
2324 .name = "Search PI",
2325 .minimum = 0,
2326 .maximum = 0xFF,
2327 .default_value = 0,
2328 },
2329 {
2330 .id = V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT,
2331 .type = V4L2_CTRL_TYPE_INTEGER,
2332 .name = "Preset num",
2333 .minimum = 0,
2334 .maximum = 12,
2335 .default_value = 0,
2336 },
2337 {
2338 .id = V4L2_CID_PRIVATE_TAVARUA_EMPHASIS,
2339 .type = V4L2_CTRL_TYPE_BOOLEAN,
2340 .name = "Emphasis",
2341 .minimum = 0,
2342 .maximum = 1,
2343 .default_value = 0,
2344 },
2345 {
2346 .id = V4L2_CID_PRIVATE_TAVARUA_RDS_STD,
2347 .type = V4L2_CTRL_TYPE_BOOLEAN,
2348 .name = "RDS standard",
2349 .minimum = 0,
2350 .maximum = 1,
2351 .default_value = 0,
2352 },
2353 {
2354 .id = V4L2_CID_PRIVATE_TAVARUA_SPACING,
2355 .type = V4L2_CTRL_TYPE_INTEGER,
2356 .name = "Channel spacing",
2357 .minimum = 0,
2358 .maximum = 2,
2359 .default_value = 0,
2360 },
2361 {
2362 .id = V4L2_CID_PRIVATE_TAVARUA_RDSON,
2363 .type = V4L2_CTRL_TYPE_BOOLEAN,
2364 .name = "RDS on/off",
2365 .minimum = 0,
2366 .maximum = 1,
2367 .default_value = 0,
2368 },
2369 {
2370 .id = V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK,
2371 .type = V4L2_CTRL_TYPE_INTEGER,
2372 .name = "RDS group mask",
2373 .minimum = 0,
2374 .maximum = 0xFFFFFFFF,
2375 .default_value = 0,
2376 },
2377 {
2378 .id = V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC,
2379 .type = V4L2_CTRL_TYPE_INTEGER,
2380 .name = "RDS processing",
2381 .minimum = 0,
2382 .maximum = 0xFF,
2383 .default_value = 0,
2384 },
2385 {
2386 .id = V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF,
2387 .type = V4L2_CTRL_TYPE_INTEGER,
2388 .name = "RDS data groups to buffer",
2389 .minimum = 1,
2390 .maximum = 21,
2391 .default_value = 0,
2392 },
2393 {
2394 .id = V4L2_CID_PRIVATE_TAVARUA_PSALL,
2395 .type = V4L2_CTRL_TYPE_BOOLEAN,
2396 .name = "pass all ps strings",
2397 .minimum = 0,
2398 .maximum = 1,
2399 .default_value = 0,
2400 },
2401 {
2402 .id = V4L2_CID_PRIVATE_TAVARUA_LP_MODE,
2403 .type = V4L2_CTRL_TYPE_BOOLEAN,
2404 .name = "Low power mode",
2405 .minimum = 0,
2406 .maximum = 1,
2407 .default_value = 0,
2408 },
2409 {
2410 .id = V4L2_CID_PRIVATE_TAVARUA_ANTENNA,
2411 .type = V4L2_CTRL_TYPE_BOOLEAN,
2412 .name = "headset/internal",
2413 .minimum = 0,
2414 .maximum = 1,
2415 .default_value = 0,
2416 },
2417 /* Private controls for FM TX*/
2418 {
2419 .id = V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT,
2420 .type = V4L2_CTRL_TYPE_INTEGER,
2421 .name = "Set PS REPEATCOUNT",
2422 .minimum = 0,
2423 .maximum = 15,
2424 },
2425 {
2426 .id = V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_PS_NAME,
2427 .type = V4L2_CTRL_TYPE_BOOLEAN,
2428 .name = "Stop PS NAME",
2429 .minimum = 0,
2430 .maximum = 1,
2431 },
2432 {
2433 .id = V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_RT,
2434 .type = V4L2_CTRL_TYPE_BOOLEAN,
2435 .name = "Stop RT",
2436 .minimum = 0,
2437 .maximum = 1,
2438 },
Anantha Krishnan71d6fa62011-12-13 19:30:51 +05302439 { .id = V4L2_CID_PRIVATE_SET_NOTCH_FILTER,
Srinivasa Rao Uppala4e38bfc2011-09-15 16:00:31 +05302440 .type = V4L2_CTRL_TYPE_INTEGER,
2441 .name = "Notch filter",
2442 .minimum = 0,
2443 .maximum = 2,
2444 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002445
2446};
2447
2448/*=============================================================================
2449FUNCTION: tavarua_vidioc_querycap
2450=============================================================================*/
2451/**
2452 This function is called to query device capabilities.
2453
2454 NOTE:
2455 All V4L2 devices support the VIDIOC_QUERYCAP ioctl. It is used to identify
2456 kernel devices compatible with this specification and to obtain information
2457 about driver and hardware capabilities. The ioctl takes a pointer to a struct
2458 v4l2_capability which is filled by the driver. When the driver is not
2459 compatible with this specification the ioctl returns an EINVAL error code.
2460
2461 @param file: File descriptor returned by open().
2462 @param capability: pointer to struct v4l2_capability.
2463
2464 @return On success 0 is returned, else error code.
2465 @return EINVAL: The device is not compatible with this specification.
2466*/
2467static int tavarua_vidioc_querycap(struct file *file, void *priv,
2468 struct v4l2_capability *capability)
2469{
2470 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2471
2472 strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
2473 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
2474 sprintf(capability->bus_info, "I2C");
2475 capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
2476
2477 capability->version = radio->chipID;
2478
2479 return 0;
2480}
2481
2482/*=============================================================================
2483FUNCTION: tavarua_vidioc_queryctrl
2484=============================================================================*/
2485/**
2486 This function is called to query the device and driver for supported video
2487 controls (enumerate control items).
2488
2489 NOTE:
2490 To query the attributes of a control, the applications set the id field of
2491 a struct v4l2_queryctrl and call the VIDIOC_QUERYCTRL ioctl with a pointer
2492 to this structure. The driver fills the rest of the structure or returns an
2493 EINVAL error code when the id is invalid.
2494
2495 @param file: File descriptor returned by open().
2496 @param qc: pointer to struct v4l2_queryctrl.
2497
2498 @return On success 0 is returned, else error code.
2499 @return EINVAL: The struct v4l2_queryctrl id is invalid.
2500*/
2501static int tavarua_vidioc_queryctrl(struct file *file, void *priv,
2502 struct v4l2_queryctrl *qc)
2503{
2504 unsigned char i;
2505 int retval = -EINVAL;
2506
2507 for (i = 0; i < ARRAY_SIZE(tavarua_v4l2_queryctrl); i++) {
2508 if (qc->id && qc->id == tavarua_v4l2_queryctrl[i].id) {
2509 memcpy(qc, &(tavarua_v4l2_queryctrl[i]), sizeof(*qc));
2510 retval = 0;
2511 break;
2512 }
2513 }
2514 if (retval < 0)
2515 printk(KERN_WARNING DRIVER_NAME
2516 ": query conv4ltrol failed with %d\n", retval);
2517
2518 return retval;
2519}
Anantha Krishnan93eb1762012-06-04 13:41:07 +05302520
2521static int update_spur_table(struct tavarua_device *radio)
2522{
2523 unsigned char xfr_buf[XFR_REG_NUM];
2524 unsigned char size = 0, tbl_size = 0;
2525 int index = 0, offset = 0, addr = 0x0, val = 0;
2526 int retval = 0, temp = 0, cnt = 0, j = 0;
2527
2528 memset(xfr_buf, 0x0, XFR_REG_NUM);
2529
2530 /* Read the SPUR Table Size */
2531 retval = xfr_rdwr_data(radio, XFR_READ, 1, SPUR_TABLE_ADDR, &tbl_size);
2532 if (retval < 0) {
2533 FMDERR("%s: Failed to read SPUR table size\n", __func__);
2534 return retval;
2535 }
2536
2537 /* Calculate the new SPUR Register address */
2538 val = addr = (SPUR_TABLE_START_ADDR + (tbl_size * 3));
2539
2540 /* Save the SPUR Table length configured by user*/
2541 temp = radio->spur_table_size;
2542
2543 /* COnfigure the new spur table length */
2544 size = (radio->spur_table_size + tbl_size);
2545 retval = xfr_rdwr_data(radio, XFR_WRITE, 1, SPUR_TABLE_ADDR, &size);
2546 if (retval < 0) {
2547 FMDERR("%s: Failed to configure SPUR table size\n", __func__);
2548 return retval;
2549 }
2550
2551 /* Program the spur table entries */
2552 for (cnt = 0; cnt < (temp / 4); cnt++) {
2553 offset = 0;
2554 for (j = 0; j < 4; j++) {
2555 xfr_buf[offset++] = GET_FREQ(COMPUTE_SPUR(
2556 radio->spur_data.freq[index]), 1);
2557 xfr_buf[offset++] = GET_FREQ(COMPUTE_SPUR(
2558 radio->spur_data.freq[index]), 0);
2559 xfr_buf[offset++] =
2560 radio->spur_data.rmssi[index];
2561 index++;
2562 }
2563 retval = xfr_rdwr_data(radio, XFR_WRITE, (SPUR_DATA_SIZE * 4),
2564 addr, xfr_buf);
2565 if (retval < 0) {
2566 FMDERR("%s: Failed to program SPUR frequencies\n",
2567 __func__);
2568 return retval;
2569 }
2570 addr += (SPUR_DATA_SIZE * 4);
2571 }
2572
2573 /* Program the additional SPUR Frequencies */
2574 temp = radio->spur_table_size;
2575 temp = (temp % 4);
2576 if (temp > 0) {
2577 offset = 0;
2578 for (j = 0; j < temp; j++) {
2579 xfr_buf[offset++] = GET_FREQ(COMPUTE_SPUR(
2580 radio->spur_data.freq[index]), 1);
2581 xfr_buf[offset++] = GET_FREQ(COMPUTE_SPUR(
2582 radio->spur_data.freq[index]), 0);
2583 xfr_buf[offset++] =
2584 radio->spur_data.rmssi[index];
2585 index++;
2586 }
2587 size = (temp * SPUR_DATA_SIZE);
2588 retval = xfr_rdwr_data(radio, XFR_WRITE, size, addr, xfr_buf);
2589 if (retval < 0) {
2590 FMDERR("%s: Failed to program SPUR frequencies\n",
2591 __func__);
2592 return retval;
2593 }
2594 }
2595
2596 return retval;
2597}
2598
2599static int xfr_rdwr_data(struct tavarua_device *radio, int op, int size,
2600 unsigned long offset, unsigned char *buf) {
2601
2602 unsigned char xfr_buf[XFR_REG_NUM];
2603 int retval = 0, temp = 0;
2604
2605 memset(xfr_buf, 0x0, XFR_REG_NUM);
2606 temp = size;
2607
2608 xfr_buf[XFR_MODE_OFFSET] = (size << 1);
2609 xfr_buf[XFR_ADDR_MSB_OFFSET] = GET_FREQ(offset, 1);
2610 xfr_buf[XFR_ADDR_LSB_OFFSET] = GET_FREQ(offset, 0);
2611
2612 if (op == XFR_READ) {
2613 xfr_buf[XFR_MODE_OFFSET] |= (XFR_PEEK_MODE);
2614 size = 3;
2615 } else if (op == XFR_WRITE) {
2616 xfr_buf[XFR_MODE_OFFSET] |= (XFR_POKE_MODE);
2617 memcpy(&xfr_buf[XFR_DATA_OFFSET], buf, size);
2618 size += 3;
2619 }
2620
2621 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, size);
2622 if (retval < 0) {
2623 FMDERR("%s: Failed to performXFR operation\n", __func__);
2624 return retval;
2625 }
2626
2627 size = temp;
2628
2629 /*Wait for the XFR interrupt */
2630 init_completion(&radio->sync_req_done);
2631 if (!wait_for_completion_timeout(&radio->sync_req_done,
2632 msecs_to_jiffies(WAIT_TIMEOUT))) {
2633 FMDERR("Timeout: No XFR interrupt");
2634 }
2635
2636 if (op == XFR_READ) {
2637 retval = tavarua_read_registers(radio, XFRDAT0, size);
2638 if (retval < 0) {
2639 FMDERR("%s: Failed to read the XFR data\n", __func__);
2640 return retval;
2641 }
2642 if (buf != NULL)
2643 memcpy(buf, &radio->registers[XFRDAT0], size);
2644 }
2645
2646 return retval;
2647}
2648
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002649static int peek_MPX_DCC(struct tavarua_device *radio)
2650{
2651 int retval = 0;
2652 unsigned char xfr_buf[XFR_REG_NUM];
2653 int MPX_DCC[] = { 0 };
2654 int DCC = 0;
2655 int ct = 0;
2656 unsigned char size = 0;
2657
2658 /*
2659 Poking the MPX_DCC_BYPASS register to freeze the
2660 value of MPX_DCC from changing while we access it
2661 */
2662
2663 /*Poking the MPX_DCC_BYPASS register : 0x88C0 */
2664 size = 0x01;
2665 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
2666 xfr_buf[1] = MPX_DCC_BYPASS_POKE_MSB;
2667 xfr_buf[2] = MPX_DCC_BYPASS_POKE_LSB;
2668 xfr_buf[3] = 0x01;
2669
2670 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 4);
2671 if (retval < 0) {
2672 FMDBG("Failed to write\n");
2673 return retval;
2674 }
2675 /*Wait for the XFR interrupt */
2676 msleep(TAVARUA_DELAY*15);
2677
2678 for (ct = 0; ct < 5; ct++)
2679 xfr_buf[ct] = 0;
2680
2681 /* Peeking Regs 0x88C2-0x88C4 */
2682 size = 0x03;
2683 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
2684 xfr_buf[1] = MPX_DCC_PEEK_MSB_REG1;
2685 xfr_buf[2] = MPX_DCC_PEEK_LSB_REG1;
2686 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
2687 if (retval < 0) {
2688 FMDBG("Failed to write\n");
2689 return retval;
2690 }
2691 /*Wait for the XFR interrupt */
2692 msleep(TAVARUA_DELAY*10);
2693 retval = tavarua_read_registers(radio, XFRDAT0, 3);
2694 if (retval < 0) {
2695 printk(KERN_INFO "INT_DET: Read failure\n");
2696 return retval;
2697 }
2698 MPX_DCC[0] = (int)radio->registers[XFRDAT0];
2699 MPX_DCC[1] = (int)radio->registers[XFRDAT1];
2700 MPX_DCC[2] = (int)radio->registers[XFRDAT2];
2701
2702 /*
2703 Form the final MPX_DCC parameter
2704 MPX_DCC[0] will form the LSB part
2705 MPX_DCC[1] will be the middle part and 4 bits of
2706 MPX_DCC[2] will be the MSB par of the 20-bit signed MPX_DCC
2707 */
2708
2709 DCC = ((int)MPX_DCC[2] << 16) | ((int)MPX_DCC[1] << 8) |
2710 ((int)MPX_DCC[0]);
2711
2712 /*
2713 if bit-19 is '1',set remaining bits to '1' & make it -tive
2714 */
2715 if (DCC & 0x00080000) {
2716 FMDBG(KERN_INFO "bit-19 is '1'\n");
2717 DCC |= 0xFFF00000;
2718 }
2719
2720 /*
2721 Poking the MPX_DCC_BYPASS register to be back to normal
2722 */
2723
2724 /*Poking the MPX_DCC_BYPASS register : 0x88C0 */
2725 size = 0x01;
2726 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
2727 xfr_buf[1] = MPX_DCC_BYPASS_POKE_MSB;
2728 xfr_buf[2] = MPX_DCC_BYPASS_POKE_LSB;
2729 xfr_buf[3] = 0x00;
2730
2731 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 4);
2732 if (retval < 0) {
2733 FMDBG("Failed to write\n");
2734 return retval;
2735 }
2736 /*Wait for the XFR interrupt */
2737 msleep(TAVARUA_DELAY*10);
2738
2739 return DCC;
2740}
2741/*=============================================================================
2742FUNCTION: tavarua_vidioc_g_ctrl
2743=============================================================================*/
2744/**
2745 This function is called to get the value of a control.
2746
2747 NOTE:
2748 To get the current value of a control, applications initialize the id field
2749 of a struct v4l2_control and call the VIDIOC_G_CTRL ioctl with a pointer to
2750 this structure.
2751
2752 When the id is invalid drivers return an EINVAL error code. When the value is
2753 out of bounds drivers can choose to take the closest valid value or return an
2754 ERANGE error code, whatever seems more appropriate.
2755
2756 @param file: File descriptor returned by open().
2757 @param ctrl: pointer to struct v4l2_control.
2758
2759 @return On success 0 is returned, else error code.
2760 @return EINVAL: The struct v4l2_control id is invalid.
2761 @return ERANGE: The struct v4l2_control value is out of bounds.
2762 @return EBUSY: The control is temporarily not changeable, possibly because
2763 another applications took over control of the device function this control
2764 belongs to.
2765*/
2766static int tavarua_vidioc_g_ctrl(struct file *file, void *priv,
2767 struct v4l2_control *ctrl)
2768{
2769 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2770 int retval = 0;
Anantha Krishnana3dcce42012-01-05 19:27:57 +05302771 int cnt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002772 unsigned char xfr_buf[XFR_REG_NUM];
2773 signed char cRmssiThreshold;
2774 signed char ioc;
2775 unsigned char size = 0;
2776
2777 switch (ctrl->id) {
2778 case V4L2_CID_AUDIO_VOLUME:
2779 break;
2780 case V4L2_CID_AUDIO_MUTE:
2781 ctrl->value = radio->registers[IOCTRL] & 0x03 ;
2782 break;
2783 case V4L2_CID_PRIVATE_TAVARUA_SRCHMODE:
2784 ctrl->value = radio->registers[SRCHCTRL] & SRCH_MODE;
2785 break;
2786 case V4L2_CID_PRIVATE_TAVARUA_SCANDWELL:
2787 ctrl->value = (radio->registers[SRCHCTRL] & SCAN_DWELL) >> 4;
2788 break;
2789 case V4L2_CID_PRIVATE_TAVARUA_SRCHON:
2790 ctrl->value = (radio->registers[SRCHCTRL] & SRCH_ON) >> 7 ;
2791 break;
2792 case V4L2_CID_PRIVATE_TAVARUA_STATE:
2793 ctrl->value = (radio->registers[RDCTRL] & 0x03);
2794 break;
2795 case V4L2_CID_PRIVATE_TAVARUA_IOVERC:
2796 retval = tavarua_read_registers(radio, IOVERC, 1);
2797 if (retval < 0)
2798 return retval;
2799 ioc = radio->registers[IOVERC];
2800 ctrl->value = ioc;
2801 break;
2802 case V4L2_CID_PRIVATE_TAVARUA_INTDET:
2803 size = 0x1;
2804 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
2805 xfr_buf[1] = INTDET_PEEK_MSB;
2806 xfr_buf[2] = INTDET_PEEK_LSB;
2807 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
2808 if (retval < 0) {
2809 FMDBG("Failed to write\n");
2810 return retval;
2811 }
2812 FMDBG("INT_DET:Sync write success\n");
2813 /*Wait for the XFR interrupt */
2814 msleep(TAVARUA_DELAY*10);
2815 /* Read the XFRDAT0 register populated by FM SoC */
2816 retval = tavarua_read_registers(radio, XFRDAT0, 3);
2817 if (retval < 0) {
2818 FMDBG("INT_DET: Read failure\n");
2819 return retval;
2820 }
2821 ctrl->value = radio->registers[XFRDAT0];
2822 break;
2823 case V4L2_CID_PRIVATE_TAVARUA_MPX_DCC:
2824 ctrl->value = peek_MPX_DCC(radio);
2825 break;
2826 case V4L2_CID_PRIVATE_TAVARUA_REGION:
2827 ctrl->value = radio->region_params.region;
2828 break;
2829 case V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH:
2830 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
2831 if (retval < 0) {
2832 FMDBG("[G IOCTL=V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
2833 FMDBG("sync_read_xfr error: [retval=%d]\n", retval);
2834 break;
2835 }
2836 /* Since RMSSI Threshold is signed value */
2837 cRmssiThreshold = (signed char)xfr_buf[0];
2838 ctrl->value = cRmssiThreshold;
2839 FMDBG("cRmssiThreshold: %d\n", cRmssiThreshold);
2840 break;
2841 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY:
2842 ctrl->value = radio->srch_params.srch_pty;
2843 break;
2844 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PI:
2845 ctrl->value = radio->srch_params.srch_pi;
2846 break;
2847 case V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT:
2848 ctrl->value = radio->srch_params.preset_num;
2849 break;
2850 case V4L2_CID_PRIVATE_TAVARUA_EMPHASIS:
2851 ctrl->value = radio->region_params.emphasis;
2852 break;
2853 case V4L2_CID_PRIVATE_TAVARUA_RDS_STD:
2854 ctrl->value = radio->region_params.rds_std;
2855 break;
2856 case V4L2_CID_PRIVATE_TAVARUA_SPACING:
2857 ctrl->value = radio->region_params.spacing;
2858 break;
2859 case V4L2_CID_PRIVATE_TAVARUA_RDSON:
2860 ctrl->value = radio->registers[RDSCTRL] & RDS_ON;
2861 break;
2862 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK:
2863 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
2864 if (retval > -1)
2865 ctrl->value = (xfr_buf[8] << 24) |
2866 (xfr_buf[9] << 16) |
2867 (xfr_buf[10] << 8) |
2868 xfr_buf[11];
2869 break;
2870 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC:
2871 retval = tavarua_read_registers(radio, ADVCTRL, 1);
2872 if (retval > -1)
2873 ctrl->value = radio->registers[ADVCTRL];
Anantha Krishnane46ef6f2011-06-29 23:56:03 +05302874 msleep(TAVARUA_DELAY*5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002875 break;
Anantha Krishnan3be3b262011-09-05 17:22:48 +05302876 case V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA:
2877 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
2878 if (retval < 0) {
2879 FMDERR("V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA]\n");
2880 FMDERR("sync_read_xfr [retval=%d]\n", retval);
2881 break;
2882 }
2883 ctrl->value = (unsigned char)xfr_buf[4];
2884 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002885 case V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF:
2886 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
2887 if (retval > -1)
2888 ctrl->value = xfr_buf[1];
2889 break;
2890 case V4L2_CID_PRIVATE_TAVARUA_PSALL:
2891 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
2892 if (retval > -1)
2893 ctrl->value = xfr_buf[12] & RDS_CONFIG_PSALL;
2894 break;
2895 case V4L2_CID_PRIVATE_TAVARUA_LP_MODE:
2896 ctrl->value = radio->lp_mode;
2897 break;
2898 case V4L2_CID_PRIVATE_TAVARUA_ANTENNA:
2899 ctrl->value = GET_REG_FIELD(radio->registers[IOCTRL],
2900 IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
2901 break;
Anantha Krishnana3dcce42012-01-05 19:27:57 +05302902 case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
2903 size = 0x04;
2904 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
2905 xfr_buf[1] = ON_CHANNEL_TH_MSB;
2906 xfr_buf[2] = ON_CHANNEL_TH_LSB;
2907 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
2908 if (retval < 0) {
2909 pr_err("%s: Failed to write\n", __func__);
2910 return retval;
2911 }
2912 /*Wait for the XFR interrupt */
2913 msleep(TAVARUA_DELAY*10);
2914 retval = tavarua_read_registers(radio, XFRDAT0, 4);
2915 if (retval < 0) {
2916 pr_err("%s: On Ch. DET: Read failure\n", __func__);
2917 return retval;
2918 }
2919 for (cnt = 0; cnt < 4; cnt++)
2920 FMDBG("On-Channel data set is : 0x%x\t",
2921 (int)radio->registers[XFRDAT0+cnt]);
2922
2923 ctrl->value = LSH_DATA(radio->registers[XFRDAT0], 24) |
2924 LSH_DATA(radio->registers[XFRDAT0+1], 16) |
2925 LSH_DATA(radio->registers[XFRDAT0+2], 8) |
2926 (radio->registers[XFRDAT0+3]);
2927 FMDBG("The On Channel Threshold value is : 0x%x", ctrl->value);
2928 break;
2929 case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
2930 size = 0x04;
2931 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
2932 xfr_buf[1] = OFF_CHANNEL_TH_MSB;
2933 xfr_buf[2] = OFF_CHANNEL_TH_LSB;
2934 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
2935 if (retval < 0) {
2936 pr_err("%s: Failed to write\n", __func__);
2937 return retval;
2938 }
2939 /*Wait for the XFR interrupt */
2940 msleep(TAVARUA_DELAY*10);
2941 retval = tavarua_read_registers(radio, XFRDAT0, 4);
2942 if (retval < 0) {
2943 pr_err("%s: Off Ch. DET: Read failure\n", __func__);
2944 return retval;
2945 }
2946 for (cnt = 0; cnt < 4; cnt++)
2947 FMDBG("Off-channel data set is : 0x%x\t",
2948 (int)radio->registers[XFRDAT0+cnt]);
2949
2950 ctrl->value = LSH_DATA(radio->registers[XFRDAT0], 24) |
2951 LSH_DATA(radio->registers[XFRDAT0+1], 16) |
2952 LSH_DATA(radio->registers[XFRDAT0+2], 8) |
2953 (radio->registers[XFRDAT0+3]);
2954 FMDBG("The Off Channel Threshold value is : 0x%x", ctrl->value);
2955 break;
2956 /*
2957 * These IOCTL's are place holders to keep the
2958 * driver compatible with change in frame works for IRIS
2959 */
2960 case V4L2_CID_PRIVATE_SINR_THRESHOLD:
2961 case V4L2_CID_PRIVATE_SINR_SAMPLES:
2962 case V4L2_CID_PRIVATE_IRIS_GET_SINR:
2963 retval = 0;
2964 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002965 default:
2966 retval = -EINVAL;
2967 }
2968 if (retval < 0)
2969 printk(KERN_WARNING DRIVER_NAME
2970 ": get control failed with %d, id: %d\n", retval, ctrl->id);
2971
2972 return retval;
2973}
2974
2975static int tavarua_vidioc_s_ext_ctrls(struct file *file, void *priv,
2976 struct v4l2_ext_controls *ctrl)
2977{
2978 int retval = 0;
2979 int bytes_to_copy;
2980 int bytes_copied = 0;
2981 int bytes_left = 0;
2982 int chunk_index = 0;
2983 char tx_data[XFR_REG_NUM];
2984 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2985 char *data = NULL;
2986 int extra_name_byte = 0;
2987 int name_bytes = 0;
2988
2989 switch ((ctrl->controls[0]).id) {
2990 case V4L2_CID_RDS_TX_PS_NAME: {
2991 FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
2992 /*Pass a sample PS string */
2993
2994 chunk_index = 0;
2995 bytes_copied = 0;
2996 bytes_left = min((int)(ctrl->controls[0]).size,
2997 MAX_PS_LENGTH);
2998 data = (ctrl->controls[0]).string;
2999
3000 /* send payload to FM hardware */
3001 while (bytes_left) {
3002 chunk_index++;
3003 FMDBG("chunk is %d", chunk_index);
3004 bytes_to_copy = min(bytes_left, XFR_REG_NUM);
3005 /*Clear the tx_data */
3006 memset(tx_data, 0, XFR_REG_NUM);
3007 if (copy_from_user(tx_data,
3008 data + bytes_copied, bytes_to_copy))
3009 return -EFAULT;
3010 retval = sync_write_xfr(radio,
3011 RDS_PS_0 + chunk_index, tx_data);
3012 if (retval < 0) {
3013 FMDBG("sync_write_xfr: %d", retval);
3014 return retval;
3015 }
3016 bytes_copied += bytes_to_copy;
3017 bytes_left -= bytes_to_copy;
3018 }
3019 memset(tx_data, 0, XFR_REG_NUM);
3020 /*Write the PS Header*/
3021 FMDBG("Writing PS header\n");
3022 extra_name_byte = (bytes_copied%8) ? 1 : 0;
3023 name_bytes = (bytes_copied/8) + extra_name_byte;
3024 /*8 bytes are grouped as 1 name */
3025 tx_data[0] = (name_bytes) & MASK_TXREPCOUNT;
3026 tx_data[1] = radio->pty & MASK_PTY; /* PTY */
3027 tx_data[2] = ((radio->pi & MASK_PI_MSB) >> 8);
3028 tx_data[3] = radio->pi & MASK_PI_LSB;
3029 /* TX ctrl + repeatCount*/
3030 tx_data[4] = TX_ON |
3031 (radio->ps_repeatcount & MASK_TXREPCOUNT);
3032 retval = sync_write_xfr(radio, RDS_PS_0, tx_data);
3033 if (retval < 0) {
3034 FMDBG("sync_write_xfr returned %d", retval);
3035 return retval;
3036 }
3037 } break;
3038 case V4L2_CID_RDS_TX_RADIO_TEXT: {
3039 chunk_index = 0;
3040 bytes_copied = 0;
3041 FMDBG("In V4L2_CID_RDS_TX_RADIO_TEXT\n");
3042 /*Pass a sample PS string */
3043 FMDBG("Passed RT String : %s\n",
3044 (ctrl->controls[0]).string);
3045 bytes_left =
3046 min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
3047 data = (ctrl->controls[0]).string;
3048 /* send payload to FM hardware */
3049 while (bytes_left) {
3050 chunk_index++;
3051 bytes_to_copy = min(bytes_left, XFR_REG_NUM);
3052 memset(tx_data, 0, XFR_REG_NUM);
3053 if (copy_from_user(tx_data,
3054 data + bytes_copied, bytes_to_copy))
3055 return -EFAULT;
3056 retval = sync_write_xfr(radio,
3057 RDS_RT_0 + chunk_index, tx_data);
3058 if (retval < 0)
3059 return retval;
3060 bytes_copied += bytes_to_copy;
3061 bytes_left -= bytes_to_copy;
3062 }
3063 /*Write the RT Header */
3064 tx_data[0] = bytes_copied;
3065 /* PTY */
3066 tx_data[1] = TX_ON | ((radio->pty & MASK_PTY) >> 8);
3067 /* PI high */
3068 tx_data[2] = ((radio->pi & MASK_PI_MSB) >> 8);
3069 /* PI low */
3070 tx_data[3] = radio->pi & MASK_PI_LSB;
3071 retval = sync_write_xfr(radio, RDS_RT_0 , tx_data);
3072 if (retval < 0)
3073 return retval;
3074 FMDBG("done RT writing: %d\n", retval);
3075 } break;
3076 default:
3077 {
3078 FMDBG("Shouldn't reach here\n");
3079 retval = -1;
3080 }
3081 }
3082 return retval;
3083}
3084
3085/*=============================================================================
3086FUNCTION: tavarua_vidioc_s_ctrl
3087=============================================================================*/
3088/**
3089 This function is called to set the value of a control.
3090
3091 NOTE:
3092 To change the value of a control, applications initialize the id and value
3093 fields of a struct v4l2_control and call the VIDIOC_S_CTRL ioctl.
3094
3095 When the id is invalid drivers return an EINVAL error code. When the value is
3096 out of bounds drivers can choose to take the closest valid value or return an
3097 ERANGE error code, whatever seems more appropriate.
3098
3099 @param file: File descriptor returned by open().
3100 @param ctrl: pointer to struct v4l2_control.
3101
3102 @return On success 0 is returned, else error code.
3103 @return EINVAL: The struct v4l2_control id is invalid.
3104 @return ERANGE: The struct v4l2_control value is out of bounds.
3105 @return EBUSY: The control is temporarily not changeable, possibly because
3106 another applications took over control of the device function this control
3107 belongs to.
3108*/
3109static int tavarua_vidioc_s_ctrl(struct file *file, void *priv,
3110 struct v4l2_control *ctrl)
3111{
3112 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3113 int retval = 0;
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303114 int size = 0, cnt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003115 unsigned char value;
3116 unsigned char xfr_buf[XFR_REG_NUM];
3117 unsigned char tx_data[XFR_REG_NUM];
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05303118 unsigned char dis_buf[XFR_REG_NUM];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003119
3120 switch (ctrl->id) {
3121 case V4L2_CID_AUDIO_VOLUME:
3122 break;
3123 case V4L2_CID_AUDIO_MUTE:
3124 value = (radio->registers[IOCTRL] & ~IOC_HRD_MUTE) |
3125 (ctrl->value & 0x03);
3126 retval = tavarua_write_register(radio, IOCTRL, value);
3127 break;
3128 case V4L2_CID_PRIVATE_TAVARUA_SRCHMODE:
3129 value = (radio->registers[SRCHCTRL] & ~SRCH_MODE) |
3130 ctrl->value;
3131 radio->registers[SRCHCTRL] = value;
3132 break;
3133 case V4L2_CID_PRIVATE_TAVARUA_SCANDWELL:
3134 value = (radio->registers[SRCHCTRL] & ~SCAN_DWELL) |
3135 (ctrl->value << 4);
3136 radio->registers[SRCHCTRL] = value;
3137 break;
3138 /* start/stop search */
3139 case V4L2_CID_PRIVATE_TAVARUA_SRCHON:
3140 FMDBG("starting search\n");
3141 tavarua_search(radio, ctrl->value, SRCH_DIR_UP);
3142 break;
3143 case V4L2_CID_PRIVATE_TAVARUA_STATE:
3144 /* check if already on */
3145 radio->handle_irq = 1;
3146 if (((ctrl->value == FM_RECV) || (ctrl->value == FM_TRANS))
3147 && !(radio->registers[RDCTRL] &
3148 ctrl->value)) {
3149 FMDBG("clearing flags\n");
3150 init_completion(&radio->sync_xfr_start);
3151 init_completion(&radio->sync_req_done);
3152 radio->xfr_in_progress = 0;
3153 radio->xfr_bytes_left = 0;
3154 FMDBG("turning on ..\n");
3155 retval = tavarua_start(radio, ctrl->value);
3156 if (retval >= 0) {
Anantha Krishnanc72725a2011-09-06 09:28:22 +05303157 /* Enabling 'SoftMute' & 'SignalBlending' */
3158 value = (radio->registers[IOCTRL] |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003159 IOC_SFT_MUTE | IOC_SIG_BLND);
Anantha Krishnanc72725a2011-09-06 09:28:22 +05303160 retval = tavarua_write_register(radio,
3161 IOCTRL, value);
3162 if (retval < 0)
3163 FMDBG("SMute and SBlending"
3164 "not enabled\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003165 }
3166 }
3167 /* check if off */
3168 else if ((ctrl->value == FM_OFF) && radio->registers[RDCTRL]) {
Anantha Krishnan93eb1762012-06-04 13:41:07 +05303169 radio->spur_table_size = 0;
Anantha Krishnan1475c932012-02-16 21:54:03 +05303170 FMDBG("%s: turning off...\n", __func__);
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05303171 tavarua_write_register(radio, RDCTRL, ctrl->value);
3172 /* flush the event and work queues */
3173 kfifo_reset(&radio->data_buf[TAVARUA_BUF_EVENTS]);
3174 flush_workqueue(radio->wqueue);
3175 /*
3176 * queue the READY event from the host side
3177 * in case of FM off
3178 */
Ayaz Ahmad0fa19842012-03-14 22:54:53 +05303179 tavarua_q_event(radio, TAVARUA_EVT_RADIO_DISABLED);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003180
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05303181 FMDBG("%s, Disable All Interrupts\n", __func__);
3182 /* disable irq */
3183 dis_buf[STATUS_REG1] = 0x00;
3184 dis_buf[STATUS_REG2] = 0x00;
3185 dis_buf[STATUS_REG3] = TRANSFER;
3186 retval = sync_write_xfr(radio, INT_CTRL, dis_buf);
3187 if (retval < 0) {
3188 pr_err("%s: failed to disable"
3189 "Interrupts\n", __func__);
3190 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003191 }
3192 }
3193 break;
Anantha Krishnanc72725a2011-09-06 09:28:22 +05303194 case V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH:
3195 FMDBG("Setting audio path ...\n");
3196 if (ctrl->value == FM_DIGITAL_PATH) {
3197 FMDBG("Digital audio path enabled ...\n");
3198 retval = tavarua_set_audio_path(
3199 TAVARUA_AUDIO_OUT_DIGITAL_ON,
3200 TAVARUA_AUDIO_OUT_ANALOG_OFF);
3201 if (retval < 0) {
3202 FMDERR("Error in tavarua_set_audio_path"
3203 " %d\n", retval);
3204 }
3205 } else if (ctrl->value == FM_ANALOG_PATH) {
3206 FMDBG("Analog audio path enabled ...\n");
3207 retval = tavarua_set_audio_path(
Venkateshwarlu Domakondab49c2cb2012-04-17 17:44:50 +05303208 TAVARUA_AUDIO_OUT_DIGITAL_OFF,
3209 TAVARUA_AUDIO_OUT_ANALOG_ON);
Anantha Krishnanc72725a2011-09-06 09:28:22 +05303210 if (retval < 0) {
3211 FMDERR("Error in tavarua_set_audio_path"
3212 " %d\n", retval);
3213 }
3214 }
3215 break;
Anantha Krishnan40bcd052011-12-05 15:28:29 +05303216 case V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM:
3217 radio->enable_optimized_srch_alg = ctrl->value;
3218 FMDBG("V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM : %d",
3219 radio->enable_optimized_srch_alg);
3220 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003221 case V4L2_CID_PRIVATE_TAVARUA_REGION:
3222 retval = tavarua_set_region(radio, ctrl->value);
3223 break;
3224 case V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH:
3225 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
3226 if (retval < 0) {
3227 FMDERR("V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
3228 FMDERR("sync_read_xfr [retval=%d]\n", retval);
3229 break;
3230 }
3231 /* RMSSI Threshold is a signed 8 bit value */
3232 xfr_buf[0] = (unsigned char)ctrl->value;
3233 xfr_buf[1] = (unsigned char)ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003234 retval = sync_write_xfr(radio, RX_CONFIG, xfr_buf);
3235 if (retval < 0) {
3236 FMDERR("V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
3237 FMDERR("sync_write_xfr [retval=%d]\n", retval);
3238 break;
3239 }
3240 break;
3241 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY:
3242 radio->srch_params.srch_pty = ctrl->value;
3243 break;
3244 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PI:
3245 radio->srch_params.srch_pi = ctrl->value;
3246 break;
3247 case V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT:
3248 radio->srch_params.preset_num = ctrl->value;
3249 break;
3250 case V4L2_CID_PRIVATE_TAVARUA_EMPHASIS:
3251 radio->region_params.emphasis = ctrl->value;
3252 break;
3253 case V4L2_CID_PRIVATE_TAVARUA_RDS_STD:
3254 radio->region_params.rds_std = ctrl->value;
3255 break;
3256 case V4L2_CID_PRIVATE_TAVARUA_SPACING:
3257 radio->region_params.spacing = ctrl->value;
3258 break;
3259 case V4L2_CID_PRIVATE_TAVARUA_RDSON:
3260 retval = 0;
3261 if (ctrl->value != (radio->registers[RDSCTRL] & RDS_ON)) {
3262 value = radio->registers[RDSCTRL] | ctrl->value;
3263 retval = tavarua_write_register(radio, RDSCTRL, value);
3264 }
3265 break;
3266 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK:
3267 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
3268 if (retval < 0)
3269 break;
3270 xfr_buf[8] = (ctrl->value & 0xFF000000) >> 24;
3271 xfr_buf[9] = (ctrl->value & 0x00FF0000) >> 16;
3272 xfr_buf[10] = (ctrl->value & 0x0000FF00) >> 8;
3273 xfr_buf[11] = (ctrl->value & 0x000000FF);
3274 retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
3275 break;
3276 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC:
Anantha Krishnane46ef6f2011-06-29 23:56:03 +05303277 value = radio->registers[ADVCTRL] | ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003278 retval = tavarua_write_register(radio, ADVCTRL, value);
3279 break;
Anantha Krishnane46ef6f2011-06-29 23:56:03 +05303280 case V4L2_CID_PRIVATE_TAVARUA_AF_JUMP:
3281 retval = tavarua_read_registers(radio, ADVCTRL, 1);
3282 SET_REG_FIELD(radio->registers[ADVCTRL], ctrl->value,
3283 RDSAF_OFFSET, RDSAF_MASK);
3284 msleep(TAVARUA_DELAY*5);
3285 retval = tavarua_write_register(radio,
3286 ADVCTRL, radio->registers[ADVCTRL]);
3287 msleep(TAVARUA_DELAY*5);
3288 break;
Anantha Krishnan3b44cd42011-07-06 12:36:15 +05303289 case V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA:
3290 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
3291 if (retval < 0) {
3292 FMDERR("V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA]\n");
3293 FMDERR("sync_read_xfr [retval=%d]\n", retval);
3294 break;
3295 }
3296 xfr_buf[4] = (unsigned char)ctrl->value;
3297 retval = sync_write_xfr(radio, RX_CONFIG, xfr_buf);
3298 if (retval < 0) {
3299 FMDERR("V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA]\n");
3300 FMDERR("sync_write_xfr [retval=%d]\n", retval);
3301 break;
3302 }
3303 break;
Anantha Krishnanf2258602011-06-30 01:32:09 +05303304 case V4L2_CID_PRIVATE_TAVARUA_HLSI:
3305 retval = tavarua_read_registers(radio, RDCTRL, 1);
3306 SET_REG_FIELD(radio->registers[RDCTRL], ctrl->value,
3307 RDCTRL_HLSI_OFFSET, RDCTRL_HLSI_MASK);
3308 retval = tavarua_write_register(radio, RDCTRL,
3309 radio->registers[RDCTRL]);
3310 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003311 case V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF:
3312 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
3313 if (retval < 0)
3314 break;
3315 xfr_buf[1] = ctrl->value;
3316 retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
3317 break;
3318 case V4L2_CID_PRIVATE_TAVARUA_PSALL:
3319 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
3320 value = ctrl->value & RDS_CONFIG_PSALL;
3321 if (retval < 0)
3322 break;
3323 xfr_buf[12] &= ~RDS_CONFIG_PSALL;
3324 xfr_buf[12] |= value;
3325 retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
3326 break;
3327 case V4L2_CID_PRIVATE_TAVARUA_LP_MODE:
3328 retval = 0;
3329 if (ctrl->value == radio->lp_mode)
3330 break;
3331 if (ctrl->value) {
3332 FMDBG("going into low power mode\n");
3333 retval = tavarua_disable_interrupts(radio);
3334 } else {
3335 FMDBG("going into normal power mode\n");
3336 tavarua_setup_interrupts(radio,
3337 (radio->registers[RDCTRL] & 0x03));
3338 }
3339 break;
3340 case V4L2_CID_PRIVATE_TAVARUA_ANTENNA:
3341 SET_REG_FIELD(radio->registers[IOCTRL], ctrl->value,
3342 IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
3343 break;
Anantha Krishnana3dcce42012-01-05 19:27:57 +05303344 case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303345 size = 0x04;
3346 /* Poking the value of ON Channel Threshold value */
3347 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
3348 xfr_buf[1] = ON_CHANNEL_TH_MSB;
3349 xfr_buf[2] = ON_CHANNEL_TH_LSB;
3350 /* Data to be poked into the register */
3351 xfr_buf[3] = (ctrl->value & 0xFF000000) >> 24;
3352 xfr_buf[4] = (ctrl->value & 0x00FF0000) >> 16;
3353 xfr_buf[5] = (ctrl->value & 0x0000FF00) >> 8;
3354 xfr_buf[6] = (ctrl->value & 0x000000FF);
3355
3356 for (cnt = 3; cnt < 7; cnt++) {
3357 FMDBG("On-channel data to be poked is : %d",
3358 (int)xfr_buf[cnt]);
3359 }
3360
3361 retval = tavarua_write_registers(radio, XFRCTRL,
3362 xfr_buf, size+3);
3363 if (retval < 0) {
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303364 pr_err("%s: Failed to write\n", __func__);
3365 return retval;
3366 }
3367 /*Wait for the XFR interrupt */
3368 msleep(TAVARUA_DELAY*10);
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303369 break;
Anantha Krishnana3dcce42012-01-05 19:27:57 +05303370 case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303371 size = 0x04;
3372 /* Poking the value of OFF Channel Threshold value */
3373 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
3374 xfr_buf[1] = OFF_CHANNEL_TH_MSB;
3375 xfr_buf[2] = OFF_CHANNEL_TH_LSB;
3376 /* Data to be poked into the register */
3377 xfr_buf[3] = (ctrl->value & 0xFF000000) >> 24;
3378 xfr_buf[4] = (ctrl->value & 0x00FF0000) >> 16;
3379 xfr_buf[5] = (ctrl->value & 0x0000FF00) >> 8;
3380 xfr_buf[6] = (ctrl->value & 0x000000FF);
3381
3382 for (cnt = 3; cnt < 7; cnt++) {
3383 FMDBG("Off-channel data to be poked is : %d",
3384 (int)xfr_buf[cnt]);
3385 }
3386
3387 retval = tavarua_write_registers(radio, XFRCTRL,
3388 xfr_buf, size+3);
3389 if (retval < 0) {
3390 pr_err("%s: Failed to write\n", __func__);
3391 return retval;
3392 }
3393 /*Wait for the XFR interrupt */
3394 msleep(TAVARUA_DELAY*10);
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303395 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003396 /* TX Controls */
3397
3398 case V4L2_CID_RDS_TX_PTY: {
3399 radio->pty = ctrl->value;
3400 } break;
3401 case V4L2_CID_RDS_TX_PI: {
3402 radio->pi = ctrl->value;
3403 } break;
3404 case V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_PS_NAME: {
3405 FMDBG("In STOP_RDS_TX_PS_NAME\n");
3406 /*Pass a sample PS string */
3407 memset(tx_data, '0', XFR_REG_NUM);
3408 FMDBG("Writing PS header\n");
3409 retval = sync_write_xfr(radio, RDS_PS_0, tx_data);
3410 FMDBG("retval of PS Header write: %d", retval);
3411
3412 } break;
3413
3414 case V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_RT: {
3415 memset(tx_data, '0', XFR_REG_NUM);
3416 FMDBG("Writing RT header\n");
3417 retval = sync_write_xfr(radio, RDS_RT_0, tx_data);
3418 FMDBG("retval of Header write: %d", retval);
3419
3420 } break;
3421
3422 case V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT: {
3423 radio->ps_repeatcount = ctrl->value;
3424 } break;
3425 case V4L2_CID_TUNE_POWER_LEVEL: {
3426 unsigned char tx_power_lvl_config[FM_TX_PWR_LVL_MAX+1] = {
3427 0x85, /* tx_da<5:3> = 0 lpf<2:0> = 5*/
3428 0x95, /* tx_da<5:3> = 2 lpf<2:0> = 5*/
3429 0x9D, /* tx_da<5:3> = 3 lpf<2:0> = 5*/
3430 0xA5, /* tx_da<5:3> = 4 lpf<2:0> = 5*/
3431 0xAD, /* tx_da<5:3> = 5 lpf<2:0> = 5*/
3432 0xB5, /* tx_da<5:3> = 6 lpf<2:0> = 5*/
3433 0xBD, /* tx_da<5:3> = 7 lpf<2:0> = 5*/
3434 0xBF /* tx_da<5:3> = 7 lpf<2:0> = 7*/
3435 };
3436 if (ctrl->value > FM_TX_PWR_LVL_MAX)
3437 ctrl->value = FM_TX_PWR_LVL_MAX;
3438 if (ctrl->value < FM_TX_PWR_LVL_0)
3439 ctrl->value = FM_TX_PWR_LVL_0;
3440 retval = sync_read_xfr(radio, PHY_TXGAIN, xfr_buf);
3441 FMDBG("return for PHY_TXGAIN is %d", retval);
3442 if (retval < 0) {
3443 FMDBG("read failed");
3444 break;
3445 }
3446 xfr_buf[2] = tx_power_lvl_config[ctrl->value];
3447 retval = sync_write_xfr(radio, PHY_TXGAIN, xfr_buf);
3448 FMDBG("return for write PHY_TXGAIN is %d", retval);
3449 if (retval < 0)
3450 FMDBG("write failed");
3451 } break;
Anantha Krishnan71d6fa62011-12-13 19:30:51 +05303452 /*These IOCTL's are place holders to keep the
Srinivasa Rao Uppala4e38bfc2011-09-15 16:00:31 +05303453 driver compatible with change in frame works for IRIS */
Anantha Krishnan71d6fa62011-12-13 19:30:51 +05303454 case V4L2_CID_PRIVATE_SOFT_MUTE:
3455 case V4L2_CID_PRIVATE_RIVA_ACCS_ADDR:
3456 case V4L2_CID_PRIVATE_RIVA_ACCS_LEN:
3457 case V4L2_CID_PRIVATE_RIVA_PEEK:
3458 case V4L2_CID_PRIVATE_RIVA_POKE:
3459 case V4L2_CID_PRIVATE_SSBI_ACCS_ADDR:
3460 case V4L2_CID_PRIVATE_SSBI_PEEK:
3461 case V4L2_CID_PRIVATE_SSBI_POKE:
3462 case V4L2_CID_PRIVATE_TX_TONE:
3463 case V4L2_CID_PRIVATE_RDS_GRP_COUNTERS:
3464 case V4L2_CID_PRIVATE_SET_NOTCH_FILTER:
3465 case V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION:
Anantha Krishnana3dcce42012-01-05 19:27:57 +05303466 case V4L2_CID_PRIVATE_SINR_THRESHOLD:
3467 case V4L2_CID_PRIVATE_SINR_SAMPLES:
Anantha Krishnan93eb1762012-06-04 13:41:07 +05303468 case V4L2_CID_PRIVATE_SPUR_SELECTION:
Srinivasa Rao Uppala4e38bfc2011-09-15 16:00:31 +05303469 retval = 0;
3470 break;
Anantha Krishnan93eb1762012-06-04 13:41:07 +05303471 case V4L2_CID_PRIVATE_SPUR_FREQ:
3472 radio->spur_data.freq[radio->spur_table_size] =
3473 ctrl->value;
3474 break;
3475 case V4L2_CID_PRIVATE_SPUR_FREQ_RMSSI:
3476 radio->spur_data.rmssi[radio->spur_table_size++] =
3477 ctrl->value;
3478 break;
3479 case V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE:
3480 retval = update_spur_table(radio);
3481 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003482 default:
3483 retval = -EINVAL;
3484 }
3485 if (retval < 0)
3486 printk(KERN_WARNING DRIVER_NAME
3487 ": set control failed with %d, id : %d\n", retval, ctrl->id);
3488
3489 return retval;
3490}
3491
3492/*=============================================================================
3493FUNCTION: tavarua_vidioc_g_tuner
3494=============================================================================*/
3495/**
3496 This function is called to get tuner attributes.
3497
3498 NOTE:
3499 To query the attributes of a tuner, applications initialize the index field
3500 and zero out the reserved array of a struct v4l2_tuner and call the
3501 VIDIOC_G_TUNER ioctl with a pointer to this structure. Drivers fill the rest
3502 of the structure or return an EINVAL error code when the index is out of
3503 bounds. To enumerate all tuners applications shall begin at index zero,
3504 incrementing by one until the driver returns EINVAL.
3505
3506 @param file: File descriptor returned by open().
3507 @param tuner: pointer to struct v4l2_tuner.
3508
3509 @return On success 0 is returned, else error code.
3510 @return EINVAL: The struct v4l2_tuner index is out of bounds.
3511*/
3512static int tavarua_vidioc_g_tuner(struct file *file, void *priv,
3513 struct v4l2_tuner *tuner)
3514{
3515 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3516 int retval;
3517 unsigned char xfr_buf[XFR_REG_NUM];
3518 char rmssi = 0;
3519 unsigned char size = 0;
3520
3521 if (tuner->index > 0)
3522 return -EINVAL;
3523
3524 /* read status rssi */
3525 retval = tavarua_read_registers(radio, IOCTRL, 1);
3526 if (retval < 0)
3527 return retval;
3528 /* read RMSSI */
3529 size = 0x1;
3530 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
3531 xfr_buf[1] = RMSSI_PEEK_MSB;
3532 xfr_buf[2] = RMSSI_PEEK_LSB;
3533 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
3534 msleep(TAVARUA_DELAY*10);
3535 retval = tavarua_read_registers(radio, XFRDAT0, 3);
3536 rmssi = radio->registers[XFRDAT0];
3537 tuner->signal = rmssi;
3538
3539 strcpy(tuner->name, "FM");
3540 tuner->type = V4L2_TUNER_RADIO;
3541 tuner->rangelow = radio->region_params.band_low;
3542 tuner->rangehigh = radio->region_params.band_high;
3543 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
3544 tuner->capability = V4L2_TUNER_CAP_LOW;
3545
3546 /* Stereo indicator == Stereo (instead of Mono) */
3547 if (radio->registers[IOCTRL] & IOC_MON_STR)
3548 tuner->audmode = V4L2_TUNER_MODE_STEREO;
3549 else
3550 tuner->audmode = V4L2_TUNER_MODE_MONO;
3551
3552 /* automatic frequency control: -1: freq to low, 1 freq to high */
3553 tuner->afc = 0;
3554
3555 return 0;
3556}
3557
3558/*=============================================================================
3559FUNCTION: tavarua_vidioc_s_tuner
3560=============================================================================*/
3561/**
3562 This function is called to set tuner attributes. Used to set mono/stereo mode.
3563
3564 NOTE:
3565 Tuners have two writable properties, the audio mode and the radio frequency.
3566 To change the audio mode, applications initialize the index, audmode and
3567 reserved fields and call the VIDIOC_S_TUNER ioctl. This will not change the
3568 current tuner, which is determined by the current video input. Drivers may
3569 choose a different audio mode if the requested mode is invalid or unsupported.
3570 Since this is a write-only ioctl, it does not return the actually selected
3571 audio mode.
3572
3573 To change the radio frequency the VIDIOC_S_FREQUENCY ioctl is available.
3574
3575 @param file: File descriptor returned by open().
3576 @param tuner: pointer to struct v4l2_tuner.
3577
3578 @return On success 0 is returned, else error code.
3579 @return -EINVAL: The struct v4l2_tuner index is out of bounds.
3580*/
3581static int tavarua_vidioc_s_tuner(struct file *file, void *priv,
3582 struct v4l2_tuner *tuner)
3583{
3584 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3585 int retval;
3586 int audmode;
3587 if (tuner->index > 0)
3588 return -EINVAL;
3589
3590 FMDBG("%s: set low to %d\n", __func__, tuner->rangelow);
3591 radio->region_params.band_low = tuner->rangelow;
3592 radio->region_params.band_high = tuner->rangehigh;
3593 if (tuner->audmode == V4L2_TUNER_MODE_MONO)
3594 /* Mono */
3595 audmode = (radio->registers[IOCTRL] | IOC_MON_STR);
3596 else
3597 /* Stereo */
3598 audmode = (radio->registers[IOCTRL] & ~IOC_MON_STR);
3599 retval = tavarua_write_register(radio, IOCTRL, audmode);
3600 if (retval < 0)
3601 printk(KERN_WARNING DRIVER_NAME
3602 ": set tuner failed with %d\n", retval);
3603
3604 return retval;
3605}
3606
3607/*=============================================================================
3608FUNCTION: tavarua_vidioc_g_frequency
3609=============================================================================*/
3610/**
3611 This function is called to get tuner or modulator radio frequency.
3612
3613 NOTE:
3614 To get the current tuner or modulator radio frequency applications set the
3615 tuner field of a struct v4l2_frequency to the respective tuner or modulator
3616 number (only input devices have tuners, only output devices have modulators),
3617 zero out the reserved array and call the VIDIOC_G_FREQUENCY ioctl with a
3618 pointer to this structure. The driver stores the current frequency in the
3619 frequency field.
3620
3621 @param file: File descriptor returned by open().
3622 @param freq: pointer to struct v4l2_frequency. This will be set to the
3623 resultant
3624 frequency in 62.5 khz on success.
3625
3626 @return On success 0 is returned, else error code.
3627 @return EINVAL: The tuner index is out of bounds or the value in the type
3628 field is wrong.
3629*/
3630static int tavarua_vidioc_g_frequency(struct file *file, void *priv,
3631 struct v4l2_frequency *freq)
3632{
3633 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3634 freq->type = V4L2_TUNER_RADIO;
3635 return tavarua_get_freq(radio, freq);
3636
3637}
3638
3639/*=============================================================================
3640FUNCTION: tavarua_vidioc_s_frequency
3641=============================================================================*/
3642/**
3643 This function is called to set tuner or modulator radio frequency.
3644
3645 NOTE:
3646 To change the current tuner or modulator radio frequency applications
3647 initialize the tuner, type and frequency fields, and the reserved array of
3648 a struct v4l2_frequency and call the VIDIOC_S_FREQUENCY ioctl with a pointer
3649 to this structure. When the requested frequency is not possible the driver
3650 assumes the closest possible value. However VIDIOC_S_FREQUENCY is a
3651 write-only ioctl, it does not return the actual new frequency.
3652
3653 @param file: File descriptor returned by open().
3654 @param freq: pointer to struct v4l2_frequency.
3655
3656 @return On success 0 is returned, else error code.
3657 @return EINVAL: The tuner index is out of bounds or the value in the type
3658 field is wrong.
3659*/
3660static int tavarua_vidioc_s_frequency(struct file *file, void *priv,
3661 struct v4l2_frequency *freq)
3662{
3663 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3664 int retval = -1;
3665 struct v4l2_frequency getFreq;
3666
3667 FMDBG("%s\n", __func__);
3668
3669 if (freq->type != V4L2_TUNER_RADIO)
3670 return -EINVAL;
3671
3672 FMDBG("Calling tavarua_set_freq\n");
3673
3674 INIT_COMPLETION(radio->sync_req_done);
3675 retval = tavarua_set_freq(radio, freq->frequency);
3676 if (retval < 0) {
3677 printk(KERN_WARNING DRIVER_NAME
3678 ": set frequency failed with %d\n", retval);
3679 } else {
3680 /* Wait for interrupt i.e. complete
3681 (&radio->sync_req_done); call */
3682 if (!wait_for_completion_timeout(&radio->sync_req_done,
3683 msecs_to_jiffies(wait_timeout))) {
3684 FMDERR("Timeout: No Tune response");
3685 retval = tavarua_get_freq(radio, &getFreq);
3686 radio->tune_req = 0;
3687 if (retval > 0) {
3688 if (getFreq.frequency == freq->frequency) {
3689 /** This is success, queut the event*/
3690 tavarua_q_event(radio,
3691 TAVARUA_EVT_TUNE_SUCC);
3692 return 0;
3693 } else {
3694 return -EIO;
3695 }
3696 }
3697 }
3698 }
3699 radio->tune_req = 0;
3700 return retval;
3701}
3702
3703/*=============================================================================
3704FUNCTION: tavarua_vidioc_dqbuf
3705=============================================================================*/
3706/**
3707 This function is called to exchange a buffer with the driver.
3708 This is main buffer function, in essense its equivalent to a blocking
3709 read call.
3710
3711 Applications call the VIDIOC_DQBUF ioctl to dequeue a filled (capturing) or
3712 displayed (output) buffer from the driver's outgoing queue. They just set
3713 the type and memory fields of a struct v4l2_buffer as above, when VIDIOC_DQBUF
3714 is called with a pointer to this structure the driver fills the remaining
3715 fields or returns an error code.
3716
3717 NOTE:
3718 By default VIDIOC_DQBUF blocks when no buffer is in the outgoing queue.
3719 When the O_NONBLOCK flag was given to the open() function, VIDIOC_DQBUF
3720 returns immediately with an EAGAIN error code when no buffer is available.
3721
3722 @param file: File descriptor returned by open().
3723 @param buffer: pointer to struct v4l2_buffer.
3724
3725 @return On success 0 is returned, else error code.
3726 @return EAGAIN: Non-blocking I/O has been selected using O_NONBLOCK and no
3727 buffer was in the outgoing queue.
3728 @return EINVAL: The buffer type is not supported, or the index is out of
3729 bounds, or no buffers have been allocated yet, or the userptr or length are
3730 invalid.
3731 @return ENOMEM: Not enough physical or virtual memory was available to enqueue
3732 a user pointer buffer.
3733 @return EIO: VIDIOC_DQBUF failed due to an internal error. Can also indicate
3734 temporary problems like signal loss. Note the driver might dequeue an (empty)
3735 buffer despite returning an error, or even stop capturing.
3736*/
3737static int tavarua_vidioc_dqbuf(struct file *file, void *priv,
3738 struct v4l2_buffer *buffer)
3739{
3740
3741 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
Venkateshwarlu Domakonda00c882d2012-04-12 10:50:53 +05303742 enum tavarua_buf_t buf_type = -1;
3743 unsigned char buf_fifo[STD_BUF_SIZE] = {0};
3744 struct kfifo *data_fifo = NULL;
3745 unsigned char *buf = NULL;
3746 unsigned int len = 0, retval = -1;
3747
3748 if ((radio == NULL) || (buffer == NULL)) {
3749 FMDERR("radio/buffer is NULL\n");
3750 return -ENXIO;
3751 }
3752 buf_type = buffer->index;
3753 buf = (unsigned char *)buffer->m.userptr;
3754 len = buffer->length;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003755 FMDBG("%s: requesting buffer %d\n", __func__, buf_type);
Venkateshwarlu Domakonda00c882d2012-04-12 10:50:53 +05303756
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003757 if ((buf_type < TAVARUA_BUF_MAX) && (buf_type >= 0)) {
3758 data_fifo = &radio->data_buf[buf_type];
3759 if (buf_type == TAVARUA_BUF_EVENTS) {
3760 if (wait_event_interruptible(radio->event_queue,
3761 kfifo_len(data_fifo)) < 0) {
3762 return -EINTR;
3763 }
3764 }
3765 } else {
3766 FMDERR("invalid buffer type\n");
3767 return -EINVAL;
3768 }
Venkateshwarlu Domakonda00c882d2012-04-12 10:50:53 +05303769 if (len <= STD_BUF_SIZE) {
3770 buffer->bytesused = kfifo_out_locked(data_fifo, &buf_fifo[0],
3771 len, &radio->buf_lock[buf_type]);
3772 } else {
3773 FMDERR("kfifo_out_locked can not use len more than 128\n");
3774 return -EINVAL;
3775 }
3776 retval = copy_to_user(buf, &buf_fifo[0], buffer->bytesused);
3777 if (retval > 0) {
3778 FMDERR("Failed to copy %d bytes of data\n", retval);
3779 return -EAGAIN;
3780 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003781
Venkateshwarlu Domakonda00c882d2012-04-12 10:50:53 +05303782 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003783}
3784
3785/*=============================================================================
3786FUNCTION: tavarua_vidioc_g_fmt_type_private
3787=============================================================================*/
3788/**
3789 This function is here to make the v4l2 framework happy.
3790 We cannot use private buffers without it.
3791
3792 @param file: File descriptor returned by open().
3793 @param f: pointer to struct v4l2_format.
3794
3795 @return On success 0 is returned, else error code.
3796 @return EINVAL: The tuner index is out of bounds or the value in the type
3797 field is wrong.
3798*/
3799static int tavarua_vidioc_g_fmt_type_private(struct file *file, void *priv,
3800 struct v4l2_format *f)
3801{
3802 return 0;
3803
3804}
3805
3806/*=============================================================================
3807FUNCTION: tavarua_vidioc_s_hw_freq_seek
3808=============================================================================*/
3809/**
3810 This function is called to perform a hardware frequency seek.
3811
3812 Start a hardware frequency seek from the current frequency. To do this
3813 applications initialize the tuner, type, seek_upward and wrap_around fields,
3814 and zero out the reserved array of a struct v4l2_hw_freq_seek and call the
3815 VIDIOC_S_HW_FREQ_SEEK ioctl with a pointer to this structure.
3816
3817 This ioctl is supported if the V4L2_CAP_HW_FREQ_SEEK capability is set.
3818
3819 @param file: File descriptor returned by open().
3820 @param seek: pointer to struct v4l2_hw_freq_seek.
3821
3822 @return On success 0 is returned, else error code.
3823 @return EINVAL: The tuner index is out of bounds or the value in the type
3824 field is wrong.
3825 @return EAGAIN: The ioctl timed-out. Try again.
3826*/
3827static int tavarua_vidioc_s_hw_freq_seek(struct file *file, void *priv,
3828 struct v4l2_hw_freq_seek *seek)
3829{
3830 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
Anantha Krishnan6be56602012-04-30 04:08:01 -07003831 int dir;
3832 if (seek->seek_upward)
3833 dir = SRCH_DIR_UP;
3834 else
3835 dir = SRCH_DIR_DOWN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003836 FMDBG("starting search\n");
Anantha Krishnan6be56602012-04-30 04:08:01 -07003837 return tavarua_search(radio, CTRL_ON, dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003838}
3839
3840/*
3841 * tavarua_viddev_tamples - video device interface
3842 */
3843static const struct v4l2_ioctl_ops tavarua_ioctl_ops = {
3844 .vidioc_querycap = tavarua_vidioc_querycap,
3845 .vidioc_queryctrl = tavarua_vidioc_queryctrl,
3846 .vidioc_g_ctrl = tavarua_vidioc_g_ctrl,
3847 .vidioc_s_ctrl = tavarua_vidioc_s_ctrl,
3848 .vidioc_g_tuner = tavarua_vidioc_g_tuner,
3849 .vidioc_s_tuner = tavarua_vidioc_s_tuner,
3850 .vidioc_g_frequency = tavarua_vidioc_g_frequency,
3851 .vidioc_s_frequency = tavarua_vidioc_s_frequency,
3852 .vidioc_s_hw_freq_seek = tavarua_vidioc_s_hw_freq_seek,
3853 .vidioc_dqbuf = tavarua_vidioc_dqbuf,
3854 .vidioc_g_fmt_type_private = tavarua_vidioc_g_fmt_type_private,
3855 .vidioc_s_ext_ctrls = tavarua_vidioc_s_ext_ctrls,
3856};
3857
3858static struct video_device tavarua_viddev_template = {
3859 .fops = &tavarua_fops,
3860 .ioctl_ops = &tavarua_ioctl_ops,
3861 .name = DRIVER_NAME,
3862 .release = video_device_release,
3863};
3864
3865/*==============================================================
3866FUNCTION: FmQSocCom_EnableInterrupts
3867==============================================================*/
3868/**
3869 This function enable interrupts.
3870
3871 @param radio: structure pointer passed by client.
3872 @param state: FM radio state (receiver/transmitter/off/reset).
3873
3874 @return => 0 if successful.
3875 @return < 0 if failure.
3876*/
3877static int tavarua_setup_interrupts(struct tavarua_device *radio,
3878 enum radio_state_t state)
3879{
3880 int retval;
3881 unsigned char int_ctrl[XFR_REG_NUM];
3882
3883 if (!radio->lp_mode)
3884 return 0;
3885
3886 int_ctrl[STATUS_REG1] = READY | TUNE | SEARCH | SCANNEXT |
3887 SIGNAL | INTF | SYNC | AUDIO;
3888 if (state == FM_RECV)
3889 int_ctrl[STATUS_REG2] = RDSDAT | RDSRT | RDSPS | RDSAF;
3890 else
3891 int_ctrl[STATUS_REG2] = TXRDSDAT | TXRDSDONE;
3892
3893 int_ctrl[STATUS_REG3] = TRANSFER | ERROR;
3894
3895 /* use xfr for interrupt setup */
3896 if (radio->chipID == MARIMBA_2_1 || radio->chipID == BAHAMA_1_0
3897 || radio->chipID == BAHAMA_2_0) {
3898 FMDBG("Setting interrupts\n");
3899 retval = sync_write_xfr(radio, INT_CTRL, int_ctrl);
3900 /* use register write to setup interrupts */
3901 } else {
3902 retval = tavarua_write_register(radio,
3903 STATUS_REG1, int_ctrl[STATUS_REG1]);
3904 if (retval < 0)
3905 return retval;
3906
3907 retval = tavarua_write_register(radio,
3908 STATUS_REG2, int_ctrl[STATUS_REG2]);
3909 if (retval < 0)
3910 return retval;
3911
3912 retval = tavarua_write_register(radio,
3913 STATUS_REG3, int_ctrl[STATUS_REG3]);
3914 if (retval < 0)
3915 return retval;
3916 }
3917
3918 radio->lp_mode = 0;
3919 /* tavarua_handle_interrupts force reads all the interrupt status
3920 * registers and it is not valid for MBA 2.1
3921 */
3922 if ((radio->chipID != MARIMBA_2_1) && (radio->chipID != BAHAMA_1_0)
3923 && (radio->chipID != BAHAMA_2_0))
3924 tavarua_handle_interrupts(radio);
3925
3926 return retval;
3927
3928}
3929
3930/*==============================================================
3931FUNCTION: tavarua_disable_interrupts
3932==============================================================*/
3933/**
3934 This function disables interrupts.
3935
3936 @param radio: structure pointer passed by client.
3937
3938 @return => 0 if successful.
3939 @return < 0 if failure.
3940*/
3941static int tavarua_disable_interrupts(struct tavarua_device *radio)
3942{
3943 unsigned char lpm_buf[XFR_REG_NUM];
3944 int retval;
3945 if (radio->lp_mode)
3946 return 0;
3947 FMDBG("%s\n", __func__);
3948 /* In Low power mode, disable all the interrupts that are not being
3949 waited by the Application */
3950 lpm_buf[STATUS_REG1] = TUNE | SEARCH | SCANNEXT;
3951 lpm_buf[STATUS_REG2] = 0x00;
3952 lpm_buf[STATUS_REG3] = TRANSFER;
3953 /* use xfr for interrupt setup */
3954 wait_timeout = 100;
3955 if (radio->chipID == MARIMBA_2_1 || radio->chipID == BAHAMA_1_0
3956 || radio->chipID == BAHAMA_2_0)
3957 retval = sync_write_xfr(radio, INT_CTRL, lpm_buf);
3958 /* use register write to setup interrupts */
3959 else
3960 retval = tavarua_write_registers(radio, STATUS_REG1, lpm_buf,
3961 ARRAY_SIZE(lpm_buf));
3962
3963 /*INT_CTL writes may fail with TIME_OUT as all the
3964 interrupts have been disabled
3965 */
3966 if (retval > -1 || retval == -ETIME) {
3967 radio->lp_mode = 1;
3968 /*Consider timeout as a valid case here*/
3969 retval = 0;
3970 }
3971 wait_timeout = WAIT_TIMEOUT;
3972 return retval;
3973
3974}
3975
3976/*==============================================================
3977FUNCTION: tavarua_start
3978==============================================================*/
3979/**
3980 Starts/enables the device (FM radio).
3981
3982 @param radio: structure pointer passed by client.
3983 @param state: FM radio state (receiver/transmitter/off/reset).
3984
3985 @return On success 0 is returned, else error code.
3986*/
3987static int tavarua_start(struct tavarua_device *radio,
3988 enum radio_state_t state)
3989{
3990
3991 int retval;
3992 FMDBG("%s <%d>\n", __func__, state);
3993 /* set geographic region */
3994 radio->region_params.region = TAVARUA_REGION_US;
3995
3996 /* set radio mode */
3997 retval = tavarua_write_register(radio, RDCTRL, state);
3998 if (retval < 0)
3999 return retval;
4000 /* wait for radio to init */
4001 msleep(RADIO_INIT_TIME);
4002 /* enable interrupts */
4003 tavarua_setup_interrupts(radio, state);
4004 /* default region is US */
4005 radio->region_params.band_low = US_LOW_BAND * FREQ_MUL;
4006 radio->region_params.band_high = US_HIGH_BAND * FREQ_MUL;
4007
4008 return 0;
4009}
4010
4011/*==============================================================
4012FUNCTION: tavarua_suspend
4013==============================================================*/
4014/**
4015 Save state and stop all devices in system.
4016
4017 @param pdev: platform device to be suspended.
4018 @param state: Power state to put each device in.
4019
4020 @return On success 0 is returned, else error code.
4021*/
4022static int tavarua_suspend(struct platform_device *pdev, pm_message_t state)
4023{
4024 struct tavarua_device *radio = platform_get_drvdata(pdev);
4025 int retval;
4026 int users = 0;
4027 printk(KERN_INFO DRIVER_NAME "%s: radio suspend\n\n", __func__);
4028 if (radio) {
Anantha Krishnana2f98082011-10-04 20:02:11 +05304029 users = atomic_read(&radio->users);
Anantha Krishnan71bea3c2011-11-15 07:36:49 +05304030 if (!users) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004031 retval = tavarua_disable_interrupts(radio);
4032 if (retval < 0) {
4033 printk(KERN_INFO DRIVER_NAME
4034 "tavarua_suspend error %d\n", retval);
4035 return -EIO;
4036 }
4037 }
4038 }
4039 return 0;
4040}
4041
4042/*==============================================================
4043FUNCTION: tavarua_resume
4044==============================================================*/
4045/**
4046 Restore state of each device in system.
4047
4048 @param pdev: platform device to be resumed.
4049
4050 @return On success 0 is returned, else error code.
4051*/
4052static int tavarua_resume(struct platform_device *pdev)
4053{
4054
4055 struct tavarua_device *radio = platform_get_drvdata(pdev);
4056 int retval;
4057 int users = 0;
4058 printk(KERN_INFO DRIVER_NAME "%s: radio resume\n\n", __func__);
4059 if (radio) {
Anantha Krishnana2f98082011-10-04 20:02:11 +05304060 users = atomic_read(&radio->users);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004061
Anantha Krishnan71bea3c2011-11-15 07:36:49 +05304062 if (!users) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004063 retval = tavarua_setup_interrupts(radio,
4064 (radio->registers[RDCTRL] & 0x03));
4065 if (retval < 0) {
4066 printk(KERN_INFO DRIVER_NAME "Error in \
4067 tavarua_resume %d\n", retval);
4068 return -EIO;
4069 }
4070 }
4071 }
4072 return 0;
4073}
4074
4075/*==============================================================
4076FUNCTION: tavarua_set_audio_path
4077==============================================================*/
4078/**
4079 This function will configure the audio path to and from the
4080 FM core.
4081
4082 This interface is expected to be called from the multimedia
4083 driver's thread. This interface should only be called when
4084 the FM hardware is enabled. If the FM hardware is not
4085 currently enabled, this interface will return an error.
4086
4087 @param digital_on: Digital audio from the FM core should be enabled/disbled.
4088 @param analog_on: Analog audio from the FM core should be enabled/disbled.
4089
4090 @return On success 0 is returned, else error code.
4091*/
4092int tavarua_set_audio_path(int digital_on, int analog_on)
4093{
4094 struct tavarua_device *radio = private_data;
4095 int rx_on = radio->registers[RDCTRL] & FM_RECV;
Venkateshwarlu Domakondab49c2cb2012-04-17 17:44:50 +05304096 int retval = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004097 if (!radio)
4098 return -ENOMEM;
4099 /* RX */
4100 FMDBG("%s: digital: %d analog: %d\n", __func__, digital_on, analog_on);
Venkateshwarlu Domakondab49c2cb2012-04-17 17:44:50 +05304101 if ((radio->pdata != NULL) && (radio->pdata->config_i2s_gpio != NULL)) {
4102 if (digital_on) {
4103 retval = radio->pdata->config_i2s_gpio(FM_I2S_ON);
4104 if (retval) {
4105 pr_err("%s: config_i2s_gpio failed\n",
4106 __func__);
4107 }
4108 } else {
4109 retval = radio->pdata->config_i2s_gpio(FM_I2S_OFF);
4110 if (retval) {
4111 pr_err("%s: config_i2s_gpio failed\n",
4112 __func__);
4113 }
4114 }
4115 }
4116
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004117 SET_REG_FIELD(radio->registers[AUDIOCTRL],
4118 ((rx_on && analog_on) ? 1 : 0),
4119 AUDIORX_ANALOG_OFFSET,
4120 AUDIORX_ANALOG_MASK);
4121 SET_REG_FIELD(radio->registers[AUDIOCTRL],
4122 ((rx_on && digital_on) ? 1 : 0),
4123 AUDIORX_DIGITAL_OFFSET,
4124 AUDIORX_DIGITAL_MASK);
4125 SET_REG_FIELD(radio->registers[AUDIOCTRL],
4126 (rx_on ? 0 : 1),
4127 AUDIOTX_OFFSET,
4128 AUDIOTX_MASK);
4129 /*
4130
4131 I2S Master/Slave configuration:
4132 Setting the FM SoC as I2S Master/Slave
4133 'false' - FM SoC is I2S Slave
4134 'true' - FM SoC is I2S Master
4135
4136 We get this infomation from the respective target's board file :
4137 MSM7x30 - FM SoC is I2S Slave
4138 MSM8x60 - FM SoC is I2S Slave
4139 MSM7x27A - FM SoC is I2S Master
4140 */
4141
4142 if (!radio->pdata->is_fm_soc_i2s_master) {
4143 FMDBG("FM SoC is I2S Slave\n");
4144 SET_REG_FIELD(radio->registers[AUDIOCTRL],
4145 (0),
4146 I2SCTRL_OFFSET,
4147 I2SCTRL_MASK);
4148 } else {
4149 FMDBG("FM SoC is I2S Master\n");
4150 SET_REG_FIELD(radio->registers[AUDIOCTRL],
4151 (1),
4152 I2SCTRL_OFFSET,
4153 I2SCTRL_MASK);
4154 }
4155 FMDBG("%s: %x\n", __func__, radio->registers[AUDIOCTRL]);
4156 return tavarua_write_register(radio, AUDIOCTRL,
4157 radio->registers[AUDIOCTRL]);
4158
4159}
4160
4161/*==============================================================
4162FUNCTION: tavarua_probe
4163==============================================================*/
4164/**
4165 Once called this functions initiates, allocates resources and registers video
4166 tuner device with the v4l2 framework.
4167
4168 NOTE:
4169 probe() should verify that the specified device hardware
4170 actually exists; sometimes platform setup code can't be sure. The probing
4171 can use device resources, including clocks, and device platform_data.
4172
4173 @param pdev: platform device to be probed.
4174
4175 @return On success 0 is returned, else error code.
4176 -ENOMEM in low memory cases
4177*/
4178static int __init tavarua_probe(struct platform_device *pdev)
4179{
4180
4181 struct marimba_fm_platform_data *tavarua_pdata;
4182 struct tavarua_device *radio;
4183 int retval;
4184 int i;
4185 FMDBG("%s: probe called\n", __func__);
4186 /* private data allocation */
4187 radio = kzalloc(sizeof(struct tavarua_device), GFP_KERNEL);
4188 if (!radio) {
4189 retval = -ENOMEM;
4190 goto err_initial;
4191 }
4192
4193 radio->marimba = platform_get_drvdata(pdev);
4194 tavarua_pdata = pdev->dev.platform_data;
4195 radio->pdata = tavarua_pdata;
4196 radio->dev = &pdev->dev;
4197 platform_set_drvdata(pdev, radio);
4198
4199 /* video device allocation */
4200 radio->videodev = video_device_alloc();
4201 if (!radio->videodev)
4202 goto err_radio;
4203
4204 /* initial configuration */
4205 memcpy(radio->videodev, &tavarua_viddev_template,
4206 sizeof(tavarua_viddev_template));
4207
4208 /*allocate internal buffers for decoded rds and event buffer*/
4209 for (i = 0; i < TAVARUA_BUF_MAX; i++) {
4210 int kfifo_alloc_rc=0;
4211 spin_lock_init(&radio->buf_lock[i]);
4212
4213 if (i == TAVARUA_BUF_RAW_RDS)
4214 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
4215 rds_buf*3, GFP_KERNEL);
Srinivasa Rao Uppalad09f24a2012-01-13 19:10:39 +05304216 else if (i == TAVARUA_BUF_RT_RDS)
4217 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
4218 STD_BUF_SIZE * 2, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004219 else
4220 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
4221 STD_BUF_SIZE, GFP_KERNEL);
4222
4223 if (kfifo_alloc_rc!=0) {
4224 printk(KERN_ERR "%s: failed allocating buffers %d\n",
4225 __func__, kfifo_alloc_rc);
4226 goto err_bufs;
4227 }
4228 }
Anantha Krishnana2f98082011-10-04 20:02:11 +05304229 /* initializing the device count */
4230 atomic_set(&radio->users, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004231 radio->xfr_in_progress = 0;
4232 radio->xfr_bytes_left = 0;
4233 for (i = 0; i < TAVARUA_XFR_MAX; i++)
4234 radio->pending_xfrs[i] = 0;
4235
4236 /* init transmit data */
4237 radio->tx_mode = TAVARUA_TX_RT;
4238 /* Init RT and PS Tx datas*/
4239 radio->pty = 0;
4240 radio->pi = 0;
4241 radio->ps_repeatcount = 0;
4242 /* init search params */
4243 radio->srch_params.srch_pty = 0;
4244 radio->srch_params.srch_pi = 0;
4245 radio->srch_params.preset_num = 0;
4246 radio->srch_params.get_list = 0;
4247 /* radio initializes to low power mode */
4248 radio->lp_mode = 1;
4249 radio->handle_irq = 1;
4250 /* init lock */
4251 mutex_init(&radio->lock);
4252 /* init completion flags */
4253 init_completion(&radio->sync_xfr_start);
4254 init_completion(&radio->sync_req_done);
4255 radio->tune_req = 0;
4256 /* initialize wait queue for event read */
4257 init_waitqueue_head(&radio->event_queue);
4258 /* initialize wait queue for raw rds read */
4259 init_waitqueue_head(&radio->read_queue);
4260
4261 video_set_drvdata(radio->videodev, radio);
4262 /*Start the worker thread for event handling and register read_int_stat
4263 as worker function*/
Taniya Das9ac855f2012-02-09 18:05:21 +05304264 radio->wqueue = create_singlethread_workqueue("kfmradio");
4265 if (!radio->wqueue)
4266 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004267
4268 /* register video device */
4269 if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
4270 printk(KERN_WARNING DRIVER_NAME
4271 ": Could not register video device\n");
4272 goto err_all;
4273 }
4274 private_data = radio;
4275 return 0;
4276
4277err_all:
4278 video_device_release(radio->videodev);
4279err_bufs:
4280 for (; i > -1; i--)
4281 kfifo_free(&radio->data_buf[i]);
4282err_radio:
4283 kfree(radio);
4284err_initial:
4285 return retval;
4286}
4287
4288/*==============================================================
4289FUNCTION: tavarua_remove
4290==============================================================*/
4291/**
4292 Removes the device.
4293
4294 @param pdev: platform device to be removed.
4295
4296 @return On success 0 is returned, else error code.
4297*/
4298static int __devexit tavarua_remove(struct platform_device *pdev)
4299{
4300 int i;
4301 struct tavarua_device *radio = platform_get_drvdata(pdev);
4302
4303 /* disable irq */
4304 tavarua_disable_irq(radio);
4305
Taniya Das9ac855f2012-02-09 18:05:21 +05304306 destroy_workqueue(radio->wqueue);
4307
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004308 video_unregister_device(radio->videodev);
4309
4310 /* free internal buffers */
4311 for (i = 0; i < TAVARUA_BUF_MAX; i++)
4312 kfifo_free(&radio->data_buf[i]);
4313
4314 /* free state struct */
4315 kfree(radio);
4316
4317 platform_set_drvdata(pdev, NULL);
4318
4319 return 0;
4320}
4321
4322/*
4323 Platform drivers follow the standard driver model convention, where
4324 discovery/enumeration is handled outside the drivers, and drivers
4325 provide probe() and remove() methods. They support power management
4326 and shutdown notifications using the standard conventions.
4327*/
4328static struct platform_driver tavarua_driver = {
4329 .driver = {
4330 .owner = THIS_MODULE,
4331 .name = "marimba_fm",
4332 },
4333 .remove = __devexit_p(tavarua_remove),
4334 .suspend = tavarua_suspend,
4335 .resume = tavarua_resume,
4336}; /* platform device we're adding */
4337
4338
4339/*************************************************************************
4340 * Module Interface
4341 ************************************************************************/
4342
4343/*==============================================================
4344FUNCTION: radio_module_init
4345==============================================================*/
4346/**
4347 Module entry - add a platform-level device.
4348
4349 @return Returns zero if the driver registered and bound to a device, else
4350 returns a negative error code when the driver not registered.
4351*/
4352static int __init radio_module_init(void)
4353{
4354 printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n");
4355 return platform_driver_probe(&tavarua_driver, tavarua_probe);
4356}
4357
4358/*==============================================================
4359FUNCTION: radio_module_exit
4360==============================================================*/
4361/**
4362 Module exit - removes a platform-level device.
4363
4364 NOTE:
4365 Note that this function will also release all memory- and port-based
4366 resources owned by the device (dev->resource).
4367
4368 @return none.
4369*/
4370static void __exit radio_module_exit(void)
4371{
4372 platform_driver_unregister(&tavarua_driver);
4373}
4374
4375MODULE_LICENSE("GPL v2");
4376MODULE_AUTHOR(DRIVER_AUTHOR);
4377MODULE_DESCRIPTION(DRIVER_DESC);
4378MODULE_VERSION(DRIVER_VERSION);
4379
4380module_init(radio_module_init);
4381module_exit(radio_module_exit);
4382