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