blob: 741c3a1459b7d90cc19ba9f539e53f4f64626b6d [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 Krishnana2f98082011-10-04 20:02:11 +05302160 atomic_inc(&radio->users);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002161 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
Taniya Das9ac855f2012-02-09 18:05:21 +05302162 flush_workqueue(radio->wqueue);
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302163 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002164}
2165
2166/*
2167 * tavarua_fops - file operations interface
2168 */
2169static const struct v4l2_file_operations tavarua_fops = {
2170 .owner = THIS_MODULE,
2171 .read = tavarua_fops_read,
2172 .write = tavarua_fops_write,
2173 .ioctl = video_ioctl2,
2174 .open = tavarua_fops_open,
2175 .release = tavarua_fops_release,
2176};
2177
2178/*************************************************************************
2179 * Video4Linux Interface
2180 *************************************************************************/
2181
2182/*
2183 * tavarua_v4l2_queryctrl - query control
2184 */
2185static struct v4l2_queryctrl tavarua_v4l2_queryctrl[] = {
2186 {
2187 .id = V4L2_CID_AUDIO_VOLUME,
2188 .type = V4L2_CTRL_TYPE_INTEGER,
2189 .name = "Volume",
2190 .minimum = 0,
2191 .maximum = 15,
2192 .step = 1,
2193 .default_value = 15,
2194 },
2195 {
2196 .id = V4L2_CID_AUDIO_BALANCE,
2197 .flags = V4L2_CTRL_FLAG_DISABLED,
2198 },
2199 {
2200 .id = V4L2_CID_AUDIO_BASS,
2201 .flags = V4L2_CTRL_FLAG_DISABLED,
2202 },
2203 {
2204 .id = V4L2_CID_AUDIO_TREBLE,
2205 .flags = V4L2_CTRL_FLAG_DISABLED,
2206 },
2207 {
2208 .id = V4L2_CID_AUDIO_MUTE,
2209 .type = V4L2_CTRL_TYPE_BOOLEAN,
2210 .name = "Mute",
2211 .minimum = 0,
2212 .maximum = 1,
2213 .step = 1,
2214 .default_value = 1,
2215 },
2216 {
2217 .id = V4L2_CID_AUDIO_LOUDNESS,
2218 .flags = V4L2_CTRL_FLAG_DISABLED,
2219 },
2220 {
2221 .id = V4L2_CID_PRIVATE_TAVARUA_SRCHMODE,
2222 .type = V4L2_CTRL_TYPE_INTEGER,
2223 .name = "Search mode",
2224 .minimum = 0,
2225 .maximum = 7,
2226 .step = 1,
2227 .default_value = 0,
2228 },
2229 {
2230 .id = V4L2_CID_PRIVATE_TAVARUA_SCANDWELL,
2231 .type = V4L2_CTRL_TYPE_INTEGER,
2232 .name = "Search dwell time",
2233 .minimum = 0,
2234 .maximum = 7,
2235 .step = 1,
2236 .default_value = 0,
2237 },
2238 {
2239 .id = V4L2_CID_PRIVATE_TAVARUA_SRCHON,
2240 .type = V4L2_CTRL_TYPE_BOOLEAN,
2241 .name = "Search on/off",
2242 .minimum = 0,
2243 .maximum = 1,
2244 .step = 1,
2245 .default_value = 1,
2246
2247 },
2248 {
2249 .id = V4L2_CID_PRIVATE_TAVARUA_STATE,
2250 .type = V4L2_CTRL_TYPE_INTEGER,
2251 .name = "radio 0ff/rx/tx/reset",
2252 .minimum = 0,
2253 .maximum = 3,
2254 .step = 1,
2255 .default_value = 1,
2256
2257 },
2258 {
2259 .id = V4L2_CID_PRIVATE_TAVARUA_REGION,
2260 .type = V4L2_CTRL_TYPE_INTEGER,
2261 .name = "radio standard",
2262 .minimum = 0,
2263 .maximum = 2,
2264 .step = 1,
2265 .default_value = 0,
2266 },
2267 {
2268 .id = V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH,
2269 .type = V4L2_CTRL_TYPE_INTEGER,
2270 .name = "Signal Threshold",
2271 .minimum = 0x80,
2272 .maximum = 0x7F,
2273 .step = 1,
2274 .default_value = 0,
2275 },
2276 {
2277 .id = V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY,
2278 .type = V4L2_CTRL_TYPE_INTEGER,
2279 .name = "Search PTY",
2280 .minimum = 0,
2281 .maximum = 31,
2282 .default_value = 0,
2283 },
2284 {
2285 .id = V4L2_CID_PRIVATE_TAVARUA_SRCH_PI,
2286 .type = V4L2_CTRL_TYPE_INTEGER,
2287 .name = "Search PI",
2288 .minimum = 0,
2289 .maximum = 0xFF,
2290 .default_value = 0,
2291 },
2292 {
2293 .id = V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT,
2294 .type = V4L2_CTRL_TYPE_INTEGER,
2295 .name = "Preset num",
2296 .minimum = 0,
2297 .maximum = 12,
2298 .default_value = 0,
2299 },
2300 {
2301 .id = V4L2_CID_PRIVATE_TAVARUA_EMPHASIS,
2302 .type = V4L2_CTRL_TYPE_BOOLEAN,
2303 .name = "Emphasis",
2304 .minimum = 0,
2305 .maximum = 1,
2306 .default_value = 0,
2307 },
2308 {
2309 .id = V4L2_CID_PRIVATE_TAVARUA_RDS_STD,
2310 .type = V4L2_CTRL_TYPE_BOOLEAN,
2311 .name = "RDS standard",
2312 .minimum = 0,
2313 .maximum = 1,
2314 .default_value = 0,
2315 },
2316 {
2317 .id = V4L2_CID_PRIVATE_TAVARUA_SPACING,
2318 .type = V4L2_CTRL_TYPE_INTEGER,
2319 .name = "Channel spacing",
2320 .minimum = 0,
2321 .maximum = 2,
2322 .default_value = 0,
2323 },
2324 {
2325 .id = V4L2_CID_PRIVATE_TAVARUA_RDSON,
2326 .type = V4L2_CTRL_TYPE_BOOLEAN,
2327 .name = "RDS on/off",
2328 .minimum = 0,
2329 .maximum = 1,
2330 .default_value = 0,
2331 },
2332 {
2333 .id = V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK,
2334 .type = V4L2_CTRL_TYPE_INTEGER,
2335 .name = "RDS group mask",
2336 .minimum = 0,
2337 .maximum = 0xFFFFFFFF,
2338 .default_value = 0,
2339 },
2340 {
2341 .id = V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC,
2342 .type = V4L2_CTRL_TYPE_INTEGER,
2343 .name = "RDS processing",
2344 .minimum = 0,
2345 .maximum = 0xFF,
2346 .default_value = 0,
2347 },
2348 {
2349 .id = V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF,
2350 .type = V4L2_CTRL_TYPE_INTEGER,
2351 .name = "RDS data groups to buffer",
2352 .minimum = 1,
2353 .maximum = 21,
2354 .default_value = 0,
2355 },
2356 {
2357 .id = V4L2_CID_PRIVATE_TAVARUA_PSALL,
2358 .type = V4L2_CTRL_TYPE_BOOLEAN,
2359 .name = "pass all ps strings",
2360 .minimum = 0,
2361 .maximum = 1,
2362 .default_value = 0,
2363 },
2364 {
2365 .id = V4L2_CID_PRIVATE_TAVARUA_LP_MODE,
2366 .type = V4L2_CTRL_TYPE_BOOLEAN,
2367 .name = "Low power mode",
2368 .minimum = 0,
2369 .maximum = 1,
2370 .default_value = 0,
2371 },
2372 {
2373 .id = V4L2_CID_PRIVATE_TAVARUA_ANTENNA,
2374 .type = V4L2_CTRL_TYPE_BOOLEAN,
2375 .name = "headset/internal",
2376 .minimum = 0,
2377 .maximum = 1,
2378 .default_value = 0,
2379 },
2380 /* Private controls for FM TX*/
2381 {
2382 .id = V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT,
2383 .type = V4L2_CTRL_TYPE_INTEGER,
2384 .name = "Set PS REPEATCOUNT",
2385 .minimum = 0,
2386 .maximum = 15,
2387 },
2388 {
2389 .id = V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_PS_NAME,
2390 .type = V4L2_CTRL_TYPE_BOOLEAN,
2391 .name = "Stop PS NAME",
2392 .minimum = 0,
2393 .maximum = 1,
2394 },
2395 {
2396 .id = V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_RT,
2397 .type = V4L2_CTRL_TYPE_BOOLEAN,
2398 .name = "Stop RT",
2399 .minimum = 0,
2400 .maximum = 1,
2401 },
Anantha Krishnan71d6fa62011-12-13 19:30:51 +05302402 { .id = V4L2_CID_PRIVATE_SET_NOTCH_FILTER,
Srinivasa Rao Uppala4e38bfc2011-09-15 16:00:31 +05302403 .type = V4L2_CTRL_TYPE_INTEGER,
2404 .name = "Notch filter",
2405 .minimum = 0,
2406 .maximum = 2,
2407 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002408
2409};
2410
2411/*=============================================================================
2412FUNCTION: tavarua_vidioc_querycap
2413=============================================================================*/
2414/**
2415 This function is called to query device capabilities.
2416
2417 NOTE:
2418 All V4L2 devices support the VIDIOC_QUERYCAP ioctl. It is used to identify
2419 kernel devices compatible with this specification and to obtain information
2420 about driver and hardware capabilities. The ioctl takes a pointer to a struct
2421 v4l2_capability which is filled by the driver. When the driver is not
2422 compatible with this specification the ioctl returns an EINVAL error code.
2423
2424 @param file: File descriptor returned by open().
2425 @param capability: pointer to struct v4l2_capability.
2426
2427 @return On success 0 is returned, else error code.
2428 @return EINVAL: The device is not compatible with this specification.
2429*/
2430static int tavarua_vidioc_querycap(struct file *file, void *priv,
2431 struct v4l2_capability *capability)
2432{
2433 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2434
2435 strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
2436 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
2437 sprintf(capability->bus_info, "I2C");
2438 capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
2439
2440 capability->version = radio->chipID;
2441
2442 return 0;
2443}
2444
2445/*=============================================================================
2446FUNCTION: tavarua_vidioc_queryctrl
2447=============================================================================*/
2448/**
2449 This function is called to query the device and driver for supported video
2450 controls (enumerate control items).
2451
2452 NOTE:
2453 To query the attributes of a control, the applications set the id field of
2454 a struct v4l2_queryctrl and call the VIDIOC_QUERYCTRL ioctl with a pointer
2455 to this structure. The driver fills the rest of the structure or returns an
2456 EINVAL error code when the id is invalid.
2457
2458 @param file: File descriptor returned by open().
2459 @param qc: pointer to struct v4l2_queryctrl.
2460
2461 @return On success 0 is returned, else error code.
2462 @return EINVAL: The struct v4l2_queryctrl id is invalid.
2463*/
2464static int tavarua_vidioc_queryctrl(struct file *file, void *priv,
2465 struct v4l2_queryctrl *qc)
2466{
2467 unsigned char i;
2468 int retval = -EINVAL;
2469
2470 for (i = 0; i < ARRAY_SIZE(tavarua_v4l2_queryctrl); i++) {
2471 if (qc->id && qc->id == tavarua_v4l2_queryctrl[i].id) {
2472 memcpy(qc, &(tavarua_v4l2_queryctrl[i]), sizeof(*qc));
2473 retval = 0;
2474 break;
2475 }
2476 }
2477 if (retval < 0)
2478 printk(KERN_WARNING DRIVER_NAME
2479 ": query conv4ltrol failed with %d\n", retval);
2480
2481 return retval;
2482}
2483static int peek_MPX_DCC(struct tavarua_device *radio)
2484{
2485 int retval = 0;
2486 unsigned char xfr_buf[XFR_REG_NUM];
2487 int MPX_DCC[] = { 0 };
2488 int DCC = 0;
2489 int ct = 0;
2490 unsigned char size = 0;
2491
2492 /*
2493 Poking the MPX_DCC_BYPASS register to freeze the
2494 value of MPX_DCC from changing while we access it
2495 */
2496
2497 /*Poking the MPX_DCC_BYPASS register : 0x88C0 */
2498 size = 0x01;
2499 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
2500 xfr_buf[1] = MPX_DCC_BYPASS_POKE_MSB;
2501 xfr_buf[2] = MPX_DCC_BYPASS_POKE_LSB;
2502 xfr_buf[3] = 0x01;
2503
2504 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 4);
2505 if (retval < 0) {
2506 FMDBG("Failed to write\n");
2507 return retval;
2508 }
2509 /*Wait for the XFR interrupt */
2510 msleep(TAVARUA_DELAY*15);
2511
2512 for (ct = 0; ct < 5; ct++)
2513 xfr_buf[ct] = 0;
2514
2515 /* Peeking Regs 0x88C2-0x88C4 */
2516 size = 0x03;
2517 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
2518 xfr_buf[1] = MPX_DCC_PEEK_MSB_REG1;
2519 xfr_buf[2] = MPX_DCC_PEEK_LSB_REG1;
2520 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
2521 if (retval < 0) {
2522 FMDBG("Failed to write\n");
2523 return retval;
2524 }
2525 /*Wait for the XFR interrupt */
2526 msleep(TAVARUA_DELAY*10);
2527 retval = tavarua_read_registers(radio, XFRDAT0, 3);
2528 if (retval < 0) {
2529 printk(KERN_INFO "INT_DET: Read failure\n");
2530 return retval;
2531 }
2532 MPX_DCC[0] = (int)radio->registers[XFRDAT0];
2533 MPX_DCC[1] = (int)radio->registers[XFRDAT1];
2534 MPX_DCC[2] = (int)radio->registers[XFRDAT2];
2535
2536 /*
2537 Form the final MPX_DCC parameter
2538 MPX_DCC[0] will form the LSB part
2539 MPX_DCC[1] will be the middle part and 4 bits of
2540 MPX_DCC[2] will be the MSB par of the 20-bit signed MPX_DCC
2541 */
2542
2543 DCC = ((int)MPX_DCC[2] << 16) | ((int)MPX_DCC[1] << 8) |
2544 ((int)MPX_DCC[0]);
2545
2546 /*
2547 if bit-19 is '1',set remaining bits to '1' & make it -tive
2548 */
2549 if (DCC & 0x00080000) {
2550 FMDBG(KERN_INFO "bit-19 is '1'\n");
2551 DCC |= 0xFFF00000;
2552 }
2553
2554 /*
2555 Poking the MPX_DCC_BYPASS register to be back to normal
2556 */
2557
2558 /*Poking the MPX_DCC_BYPASS register : 0x88C0 */
2559 size = 0x01;
2560 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
2561 xfr_buf[1] = MPX_DCC_BYPASS_POKE_MSB;
2562 xfr_buf[2] = MPX_DCC_BYPASS_POKE_LSB;
2563 xfr_buf[3] = 0x00;
2564
2565 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 4);
2566 if (retval < 0) {
2567 FMDBG("Failed to write\n");
2568 return retval;
2569 }
2570 /*Wait for the XFR interrupt */
2571 msleep(TAVARUA_DELAY*10);
2572
2573 return DCC;
2574}
2575/*=============================================================================
2576FUNCTION: tavarua_vidioc_g_ctrl
2577=============================================================================*/
2578/**
2579 This function is called to get the value of a control.
2580
2581 NOTE:
2582 To get the current value of a control, applications initialize the id field
2583 of a struct v4l2_control and call the VIDIOC_G_CTRL ioctl with a pointer to
2584 this structure.
2585
2586 When the id is invalid drivers return an EINVAL error code. When the value is
2587 out of bounds drivers can choose to take the closest valid value or return an
2588 ERANGE error code, whatever seems more appropriate.
2589
2590 @param file: File descriptor returned by open().
2591 @param ctrl: pointer to struct v4l2_control.
2592
2593 @return On success 0 is returned, else error code.
2594 @return EINVAL: The struct v4l2_control id is invalid.
2595 @return ERANGE: The struct v4l2_control value is out of bounds.
2596 @return EBUSY: The control is temporarily not changeable, possibly because
2597 another applications took over control of the device function this control
2598 belongs to.
2599*/
2600static int tavarua_vidioc_g_ctrl(struct file *file, void *priv,
2601 struct v4l2_control *ctrl)
2602{
2603 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2604 int retval = 0;
Anantha Krishnana3dcce42012-01-05 19:27:57 +05302605 int cnt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002606 unsigned char xfr_buf[XFR_REG_NUM];
2607 signed char cRmssiThreshold;
2608 signed char ioc;
2609 unsigned char size = 0;
2610
2611 switch (ctrl->id) {
2612 case V4L2_CID_AUDIO_VOLUME:
2613 break;
2614 case V4L2_CID_AUDIO_MUTE:
2615 ctrl->value = radio->registers[IOCTRL] & 0x03 ;
2616 break;
2617 case V4L2_CID_PRIVATE_TAVARUA_SRCHMODE:
2618 ctrl->value = radio->registers[SRCHCTRL] & SRCH_MODE;
2619 break;
2620 case V4L2_CID_PRIVATE_TAVARUA_SCANDWELL:
2621 ctrl->value = (radio->registers[SRCHCTRL] & SCAN_DWELL) >> 4;
2622 break;
2623 case V4L2_CID_PRIVATE_TAVARUA_SRCHON:
2624 ctrl->value = (radio->registers[SRCHCTRL] & SRCH_ON) >> 7 ;
2625 break;
2626 case V4L2_CID_PRIVATE_TAVARUA_STATE:
2627 ctrl->value = (radio->registers[RDCTRL] & 0x03);
2628 break;
2629 case V4L2_CID_PRIVATE_TAVARUA_IOVERC:
2630 retval = tavarua_read_registers(radio, IOVERC, 1);
2631 if (retval < 0)
2632 return retval;
2633 ioc = radio->registers[IOVERC];
2634 ctrl->value = ioc;
2635 break;
2636 case V4L2_CID_PRIVATE_TAVARUA_INTDET:
2637 size = 0x1;
2638 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
2639 xfr_buf[1] = INTDET_PEEK_MSB;
2640 xfr_buf[2] = INTDET_PEEK_LSB;
2641 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
2642 if (retval < 0) {
2643 FMDBG("Failed to write\n");
2644 return retval;
2645 }
2646 FMDBG("INT_DET:Sync write success\n");
2647 /*Wait for the XFR interrupt */
2648 msleep(TAVARUA_DELAY*10);
2649 /* Read the XFRDAT0 register populated by FM SoC */
2650 retval = tavarua_read_registers(radio, XFRDAT0, 3);
2651 if (retval < 0) {
2652 FMDBG("INT_DET: Read failure\n");
2653 return retval;
2654 }
2655 ctrl->value = radio->registers[XFRDAT0];
2656 break;
2657 case V4L2_CID_PRIVATE_TAVARUA_MPX_DCC:
2658 ctrl->value = peek_MPX_DCC(radio);
2659 break;
2660 case V4L2_CID_PRIVATE_TAVARUA_REGION:
2661 ctrl->value = radio->region_params.region;
2662 break;
2663 case V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH:
2664 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
2665 if (retval < 0) {
2666 FMDBG("[G IOCTL=V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
2667 FMDBG("sync_read_xfr error: [retval=%d]\n", retval);
2668 break;
2669 }
2670 /* Since RMSSI Threshold is signed value */
2671 cRmssiThreshold = (signed char)xfr_buf[0];
2672 ctrl->value = cRmssiThreshold;
2673 FMDBG("cRmssiThreshold: %d\n", cRmssiThreshold);
2674 break;
2675 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY:
2676 ctrl->value = radio->srch_params.srch_pty;
2677 break;
2678 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PI:
2679 ctrl->value = radio->srch_params.srch_pi;
2680 break;
2681 case V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT:
2682 ctrl->value = radio->srch_params.preset_num;
2683 break;
2684 case V4L2_CID_PRIVATE_TAVARUA_EMPHASIS:
2685 ctrl->value = radio->region_params.emphasis;
2686 break;
2687 case V4L2_CID_PRIVATE_TAVARUA_RDS_STD:
2688 ctrl->value = radio->region_params.rds_std;
2689 break;
2690 case V4L2_CID_PRIVATE_TAVARUA_SPACING:
2691 ctrl->value = radio->region_params.spacing;
2692 break;
2693 case V4L2_CID_PRIVATE_TAVARUA_RDSON:
2694 ctrl->value = radio->registers[RDSCTRL] & RDS_ON;
2695 break;
2696 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK:
2697 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
2698 if (retval > -1)
2699 ctrl->value = (xfr_buf[8] << 24) |
2700 (xfr_buf[9] << 16) |
2701 (xfr_buf[10] << 8) |
2702 xfr_buf[11];
2703 break;
2704 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC:
2705 retval = tavarua_read_registers(radio, ADVCTRL, 1);
2706 if (retval > -1)
2707 ctrl->value = radio->registers[ADVCTRL];
Anantha Krishnane46ef6f2011-06-29 23:56:03 +05302708 msleep(TAVARUA_DELAY*5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002709 break;
Anantha Krishnan3be3b262011-09-05 17:22:48 +05302710 case V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA:
2711 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
2712 if (retval < 0) {
2713 FMDERR("V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA]\n");
2714 FMDERR("sync_read_xfr [retval=%d]\n", retval);
2715 break;
2716 }
2717 ctrl->value = (unsigned char)xfr_buf[4];
2718 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002719 case V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF:
2720 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
2721 if (retval > -1)
2722 ctrl->value = xfr_buf[1];
2723 break;
2724 case V4L2_CID_PRIVATE_TAVARUA_PSALL:
2725 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
2726 if (retval > -1)
2727 ctrl->value = xfr_buf[12] & RDS_CONFIG_PSALL;
2728 break;
2729 case V4L2_CID_PRIVATE_TAVARUA_LP_MODE:
2730 ctrl->value = radio->lp_mode;
2731 break;
2732 case V4L2_CID_PRIVATE_TAVARUA_ANTENNA:
2733 ctrl->value = GET_REG_FIELD(radio->registers[IOCTRL],
2734 IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
2735 break;
Anantha Krishnana3dcce42012-01-05 19:27:57 +05302736 case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
2737 size = 0x04;
2738 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
2739 xfr_buf[1] = ON_CHANNEL_TH_MSB;
2740 xfr_buf[2] = ON_CHANNEL_TH_LSB;
2741 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
2742 if (retval < 0) {
2743 pr_err("%s: Failed to write\n", __func__);
2744 return retval;
2745 }
2746 /*Wait for the XFR interrupt */
2747 msleep(TAVARUA_DELAY*10);
2748 retval = tavarua_read_registers(radio, XFRDAT0, 4);
2749 if (retval < 0) {
2750 pr_err("%s: On Ch. DET: Read failure\n", __func__);
2751 return retval;
2752 }
2753 for (cnt = 0; cnt < 4; cnt++)
2754 FMDBG("On-Channel data set is : 0x%x\t",
2755 (int)radio->registers[XFRDAT0+cnt]);
2756
2757 ctrl->value = LSH_DATA(radio->registers[XFRDAT0], 24) |
2758 LSH_DATA(radio->registers[XFRDAT0+1], 16) |
2759 LSH_DATA(radio->registers[XFRDAT0+2], 8) |
2760 (radio->registers[XFRDAT0+3]);
2761 FMDBG("The On Channel Threshold value is : 0x%x", ctrl->value);
2762 break;
2763 case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
2764 size = 0x04;
2765 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
2766 xfr_buf[1] = OFF_CHANNEL_TH_MSB;
2767 xfr_buf[2] = OFF_CHANNEL_TH_LSB;
2768 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
2769 if (retval < 0) {
2770 pr_err("%s: Failed to write\n", __func__);
2771 return retval;
2772 }
2773 /*Wait for the XFR interrupt */
2774 msleep(TAVARUA_DELAY*10);
2775 retval = tavarua_read_registers(radio, XFRDAT0, 4);
2776 if (retval < 0) {
2777 pr_err("%s: Off Ch. DET: Read failure\n", __func__);
2778 return retval;
2779 }
2780 for (cnt = 0; cnt < 4; cnt++)
2781 FMDBG("Off-channel data set is : 0x%x\t",
2782 (int)radio->registers[XFRDAT0+cnt]);
2783
2784 ctrl->value = LSH_DATA(radio->registers[XFRDAT0], 24) |
2785 LSH_DATA(radio->registers[XFRDAT0+1], 16) |
2786 LSH_DATA(radio->registers[XFRDAT0+2], 8) |
2787 (radio->registers[XFRDAT0+3]);
2788 FMDBG("The Off Channel Threshold value is : 0x%x", ctrl->value);
2789 break;
2790 /*
2791 * These IOCTL's are place holders to keep the
2792 * driver compatible with change in frame works for IRIS
2793 */
2794 case V4L2_CID_PRIVATE_SINR_THRESHOLD:
2795 case V4L2_CID_PRIVATE_SINR_SAMPLES:
2796 case V4L2_CID_PRIVATE_IRIS_GET_SINR:
2797 retval = 0;
2798 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002799 default:
2800 retval = -EINVAL;
2801 }
2802 if (retval < 0)
2803 printk(KERN_WARNING DRIVER_NAME
2804 ": get control failed with %d, id: %d\n", retval, ctrl->id);
2805
2806 return retval;
2807}
2808
2809static int tavarua_vidioc_s_ext_ctrls(struct file *file, void *priv,
2810 struct v4l2_ext_controls *ctrl)
2811{
2812 int retval = 0;
2813 int bytes_to_copy;
2814 int bytes_copied = 0;
2815 int bytes_left = 0;
2816 int chunk_index = 0;
2817 char tx_data[XFR_REG_NUM];
2818 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2819 char *data = NULL;
2820 int extra_name_byte = 0;
2821 int name_bytes = 0;
2822
2823 switch ((ctrl->controls[0]).id) {
2824 case V4L2_CID_RDS_TX_PS_NAME: {
2825 FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
2826 /*Pass a sample PS string */
2827
2828 chunk_index = 0;
2829 bytes_copied = 0;
2830 bytes_left = min((int)(ctrl->controls[0]).size,
2831 MAX_PS_LENGTH);
2832 data = (ctrl->controls[0]).string;
2833
2834 /* send payload to FM hardware */
2835 while (bytes_left) {
2836 chunk_index++;
2837 FMDBG("chunk is %d", chunk_index);
2838 bytes_to_copy = min(bytes_left, XFR_REG_NUM);
2839 /*Clear the tx_data */
2840 memset(tx_data, 0, XFR_REG_NUM);
2841 if (copy_from_user(tx_data,
2842 data + bytes_copied, bytes_to_copy))
2843 return -EFAULT;
2844 retval = sync_write_xfr(radio,
2845 RDS_PS_0 + chunk_index, tx_data);
2846 if (retval < 0) {
2847 FMDBG("sync_write_xfr: %d", retval);
2848 return retval;
2849 }
2850 bytes_copied += bytes_to_copy;
2851 bytes_left -= bytes_to_copy;
2852 }
2853 memset(tx_data, 0, XFR_REG_NUM);
2854 /*Write the PS Header*/
2855 FMDBG("Writing PS header\n");
2856 extra_name_byte = (bytes_copied%8) ? 1 : 0;
2857 name_bytes = (bytes_copied/8) + extra_name_byte;
2858 /*8 bytes are grouped as 1 name */
2859 tx_data[0] = (name_bytes) & MASK_TXREPCOUNT;
2860 tx_data[1] = radio->pty & MASK_PTY; /* PTY */
2861 tx_data[2] = ((radio->pi & MASK_PI_MSB) >> 8);
2862 tx_data[3] = radio->pi & MASK_PI_LSB;
2863 /* TX ctrl + repeatCount*/
2864 tx_data[4] = TX_ON |
2865 (radio->ps_repeatcount & MASK_TXREPCOUNT);
2866 retval = sync_write_xfr(radio, RDS_PS_0, tx_data);
2867 if (retval < 0) {
2868 FMDBG("sync_write_xfr returned %d", retval);
2869 return retval;
2870 }
2871 } break;
2872 case V4L2_CID_RDS_TX_RADIO_TEXT: {
2873 chunk_index = 0;
2874 bytes_copied = 0;
2875 FMDBG("In V4L2_CID_RDS_TX_RADIO_TEXT\n");
2876 /*Pass a sample PS string */
2877 FMDBG("Passed RT String : %s\n",
2878 (ctrl->controls[0]).string);
2879 bytes_left =
2880 min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
2881 data = (ctrl->controls[0]).string;
2882 /* send payload to FM hardware */
2883 while (bytes_left) {
2884 chunk_index++;
2885 bytes_to_copy = min(bytes_left, XFR_REG_NUM);
2886 memset(tx_data, 0, XFR_REG_NUM);
2887 if (copy_from_user(tx_data,
2888 data + bytes_copied, bytes_to_copy))
2889 return -EFAULT;
2890 retval = sync_write_xfr(radio,
2891 RDS_RT_0 + chunk_index, tx_data);
2892 if (retval < 0)
2893 return retval;
2894 bytes_copied += bytes_to_copy;
2895 bytes_left -= bytes_to_copy;
2896 }
2897 /*Write the RT Header */
2898 tx_data[0] = bytes_copied;
2899 /* PTY */
2900 tx_data[1] = TX_ON | ((radio->pty & MASK_PTY) >> 8);
2901 /* PI high */
2902 tx_data[2] = ((radio->pi & MASK_PI_MSB) >> 8);
2903 /* PI low */
2904 tx_data[3] = radio->pi & MASK_PI_LSB;
2905 retval = sync_write_xfr(radio, RDS_RT_0 , tx_data);
2906 if (retval < 0)
2907 return retval;
2908 FMDBG("done RT writing: %d\n", retval);
2909 } break;
2910 default:
2911 {
2912 FMDBG("Shouldn't reach here\n");
2913 retval = -1;
2914 }
2915 }
2916 return retval;
2917}
2918
2919/*=============================================================================
2920FUNCTION: tavarua_vidioc_s_ctrl
2921=============================================================================*/
2922/**
2923 This function is called to set the value of a control.
2924
2925 NOTE:
2926 To change the value of a control, applications initialize the id and value
2927 fields of a struct v4l2_control and call the VIDIOC_S_CTRL ioctl.
2928
2929 When the id is invalid drivers return an EINVAL error code. When the value is
2930 out of bounds drivers can choose to take the closest valid value or return an
2931 ERANGE error code, whatever seems more appropriate.
2932
2933 @param file: File descriptor returned by open().
2934 @param ctrl: pointer to struct v4l2_control.
2935
2936 @return On success 0 is returned, else error code.
2937 @return EINVAL: The struct v4l2_control id is invalid.
2938 @return ERANGE: The struct v4l2_control value is out of bounds.
2939 @return EBUSY: The control is temporarily not changeable, possibly because
2940 another applications took over control of the device function this control
2941 belongs to.
2942*/
2943static int tavarua_vidioc_s_ctrl(struct file *file, void *priv,
2944 struct v4l2_control *ctrl)
2945{
2946 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2947 int retval = 0;
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05302948 int size = 0, cnt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002949 unsigned char value;
2950 unsigned char xfr_buf[XFR_REG_NUM];
2951 unsigned char tx_data[XFR_REG_NUM];
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302952 unsigned char dis_buf[XFR_REG_NUM];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002953
2954 switch (ctrl->id) {
2955 case V4L2_CID_AUDIO_VOLUME:
2956 break;
2957 case V4L2_CID_AUDIO_MUTE:
2958 value = (radio->registers[IOCTRL] & ~IOC_HRD_MUTE) |
2959 (ctrl->value & 0x03);
2960 retval = tavarua_write_register(radio, IOCTRL, value);
2961 break;
2962 case V4L2_CID_PRIVATE_TAVARUA_SRCHMODE:
2963 value = (radio->registers[SRCHCTRL] & ~SRCH_MODE) |
2964 ctrl->value;
2965 radio->registers[SRCHCTRL] = value;
2966 break;
2967 case V4L2_CID_PRIVATE_TAVARUA_SCANDWELL:
2968 value = (radio->registers[SRCHCTRL] & ~SCAN_DWELL) |
2969 (ctrl->value << 4);
2970 radio->registers[SRCHCTRL] = value;
2971 break;
2972 /* start/stop search */
2973 case V4L2_CID_PRIVATE_TAVARUA_SRCHON:
2974 FMDBG("starting search\n");
2975 tavarua_search(radio, ctrl->value, SRCH_DIR_UP);
2976 break;
2977 case V4L2_CID_PRIVATE_TAVARUA_STATE:
2978 /* check if already on */
2979 radio->handle_irq = 1;
2980 if (((ctrl->value == FM_RECV) || (ctrl->value == FM_TRANS))
2981 && !(radio->registers[RDCTRL] &
2982 ctrl->value)) {
2983 FMDBG("clearing flags\n");
2984 init_completion(&radio->sync_xfr_start);
2985 init_completion(&radio->sync_req_done);
2986 radio->xfr_in_progress = 0;
2987 radio->xfr_bytes_left = 0;
2988 FMDBG("turning on ..\n");
2989 retval = tavarua_start(radio, ctrl->value);
2990 if (retval >= 0) {
Anantha Krishnanc72725a2011-09-06 09:28:22 +05302991 /* Enabling 'SoftMute' & 'SignalBlending' */
2992 value = (radio->registers[IOCTRL] |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002993 IOC_SFT_MUTE | IOC_SIG_BLND);
Anantha Krishnanc72725a2011-09-06 09:28:22 +05302994 retval = tavarua_write_register(radio,
2995 IOCTRL, value);
2996 if (retval < 0)
2997 FMDBG("SMute and SBlending"
2998 "not enabled\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002999 }
3000 }
3001 /* check if off */
3002 else if ((ctrl->value == FM_OFF) && radio->registers[RDCTRL]) {
Anantha Krishnan1475c932012-02-16 21:54:03 +05303003 FMDBG("%s: turning off...\n", __func__);
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05303004 tavarua_write_register(radio, RDCTRL, ctrl->value);
3005 /* flush the event and work queues */
3006 kfifo_reset(&radio->data_buf[TAVARUA_BUF_EVENTS]);
3007 flush_workqueue(radio->wqueue);
3008 /*
3009 * queue the READY event from the host side
3010 * in case of FM off
3011 */
Ayaz Ahmad0fa19842012-03-14 22:54:53 +05303012 tavarua_q_event(radio, TAVARUA_EVT_RADIO_DISABLED);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003013
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05303014 FMDBG("%s, Disable All Interrupts\n", __func__);
3015 /* disable irq */
3016 dis_buf[STATUS_REG1] = 0x00;
3017 dis_buf[STATUS_REG2] = 0x00;
3018 dis_buf[STATUS_REG3] = TRANSFER;
3019 retval = sync_write_xfr(radio, INT_CTRL, dis_buf);
3020 if (retval < 0) {
3021 pr_err("%s: failed to disable"
3022 "Interrupts\n", __func__);
3023 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003024 }
3025 }
3026 break;
Anantha Krishnanc72725a2011-09-06 09:28:22 +05303027 case V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH:
3028 FMDBG("Setting audio path ...\n");
3029 if (ctrl->value == FM_DIGITAL_PATH) {
3030 FMDBG("Digital audio path enabled ...\n");
3031 retval = tavarua_set_audio_path(
3032 TAVARUA_AUDIO_OUT_DIGITAL_ON,
3033 TAVARUA_AUDIO_OUT_ANALOG_OFF);
3034 if (retval < 0) {
3035 FMDERR("Error in tavarua_set_audio_path"
3036 " %d\n", retval);
3037 }
3038 } else if (ctrl->value == FM_ANALOG_PATH) {
3039 FMDBG("Analog audio path enabled ...\n");
3040 retval = tavarua_set_audio_path(
Venkateshwarlu Domakondab49c2cb2012-04-17 17:44:50 +05303041 TAVARUA_AUDIO_OUT_DIGITAL_OFF,
3042 TAVARUA_AUDIO_OUT_ANALOG_ON);
Anantha Krishnanc72725a2011-09-06 09:28:22 +05303043 if (retval < 0) {
3044 FMDERR("Error in tavarua_set_audio_path"
3045 " %d\n", retval);
3046 }
3047 }
3048 break;
Anantha Krishnan40bcd052011-12-05 15:28:29 +05303049 case V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM:
3050 radio->enable_optimized_srch_alg = ctrl->value;
3051 FMDBG("V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM : %d",
3052 radio->enable_optimized_srch_alg);
3053 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003054 case V4L2_CID_PRIVATE_TAVARUA_REGION:
3055 retval = tavarua_set_region(radio, ctrl->value);
3056 break;
3057 case V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH:
3058 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
3059 if (retval < 0) {
3060 FMDERR("V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
3061 FMDERR("sync_read_xfr [retval=%d]\n", retval);
3062 break;
3063 }
3064 /* RMSSI Threshold is a signed 8 bit value */
3065 xfr_buf[0] = (unsigned char)ctrl->value;
3066 xfr_buf[1] = (unsigned char)ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003067 retval = sync_write_xfr(radio, RX_CONFIG, xfr_buf);
3068 if (retval < 0) {
3069 FMDERR("V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
3070 FMDERR("sync_write_xfr [retval=%d]\n", retval);
3071 break;
3072 }
3073 break;
3074 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY:
3075 radio->srch_params.srch_pty = ctrl->value;
3076 break;
3077 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PI:
3078 radio->srch_params.srch_pi = ctrl->value;
3079 break;
3080 case V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT:
3081 radio->srch_params.preset_num = ctrl->value;
3082 break;
3083 case V4L2_CID_PRIVATE_TAVARUA_EMPHASIS:
3084 radio->region_params.emphasis = ctrl->value;
3085 break;
3086 case V4L2_CID_PRIVATE_TAVARUA_RDS_STD:
3087 radio->region_params.rds_std = ctrl->value;
3088 break;
3089 case V4L2_CID_PRIVATE_TAVARUA_SPACING:
3090 radio->region_params.spacing = ctrl->value;
3091 break;
3092 case V4L2_CID_PRIVATE_TAVARUA_RDSON:
3093 retval = 0;
3094 if (ctrl->value != (radio->registers[RDSCTRL] & RDS_ON)) {
3095 value = radio->registers[RDSCTRL] | ctrl->value;
3096 retval = tavarua_write_register(radio, RDSCTRL, value);
3097 }
3098 break;
3099 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK:
3100 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
3101 if (retval < 0)
3102 break;
3103 xfr_buf[8] = (ctrl->value & 0xFF000000) >> 24;
3104 xfr_buf[9] = (ctrl->value & 0x00FF0000) >> 16;
3105 xfr_buf[10] = (ctrl->value & 0x0000FF00) >> 8;
3106 xfr_buf[11] = (ctrl->value & 0x000000FF);
3107 retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
3108 break;
3109 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC:
Anantha Krishnane46ef6f2011-06-29 23:56:03 +05303110 value = radio->registers[ADVCTRL] | ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003111 retval = tavarua_write_register(radio, ADVCTRL, value);
3112 break;
Anantha Krishnane46ef6f2011-06-29 23:56:03 +05303113 case V4L2_CID_PRIVATE_TAVARUA_AF_JUMP:
3114 retval = tavarua_read_registers(radio, ADVCTRL, 1);
3115 SET_REG_FIELD(radio->registers[ADVCTRL], ctrl->value,
3116 RDSAF_OFFSET, RDSAF_MASK);
3117 msleep(TAVARUA_DELAY*5);
3118 retval = tavarua_write_register(radio,
3119 ADVCTRL, radio->registers[ADVCTRL]);
3120 msleep(TAVARUA_DELAY*5);
3121 break;
Anantha Krishnan3b44cd42011-07-06 12:36:15 +05303122 case V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA:
3123 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
3124 if (retval < 0) {
3125 FMDERR("V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA]\n");
3126 FMDERR("sync_read_xfr [retval=%d]\n", retval);
3127 break;
3128 }
3129 xfr_buf[4] = (unsigned char)ctrl->value;
3130 retval = sync_write_xfr(radio, RX_CONFIG, xfr_buf);
3131 if (retval < 0) {
3132 FMDERR("V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA]\n");
3133 FMDERR("sync_write_xfr [retval=%d]\n", retval);
3134 break;
3135 }
3136 break;
Anantha Krishnanf2258602011-06-30 01:32:09 +05303137 case V4L2_CID_PRIVATE_TAVARUA_HLSI:
3138 retval = tavarua_read_registers(radio, RDCTRL, 1);
3139 SET_REG_FIELD(radio->registers[RDCTRL], ctrl->value,
3140 RDCTRL_HLSI_OFFSET, RDCTRL_HLSI_MASK);
3141 retval = tavarua_write_register(radio, RDCTRL,
3142 radio->registers[RDCTRL]);
3143 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003144 case V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF:
3145 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
3146 if (retval < 0)
3147 break;
3148 xfr_buf[1] = ctrl->value;
3149 retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
3150 break;
3151 case V4L2_CID_PRIVATE_TAVARUA_PSALL:
3152 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
3153 value = ctrl->value & RDS_CONFIG_PSALL;
3154 if (retval < 0)
3155 break;
3156 xfr_buf[12] &= ~RDS_CONFIG_PSALL;
3157 xfr_buf[12] |= value;
3158 retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
3159 break;
3160 case V4L2_CID_PRIVATE_TAVARUA_LP_MODE:
3161 retval = 0;
3162 if (ctrl->value == radio->lp_mode)
3163 break;
3164 if (ctrl->value) {
3165 FMDBG("going into low power mode\n");
3166 retval = tavarua_disable_interrupts(radio);
3167 } else {
3168 FMDBG("going into normal power mode\n");
3169 tavarua_setup_interrupts(radio,
3170 (radio->registers[RDCTRL] & 0x03));
3171 }
3172 break;
3173 case V4L2_CID_PRIVATE_TAVARUA_ANTENNA:
3174 SET_REG_FIELD(radio->registers[IOCTRL], ctrl->value,
3175 IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
3176 break;
Anantha Krishnana3dcce42012-01-05 19:27:57 +05303177 case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303178 size = 0x04;
3179 /* Poking the value of ON Channel Threshold value */
3180 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
3181 xfr_buf[1] = ON_CHANNEL_TH_MSB;
3182 xfr_buf[2] = ON_CHANNEL_TH_LSB;
3183 /* Data to be poked into the register */
3184 xfr_buf[3] = (ctrl->value & 0xFF000000) >> 24;
3185 xfr_buf[4] = (ctrl->value & 0x00FF0000) >> 16;
3186 xfr_buf[5] = (ctrl->value & 0x0000FF00) >> 8;
3187 xfr_buf[6] = (ctrl->value & 0x000000FF);
3188
3189 for (cnt = 3; cnt < 7; cnt++) {
3190 FMDBG("On-channel data to be poked is : %d",
3191 (int)xfr_buf[cnt]);
3192 }
3193
3194 retval = tavarua_write_registers(radio, XFRCTRL,
3195 xfr_buf, size+3);
3196 if (retval < 0) {
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303197 pr_err("%s: Failed to write\n", __func__);
3198 return retval;
3199 }
3200 /*Wait for the XFR interrupt */
3201 msleep(TAVARUA_DELAY*10);
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303202 break;
Anantha Krishnana3dcce42012-01-05 19:27:57 +05303203 case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303204 size = 0x04;
3205 /* Poking the value of OFF Channel Threshold value */
3206 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
3207 xfr_buf[1] = OFF_CHANNEL_TH_MSB;
3208 xfr_buf[2] = OFF_CHANNEL_TH_LSB;
3209 /* Data to be poked into the register */
3210 xfr_buf[3] = (ctrl->value & 0xFF000000) >> 24;
3211 xfr_buf[4] = (ctrl->value & 0x00FF0000) >> 16;
3212 xfr_buf[5] = (ctrl->value & 0x0000FF00) >> 8;
3213 xfr_buf[6] = (ctrl->value & 0x000000FF);
3214
3215 for (cnt = 3; cnt < 7; cnt++) {
3216 FMDBG("Off-channel data to be poked is : %d",
3217 (int)xfr_buf[cnt]);
3218 }
3219
3220 retval = tavarua_write_registers(radio, XFRCTRL,
3221 xfr_buf, size+3);
3222 if (retval < 0) {
3223 pr_err("%s: Failed to write\n", __func__);
3224 return retval;
3225 }
3226 /*Wait for the XFR interrupt */
3227 msleep(TAVARUA_DELAY*10);
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303228 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003229 /* TX Controls */
3230
3231 case V4L2_CID_RDS_TX_PTY: {
3232 radio->pty = ctrl->value;
3233 } break;
3234 case V4L2_CID_RDS_TX_PI: {
3235 radio->pi = ctrl->value;
3236 } break;
3237 case V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_PS_NAME: {
3238 FMDBG("In STOP_RDS_TX_PS_NAME\n");
3239 /*Pass a sample PS string */
3240 memset(tx_data, '0', XFR_REG_NUM);
3241 FMDBG("Writing PS header\n");
3242 retval = sync_write_xfr(radio, RDS_PS_0, tx_data);
3243 FMDBG("retval of PS Header write: %d", retval);
3244
3245 } break;
3246
3247 case V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_RT: {
3248 memset(tx_data, '0', XFR_REG_NUM);
3249 FMDBG("Writing RT header\n");
3250 retval = sync_write_xfr(radio, RDS_RT_0, tx_data);
3251 FMDBG("retval of Header write: %d", retval);
3252
3253 } break;
3254
3255 case V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT: {
3256 radio->ps_repeatcount = ctrl->value;
3257 } break;
3258 case V4L2_CID_TUNE_POWER_LEVEL: {
3259 unsigned char tx_power_lvl_config[FM_TX_PWR_LVL_MAX+1] = {
3260 0x85, /* tx_da<5:3> = 0 lpf<2:0> = 5*/
3261 0x95, /* tx_da<5:3> = 2 lpf<2:0> = 5*/
3262 0x9D, /* tx_da<5:3> = 3 lpf<2:0> = 5*/
3263 0xA5, /* tx_da<5:3> = 4 lpf<2:0> = 5*/
3264 0xAD, /* tx_da<5:3> = 5 lpf<2:0> = 5*/
3265 0xB5, /* tx_da<5:3> = 6 lpf<2:0> = 5*/
3266 0xBD, /* tx_da<5:3> = 7 lpf<2:0> = 5*/
3267 0xBF /* tx_da<5:3> = 7 lpf<2:0> = 7*/
3268 };
3269 if (ctrl->value > FM_TX_PWR_LVL_MAX)
3270 ctrl->value = FM_TX_PWR_LVL_MAX;
3271 if (ctrl->value < FM_TX_PWR_LVL_0)
3272 ctrl->value = FM_TX_PWR_LVL_0;
3273 retval = sync_read_xfr(radio, PHY_TXGAIN, xfr_buf);
3274 FMDBG("return for PHY_TXGAIN is %d", retval);
3275 if (retval < 0) {
3276 FMDBG("read failed");
3277 break;
3278 }
3279 xfr_buf[2] = tx_power_lvl_config[ctrl->value];
3280 retval = sync_write_xfr(radio, PHY_TXGAIN, xfr_buf);
3281 FMDBG("return for write PHY_TXGAIN is %d", retval);
3282 if (retval < 0)
3283 FMDBG("write failed");
3284 } break;
Anantha Krishnan71d6fa62011-12-13 19:30:51 +05303285 /*These IOCTL's are place holders to keep the
Srinivasa Rao Uppala4e38bfc2011-09-15 16:00:31 +05303286 driver compatible with change in frame works for IRIS */
Anantha Krishnan71d6fa62011-12-13 19:30:51 +05303287 case V4L2_CID_PRIVATE_SOFT_MUTE:
3288 case V4L2_CID_PRIVATE_RIVA_ACCS_ADDR:
3289 case V4L2_CID_PRIVATE_RIVA_ACCS_LEN:
3290 case V4L2_CID_PRIVATE_RIVA_PEEK:
3291 case V4L2_CID_PRIVATE_RIVA_POKE:
3292 case V4L2_CID_PRIVATE_SSBI_ACCS_ADDR:
3293 case V4L2_CID_PRIVATE_SSBI_PEEK:
3294 case V4L2_CID_PRIVATE_SSBI_POKE:
3295 case V4L2_CID_PRIVATE_TX_TONE:
3296 case V4L2_CID_PRIVATE_RDS_GRP_COUNTERS:
3297 case V4L2_CID_PRIVATE_SET_NOTCH_FILTER:
3298 case V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION:
Anantha Krishnana3dcce42012-01-05 19:27:57 +05303299 case V4L2_CID_PRIVATE_SINR_THRESHOLD:
3300 case V4L2_CID_PRIVATE_SINR_SAMPLES:
Srinivasa Rao Uppala4e38bfc2011-09-15 16:00:31 +05303301 retval = 0;
3302 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003303 default:
3304 retval = -EINVAL;
3305 }
3306 if (retval < 0)
3307 printk(KERN_WARNING DRIVER_NAME
3308 ": set control failed with %d, id : %d\n", retval, ctrl->id);
3309
3310 return retval;
3311}
3312
3313/*=============================================================================
3314FUNCTION: tavarua_vidioc_g_tuner
3315=============================================================================*/
3316/**
3317 This function is called to get tuner attributes.
3318
3319 NOTE:
3320 To query the attributes of a tuner, applications initialize the index field
3321 and zero out the reserved array of a struct v4l2_tuner and call the
3322 VIDIOC_G_TUNER ioctl with a pointer to this structure. Drivers fill the rest
3323 of the structure or return an EINVAL error code when the index is out of
3324 bounds. To enumerate all tuners applications shall begin at index zero,
3325 incrementing by one until the driver returns EINVAL.
3326
3327 @param file: File descriptor returned by open().
3328 @param tuner: pointer to struct v4l2_tuner.
3329
3330 @return On success 0 is returned, else error code.
3331 @return EINVAL: The struct v4l2_tuner index is out of bounds.
3332*/
3333static int tavarua_vidioc_g_tuner(struct file *file, void *priv,
3334 struct v4l2_tuner *tuner)
3335{
3336 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3337 int retval;
3338 unsigned char xfr_buf[XFR_REG_NUM];
3339 char rmssi = 0;
3340 unsigned char size = 0;
3341
3342 if (tuner->index > 0)
3343 return -EINVAL;
3344
3345 /* read status rssi */
3346 retval = tavarua_read_registers(radio, IOCTRL, 1);
3347 if (retval < 0)
3348 return retval;
3349 /* read RMSSI */
3350 size = 0x1;
3351 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
3352 xfr_buf[1] = RMSSI_PEEK_MSB;
3353 xfr_buf[2] = RMSSI_PEEK_LSB;
3354 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
3355 msleep(TAVARUA_DELAY*10);
3356 retval = tavarua_read_registers(radio, XFRDAT0, 3);
3357 rmssi = radio->registers[XFRDAT0];
3358 tuner->signal = rmssi;
3359
3360 strcpy(tuner->name, "FM");
3361 tuner->type = V4L2_TUNER_RADIO;
3362 tuner->rangelow = radio->region_params.band_low;
3363 tuner->rangehigh = radio->region_params.band_high;
3364 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
3365 tuner->capability = V4L2_TUNER_CAP_LOW;
3366
3367 /* Stereo indicator == Stereo (instead of Mono) */
3368 if (radio->registers[IOCTRL] & IOC_MON_STR)
3369 tuner->audmode = V4L2_TUNER_MODE_STEREO;
3370 else
3371 tuner->audmode = V4L2_TUNER_MODE_MONO;
3372
3373 /* automatic frequency control: -1: freq to low, 1 freq to high */
3374 tuner->afc = 0;
3375
3376 return 0;
3377}
3378
3379/*=============================================================================
3380FUNCTION: tavarua_vidioc_s_tuner
3381=============================================================================*/
3382/**
3383 This function is called to set tuner attributes. Used to set mono/stereo mode.
3384
3385 NOTE:
3386 Tuners have two writable properties, the audio mode and the radio frequency.
3387 To change the audio mode, applications initialize the index, audmode and
3388 reserved fields and call the VIDIOC_S_TUNER ioctl. This will not change the
3389 current tuner, which is determined by the current video input. Drivers may
3390 choose a different audio mode if the requested mode is invalid or unsupported.
3391 Since this is a write-only ioctl, it does not return the actually selected
3392 audio mode.
3393
3394 To change the radio frequency the VIDIOC_S_FREQUENCY ioctl is available.
3395
3396 @param file: File descriptor returned by open().
3397 @param tuner: pointer to struct v4l2_tuner.
3398
3399 @return On success 0 is returned, else error code.
3400 @return -EINVAL: The struct v4l2_tuner index is out of bounds.
3401*/
3402static int tavarua_vidioc_s_tuner(struct file *file, void *priv,
3403 struct v4l2_tuner *tuner)
3404{
3405 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3406 int retval;
3407 int audmode;
3408 if (tuner->index > 0)
3409 return -EINVAL;
3410
3411 FMDBG("%s: set low to %d\n", __func__, tuner->rangelow);
3412 radio->region_params.band_low = tuner->rangelow;
3413 radio->region_params.band_high = tuner->rangehigh;
3414 if (tuner->audmode == V4L2_TUNER_MODE_MONO)
3415 /* Mono */
3416 audmode = (radio->registers[IOCTRL] | IOC_MON_STR);
3417 else
3418 /* Stereo */
3419 audmode = (radio->registers[IOCTRL] & ~IOC_MON_STR);
3420 retval = tavarua_write_register(radio, IOCTRL, audmode);
3421 if (retval < 0)
3422 printk(KERN_WARNING DRIVER_NAME
3423 ": set tuner failed with %d\n", retval);
3424
3425 return retval;
3426}
3427
3428/*=============================================================================
3429FUNCTION: tavarua_vidioc_g_frequency
3430=============================================================================*/
3431/**
3432 This function is called to get tuner or modulator radio frequency.
3433
3434 NOTE:
3435 To get the current tuner or modulator radio frequency applications set the
3436 tuner field of a struct v4l2_frequency to the respective tuner or modulator
3437 number (only input devices have tuners, only output devices have modulators),
3438 zero out the reserved array and call the VIDIOC_G_FREQUENCY ioctl with a
3439 pointer to this structure. The driver stores the current frequency in the
3440 frequency field.
3441
3442 @param file: File descriptor returned by open().
3443 @param freq: pointer to struct v4l2_frequency. This will be set to the
3444 resultant
3445 frequency in 62.5 khz on success.
3446
3447 @return On success 0 is returned, else error code.
3448 @return EINVAL: The tuner index is out of bounds or the value in the type
3449 field is wrong.
3450*/
3451static int tavarua_vidioc_g_frequency(struct file *file, void *priv,
3452 struct v4l2_frequency *freq)
3453{
3454 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3455 freq->type = V4L2_TUNER_RADIO;
3456 return tavarua_get_freq(radio, freq);
3457
3458}
3459
3460/*=============================================================================
3461FUNCTION: tavarua_vidioc_s_frequency
3462=============================================================================*/
3463/**
3464 This function is called to set tuner or modulator radio frequency.
3465
3466 NOTE:
3467 To change the current tuner or modulator radio frequency applications
3468 initialize the tuner, type and frequency fields, and the reserved array of
3469 a struct v4l2_frequency and call the VIDIOC_S_FREQUENCY ioctl with a pointer
3470 to this structure. When the requested frequency is not possible the driver
3471 assumes the closest possible value. However VIDIOC_S_FREQUENCY is a
3472 write-only ioctl, it does not return the actual new frequency.
3473
3474 @param file: File descriptor returned by open().
3475 @param freq: pointer to struct v4l2_frequency.
3476
3477 @return On success 0 is returned, else error code.
3478 @return EINVAL: The tuner index is out of bounds or the value in the type
3479 field is wrong.
3480*/
3481static int tavarua_vidioc_s_frequency(struct file *file, void *priv,
3482 struct v4l2_frequency *freq)
3483{
3484 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3485 int retval = -1;
3486 struct v4l2_frequency getFreq;
3487
3488 FMDBG("%s\n", __func__);
3489
3490 if (freq->type != V4L2_TUNER_RADIO)
3491 return -EINVAL;
3492
3493 FMDBG("Calling tavarua_set_freq\n");
3494
3495 INIT_COMPLETION(radio->sync_req_done);
3496 retval = tavarua_set_freq(radio, freq->frequency);
3497 if (retval < 0) {
3498 printk(KERN_WARNING DRIVER_NAME
3499 ": set frequency failed with %d\n", retval);
3500 } else {
3501 /* Wait for interrupt i.e. complete
3502 (&radio->sync_req_done); call */
3503 if (!wait_for_completion_timeout(&radio->sync_req_done,
3504 msecs_to_jiffies(wait_timeout))) {
3505 FMDERR("Timeout: No Tune response");
3506 retval = tavarua_get_freq(radio, &getFreq);
3507 radio->tune_req = 0;
3508 if (retval > 0) {
3509 if (getFreq.frequency == freq->frequency) {
3510 /** This is success, queut the event*/
3511 tavarua_q_event(radio,
3512 TAVARUA_EVT_TUNE_SUCC);
3513 return 0;
3514 } else {
3515 return -EIO;
3516 }
3517 }
3518 }
3519 }
3520 radio->tune_req = 0;
3521 return retval;
3522}
3523
3524/*=============================================================================
3525FUNCTION: tavarua_vidioc_dqbuf
3526=============================================================================*/
3527/**
3528 This function is called to exchange a buffer with the driver.
3529 This is main buffer function, in essense its equivalent to a blocking
3530 read call.
3531
3532 Applications call the VIDIOC_DQBUF ioctl to dequeue a filled (capturing) or
3533 displayed (output) buffer from the driver's outgoing queue. They just set
3534 the type and memory fields of a struct v4l2_buffer as above, when VIDIOC_DQBUF
3535 is called with a pointer to this structure the driver fills the remaining
3536 fields or returns an error code.
3537
3538 NOTE:
3539 By default VIDIOC_DQBUF blocks when no buffer is in the outgoing queue.
3540 When the O_NONBLOCK flag was given to the open() function, VIDIOC_DQBUF
3541 returns immediately with an EAGAIN error code when no buffer is available.
3542
3543 @param file: File descriptor returned by open().
3544 @param buffer: pointer to struct v4l2_buffer.
3545
3546 @return On success 0 is returned, else error code.
3547 @return EAGAIN: Non-blocking I/O has been selected using O_NONBLOCK and no
3548 buffer was in the outgoing queue.
3549 @return EINVAL: The buffer type is not supported, or the index is out of
3550 bounds, or no buffers have been allocated yet, or the userptr or length are
3551 invalid.
3552 @return ENOMEM: Not enough physical or virtual memory was available to enqueue
3553 a user pointer buffer.
3554 @return EIO: VIDIOC_DQBUF failed due to an internal error. Can also indicate
3555 temporary problems like signal loss. Note the driver might dequeue an (empty)
3556 buffer despite returning an error, or even stop capturing.
3557*/
3558static int tavarua_vidioc_dqbuf(struct file *file, void *priv,
3559 struct v4l2_buffer *buffer)
3560{
3561
3562 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3563 enum tavarua_buf_t buf_type = buffer->index;
3564 struct kfifo *data_fifo;
3565 unsigned char *buf = (unsigned char *)buffer->m.userptr;
3566 unsigned int len = buffer->length;
3567 FMDBG("%s: requesting buffer %d\n", __func__, buf_type);
3568 /* check if we can access the user buffer */
3569 if (!access_ok(VERIFY_WRITE, buf, len))
3570 return -EFAULT;
3571 if ((buf_type < TAVARUA_BUF_MAX) && (buf_type >= 0)) {
3572 data_fifo = &radio->data_buf[buf_type];
3573 if (buf_type == TAVARUA_BUF_EVENTS) {
3574 if (wait_event_interruptible(radio->event_queue,
3575 kfifo_len(data_fifo)) < 0) {
3576 return -EINTR;
3577 }
3578 }
3579 } else {
3580 FMDERR("invalid buffer type\n");
3581 return -EINVAL;
3582 }
3583 buffer->bytesused = kfifo_out_locked(data_fifo, buf, len,
3584 &radio->buf_lock[buf_type]);
3585
3586 return 0;
3587}
3588
3589/*=============================================================================
3590FUNCTION: tavarua_vidioc_g_fmt_type_private
3591=============================================================================*/
3592/**
3593 This function is here to make the v4l2 framework happy.
3594 We cannot use private buffers without it.
3595
3596 @param file: File descriptor returned by open().
3597 @param f: pointer to struct v4l2_format.
3598
3599 @return On success 0 is returned, else error code.
3600 @return EINVAL: The tuner index is out of bounds or the value in the type
3601 field is wrong.
3602*/
3603static int tavarua_vidioc_g_fmt_type_private(struct file *file, void *priv,
3604 struct v4l2_format *f)
3605{
3606 return 0;
3607
3608}
3609
3610/*=============================================================================
3611FUNCTION: tavarua_vidioc_s_hw_freq_seek
3612=============================================================================*/
3613/**
3614 This function is called to perform a hardware frequency seek.
3615
3616 Start a hardware frequency seek from the current frequency. To do this
3617 applications initialize the tuner, type, seek_upward and wrap_around fields,
3618 and zero out the reserved array of a struct v4l2_hw_freq_seek and call the
3619 VIDIOC_S_HW_FREQ_SEEK ioctl with a pointer to this structure.
3620
3621 This ioctl is supported if the V4L2_CAP_HW_FREQ_SEEK capability is set.
3622
3623 @param file: File descriptor returned by open().
3624 @param seek: pointer to struct v4l2_hw_freq_seek.
3625
3626 @return On success 0 is returned, else error code.
3627 @return EINVAL: The tuner index is out of bounds or the value in the type
3628 field is wrong.
3629 @return EAGAIN: The ioctl timed-out. Try again.
3630*/
3631static int tavarua_vidioc_s_hw_freq_seek(struct file *file, void *priv,
3632 struct v4l2_hw_freq_seek *seek)
3633{
3634 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003635 FMDBG("starting search\n");
Anantha Krishnan75b90b22012-03-08 12:42:30 +05303636 return tavarua_search(radio, CTRL_ON, seek->seek_upward);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003637}
3638
3639/*
3640 * tavarua_viddev_tamples - video device interface
3641 */
3642static const struct v4l2_ioctl_ops tavarua_ioctl_ops = {
3643 .vidioc_querycap = tavarua_vidioc_querycap,
3644 .vidioc_queryctrl = tavarua_vidioc_queryctrl,
3645 .vidioc_g_ctrl = tavarua_vidioc_g_ctrl,
3646 .vidioc_s_ctrl = tavarua_vidioc_s_ctrl,
3647 .vidioc_g_tuner = tavarua_vidioc_g_tuner,
3648 .vidioc_s_tuner = tavarua_vidioc_s_tuner,
3649 .vidioc_g_frequency = tavarua_vidioc_g_frequency,
3650 .vidioc_s_frequency = tavarua_vidioc_s_frequency,
3651 .vidioc_s_hw_freq_seek = tavarua_vidioc_s_hw_freq_seek,
3652 .vidioc_dqbuf = tavarua_vidioc_dqbuf,
3653 .vidioc_g_fmt_type_private = tavarua_vidioc_g_fmt_type_private,
3654 .vidioc_s_ext_ctrls = tavarua_vidioc_s_ext_ctrls,
3655};
3656
3657static struct video_device tavarua_viddev_template = {
3658 .fops = &tavarua_fops,
3659 .ioctl_ops = &tavarua_ioctl_ops,
3660 .name = DRIVER_NAME,
3661 .release = video_device_release,
3662};
3663
3664/*==============================================================
3665FUNCTION: FmQSocCom_EnableInterrupts
3666==============================================================*/
3667/**
3668 This function enable interrupts.
3669
3670 @param radio: structure pointer passed by client.
3671 @param state: FM radio state (receiver/transmitter/off/reset).
3672
3673 @return => 0 if successful.
3674 @return < 0 if failure.
3675*/
3676static int tavarua_setup_interrupts(struct tavarua_device *radio,
3677 enum radio_state_t state)
3678{
3679 int retval;
3680 unsigned char int_ctrl[XFR_REG_NUM];
3681
3682 if (!radio->lp_mode)
3683 return 0;
3684
3685 int_ctrl[STATUS_REG1] = READY | TUNE | SEARCH | SCANNEXT |
3686 SIGNAL | INTF | SYNC | AUDIO;
3687 if (state == FM_RECV)
3688 int_ctrl[STATUS_REG2] = RDSDAT | RDSRT | RDSPS | RDSAF;
3689 else
3690 int_ctrl[STATUS_REG2] = TXRDSDAT | TXRDSDONE;
3691
3692 int_ctrl[STATUS_REG3] = TRANSFER | ERROR;
3693
3694 /* use xfr for interrupt setup */
3695 if (radio->chipID == MARIMBA_2_1 || radio->chipID == BAHAMA_1_0
3696 || radio->chipID == BAHAMA_2_0) {
3697 FMDBG("Setting interrupts\n");
3698 retval = sync_write_xfr(radio, INT_CTRL, int_ctrl);
3699 /* use register write to setup interrupts */
3700 } else {
3701 retval = tavarua_write_register(radio,
3702 STATUS_REG1, int_ctrl[STATUS_REG1]);
3703 if (retval < 0)
3704 return retval;
3705
3706 retval = tavarua_write_register(radio,
3707 STATUS_REG2, int_ctrl[STATUS_REG2]);
3708 if (retval < 0)
3709 return retval;
3710
3711 retval = tavarua_write_register(radio,
3712 STATUS_REG3, int_ctrl[STATUS_REG3]);
3713 if (retval < 0)
3714 return retval;
3715 }
3716
3717 radio->lp_mode = 0;
3718 /* tavarua_handle_interrupts force reads all the interrupt status
3719 * registers and it is not valid for MBA 2.1
3720 */
3721 if ((radio->chipID != MARIMBA_2_1) && (radio->chipID != BAHAMA_1_0)
3722 && (radio->chipID != BAHAMA_2_0))
3723 tavarua_handle_interrupts(radio);
3724
3725 return retval;
3726
3727}
3728
3729/*==============================================================
3730FUNCTION: tavarua_disable_interrupts
3731==============================================================*/
3732/**
3733 This function disables interrupts.
3734
3735 @param radio: structure pointer passed by client.
3736
3737 @return => 0 if successful.
3738 @return < 0 if failure.
3739*/
3740static int tavarua_disable_interrupts(struct tavarua_device *radio)
3741{
3742 unsigned char lpm_buf[XFR_REG_NUM];
3743 int retval;
3744 if (radio->lp_mode)
3745 return 0;
3746 FMDBG("%s\n", __func__);
3747 /* In Low power mode, disable all the interrupts that are not being
3748 waited by the Application */
3749 lpm_buf[STATUS_REG1] = TUNE | SEARCH | SCANNEXT;
3750 lpm_buf[STATUS_REG2] = 0x00;
3751 lpm_buf[STATUS_REG3] = TRANSFER;
3752 /* use xfr for interrupt setup */
3753 wait_timeout = 100;
3754 if (radio->chipID == MARIMBA_2_1 || radio->chipID == BAHAMA_1_0
3755 || radio->chipID == BAHAMA_2_0)
3756 retval = sync_write_xfr(radio, INT_CTRL, lpm_buf);
3757 /* use register write to setup interrupts */
3758 else
3759 retval = tavarua_write_registers(radio, STATUS_REG1, lpm_buf,
3760 ARRAY_SIZE(lpm_buf));
3761
3762 /*INT_CTL writes may fail with TIME_OUT as all the
3763 interrupts have been disabled
3764 */
3765 if (retval > -1 || retval == -ETIME) {
3766 radio->lp_mode = 1;
3767 /*Consider timeout as a valid case here*/
3768 retval = 0;
3769 }
3770 wait_timeout = WAIT_TIMEOUT;
3771 return retval;
3772
3773}
3774
3775/*==============================================================
3776FUNCTION: tavarua_start
3777==============================================================*/
3778/**
3779 Starts/enables the device (FM radio).
3780
3781 @param radio: structure pointer passed by client.
3782 @param state: FM radio state (receiver/transmitter/off/reset).
3783
3784 @return On success 0 is returned, else error code.
3785*/
3786static int tavarua_start(struct tavarua_device *radio,
3787 enum radio_state_t state)
3788{
3789
3790 int retval;
3791 FMDBG("%s <%d>\n", __func__, state);
3792 /* set geographic region */
3793 radio->region_params.region = TAVARUA_REGION_US;
3794
3795 /* set radio mode */
3796 retval = tavarua_write_register(radio, RDCTRL, state);
3797 if (retval < 0)
3798 return retval;
3799 /* wait for radio to init */
3800 msleep(RADIO_INIT_TIME);
3801 /* enable interrupts */
3802 tavarua_setup_interrupts(radio, state);
3803 /* default region is US */
3804 radio->region_params.band_low = US_LOW_BAND * FREQ_MUL;
3805 radio->region_params.band_high = US_HIGH_BAND * FREQ_MUL;
3806
3807 return 0;
3808}
3809
3810/*==============================================================
3811FUNCTION: tavarua_suspend
3812==============================================================*/
3813/**
3814 Save state and stop all devices in system.
3815
3816 @param pdev: platform device to be suspended.
3817 @param state: Power state to put each device in.
3818
3819 @return On success 0 is returned, else error code.
3820*/
3821static int tavarua_suspend(struct platform_device *pdev, pm_message_t state)
3822{
3823 struct tavarua_device *radio = platform_get_drvdata(pdev);
3824 int retval;
3825 int users = 0;
3826 printk(KERN_INFO DRIVER_NAME "%s: radio suspend\n\n", __func__);
3827 if (radio) {
Anantha Krishnana2f98082011-10-04 20:02:11 +05303828 users = atomic_read(&radio->users);
Anantha Krishnan71bea3c2011-11-15 07:36:49 +05303829 if (!users) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003830 retval = tavarua_disable_interrupts(radio);
3831 if (retval < 0) {
3832 printk(KERN_INFO DRIVER_NAME
3833 "tavarua_suspend error %d\n", retval);
3834 return -EIO;
3835 }
3836 }
3837 }
3838 return 0;
3839}
3840
3841/*==============================================================
3842FUNCTION: tavarua_resume
3843==============================================================*/
3844/**
3845 Restore state of each device in system.
3846
3847 @param pdev: platform device to be resumed.
3848
3849 @return On success 0 is returned, else error code.
3850*/
3851static int tavarua_resume(struct platform_device *pdev)
3852{
3853
3854 struct tavarua_device *radio = platform_get_drvdata(pdev);
3855 int retval;
3856 int users = 0;
3857 printk(KERN_INFO DRIVER_NAME "%s: radio resume\n\n", __func__);
3858 if (radio) {
Anantha Krishnana2f98082011-10-04 20:02:11 +05303859 users = atomic_read(&radio->users);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003860
Anantha Krishnan71bea3c2011-11-15 07:36:49 +05303861 if (!users) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003862 retval = tavarua_setup_interrupts(radio,
3863 (radio->registers[RDCTRL] & 0x03));
3864 if (retval < 0) {
3865 printk(KERN_INFO DRIVER_NAME "Error in \
3866 tavarua_resume %d\n", retval);
3867 return -EIO;
3868 }
3869 }
3870 }
3871 return 0;
3872}
3873
3874/*==============================================================
3875FUNCTION: tavarua_set_audio_path
3876==============================================================*/
3877/**
3878 This function will configure the audio path to and from the
3879 FM core.
3880
3881 This interface is expected to be called from the multimedia
3882 driver's thread. This interface should only be called when
3883 the FM hardware is enabled. If the FM hardware is not
3884 currently enabled, this interface will return an error.
3885
3886 @param digital_on: Digital audio from the FM core should be enabled/disbled.
3887 @param analog_on: Analog audio from the FM core should be enabled/disbled.
3888
3889 @return On success 0 is returned, else error code.
3890*/
3891int tavarua_set_audio_path(int digital_on, int analog_on)
3892{
3893 struct tavarua_device *radio = private_data;
3894 int rx_on = radio->registers[RDCTRL] & FM_RECV;
Venkateshwarlu Domakondab49c2cb2012-04-17 17:44:50 +05303895 int retval = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003896 if (!radio)
3897 return -ENOMEM;
3898 /* RX */
3899 FMDBG("%s: digital: %d analog: %d\n", __func__, digital_on, analog_on);
Venkateshwarlu Domakondab49c2cb2012-04-17 17:44:50 +05303900 if ((radio->pdata != NULL) && (radio->pdata->config_i2s_gpio != NULL)) {
3901 if (digital_on) {
3902 retval = radio->pdata->config_i2s_gpio(FM_I2S_ON);
3903 if (retval) {
3904 pr_err("%s: config_i2s_gpio failed\n",
3905 __func__);
3906 }
3907 } else {
3908 retval = radio->pdata->config_i2s_gpio(FM_I2S_OFF);
3909 if (retval) {
3910 pr_err("%s: config_i2s_gpio failed\n",
3911 __func__);
3912 }
3913 }
3914 }
3915
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003916 SET_REG_FIELD(radio->registers[AUDIOCTRL],
3917 ((rx_on && analog_on) ? 1 : 0),
3918 AUDIORX_ANALOG_OFFSET,
3919 AUDIORX_ANALOG_MASK);
3920 SET_REG_FIELD(radio->registers[AUDIOCTRL],
3921 ((rx_on && digital_on) ? 1 : 0),
3922 AUDIORX_DIGITAL_OFFSET,
3923 AUDIORX_DIGITAL_MASK);
3924 SET_REG_FIELD(radio->registers[AUDIOCTRL],
3925 (rx_on ? 0 : 1),
3926 AUDIOTX_OFFSET,
3927 AUDIOTX_MASK);
3928 /*
3929
3930 I2S Master/Slave configuration:
3931 Setting the FM SoC as I2S Master/Slave
3932 'false' - FM SoC is I2S Slave
3933 'true' - FM SoC is I2S Master
3934
3935 We get this infomation from the respective target's board file :
3936 MSM7x30 - FM SoC is I2S Slave
3937 MSM8x60 - FM SoC is I2S Slave
3938 MSM7x27A - FM SoC is I2S Master
3939 */
3940
3941 if (!radio->pdata->is_fm_soc_i2s_master) {
3942 FMDBG("FM SoC is I2S Slave\n");
3943 SET_REG_FIELD(radio->registers[AUDIOCTRL],
3944 (0),
3945 I2SCTRL_OFFSET,
3946 I2SCTRL_MASK);
3947 } else {
3948 FMDBG("FM SoC is I2S Master\n");
3949 SET_REG_FIELD(radio->registers[AUDIOCTRL],
3950 (1),
3951 I2SCTRL_OFFSET,
3952 I2SCTRL_MASK);
3953 }
3954 FMDBG("%s: %x\n", __func__, radio->registers[AUDIOCTRL]);
3955 return tavarua_write_register(radio, AUDIOCTRL,
3956 radio->registers[AUDIOCTRL]);
3957
3958}
3959
3960/*==============================================================
3961FUNCTION: tavarua_probe
3962==============================================================*/
3963/**
3964 Once called this functions initiates, allocates resources and registers video
3965 tuner device with the v4l2 framework.
3966
3967 NOTE:
3968 probe() should verify that the specified device hardware
3969 actually exists; sometimes platform setup code can't be sure. The probing
3970 can use device resources, including clocks, and device platform_data.
3971
3972 @param pdev: platform device to be probed.
3973
3974 @return On success 0 is returned, else error code.
3975 -ENOMEM in low memory cases
3976*/
3977static int __init tavarua_probe(struct platform_device *pdev)
3978{
3979
3980 struct marimba_fm_platform_data *tavarua_pdata;
3981 struct tavarua_device *radio;
3982 int retval;
3983 int i;
3984 FMDBG("%s: probe called\n", __func__);
3985 /* private data allocation */
3986 radio = kzalloc(sizeof(struct tavarua_device), GFP_KERNEL);
3987 if (!radio) {
3988 retval = -ENOMEM;
3989 goto err_initial;
3990 }
3991
3992 radio->marimba = platform_get_drvdata(pdev);
3993 tavarua_pdata = pdev->dev.platform_data;
3994 radio->pdata = tavarua_pdata;
3995 radio->dev = &pdev->dev;
3996 platform_set_drvdata(pdev, radio);
3997
3998 /* video device allocation */
3999 radio->videodev = video_device_alloc();
4000 if (!radio->videodev)
4001 goto err_radio;
4002
4003 /* initial configuration */
4004 memcpy(radio->videodev, &tavarua_viddev_template,
4005 sizeof(tavarua_viddev_template));
4006
4007 /*allocate internal buffers for decoded rds and event buffer*/
4008 for (i = 0; i < TAVARUA_BUF_MAX; i++) {
4009 int kfifo_alloc_rc=0;
4010 spin_lock_init(&radio->buf_lock[i]);
4011
4012 if (i == TAVARUA_BUF_RAW_RDS)
4013 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
4014 rds_buf*3, GFP_KERNEL);
Srinivasa Rao Uppalad09f24a2012-01-13 19:10:39 +05304015 else if (i == TAVARUA_BUF_RT_RDS)
4016 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
4017 STD_BUF_SIZE * 2, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004018 else
4019 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
4020 STD_BUF_SIZE, GFP_KERNEL);
4021
4022 if (kfifo_alloc_rc!=0) {
4023 printk(KERN_ERR "%s: failed allocating buffers %d\n",
4024 __func__, kfifo_alloc_rc);
4025 goto err_bufs;
4026 }
4027 }
Anantha Krishnana2f98082011-10-04 20:02:11 +05304028 /* initializing the device count */
4029 atomic_set(&radio->users, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004030 radio->xfr_in_progress = 0;
4031 radio->xfr_bytes_left = 0;
4032 for (i = 0; i < TAVARUA_XFR_MAX; i++)
4033 radio->pending_xfrs[i] = 0;
4034
4035 /* init transmit data */
4036 radio->tx_mode = TAVARUA_TX_RT;
4037 /* Init RT and PS Tx datas*/
4038 radio->pty = 0;
4039 radio->pi = 0;
4040 radio->ps_repeatcount = 0;
4041 /* init search params */
4042 radio->srch_params.srch_pty = 0;
4043 radio->srch_params.srch_pi = 0;
4044 radio->srch_params.preset_num = 0;
4045 radio->srch_params.get_list = 0;
4046 /* radio initializes to low power mode */
4047 radio->lp_mode = 1;
4048 radio->handle_irq = 1;
4049 /* init lock */
4050 mutex_init(&radio->lock);
4051 /* init completion flags */
4052 init_completion(&radio->sync_xfr_start);
4053 init_completion(&radio->sync_req_done);
4054 radio->tune_req = 0;
4055 /* initialize wait queue for event read */
4056 init_waitqueue_head(&radio->event_queue);
4057 /* initialize wait queue for raw rds read */
4058 init_waitqueue_head(&radio->read_queue);
4059
4060 video_set_drvdata(radio->videodev, radio);
4061 /*Start the worker thread for event handling and register read_int_stat
4062 as worker function*/
Taniya Das9ac855f2012-02-09 18:05:21 +05304063 radio->wqueue = create_singlethread_workqueue("kfmradio");
4064 if (!radio->wqueue)
4065 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004066
4067 /* register video device */
4068 if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
4069 printk(KERN_WARNING DRIVER_NAME
4070 ": Could not register video device\n");
4071 goto err_all;
4072 }
4073 private_data = radio;
4074 return 0;
4075
4076err_all:
4077 video_device_release(radio->videodev);
4078err_bufs:
4079 for (; i > -1; i--)
4080 kfifo_free(&radio->data_buf[i]);
4081err_radio:
4082 kfree(radio);
4083err_initial:
4084 return retval;
4085}
4086
4087/*==============================================================
4088FUNCTION: tavarua_remove
4089==============================================================*/
4090/**
4091 Removes the device.
4092
4093 @param pdev: platform device to be removed.
4094
4095 @return On success 0 is returned, else error code.
4096*/
4097static int __devexit tavarua_remove(struct platform_device *pdev)
4098{
4099 int i;
4100 struct tavarua_device *radio = platform_get_drvdata(pdev);
4101
4102 /* disable irq */
4103 tavarua_disable_irq(radio);
4104
Taniya Das9ac855f2012-02-09 18:05:21 +05304105 destroy_workqueue(radio->wqueue);
4106
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004107 video_unregister_device(radio->videodev);
4108
4109 /* free internal buffers */
4110 for (i = 0; i < TAVARUA_BUF_MAX; i++)
4111 kfifo_free(&radio->data_buf[i]);
4112
4113 /* free state struct */
4114 kfree(radio);
4115
4116 platform_set_drvdata(pdev, NULL);
4117
4118 return 0;
4119}
4120
4121/*
4122 Platform drivers follow the standard driver model convention, where
4123 discovery/enumeration is handled outside the drivers, and drivers
4124 provide probe() and remove() methods. They support power management
4125 and shutdown notifications using the standard conventions.
4126*/
4127static struct platform_driver tavarua_driver = {
4128 .driver = {
4129 .owner = THIS_MODULE,
4130 .name = "marimba_fm",
4131 },
4132 .remove = __devexit_p(tavarua_remove),
4133 .suspend = tavarua_suspend,
4134 .resume = tavarua_resume,
4135}; /* platform device we're adding */
4136
4137
4138/*************************************************************************
4139 * Module Interface
4140 ************************************************************************/
4141
4142/*==============================================================
4143FUNCTION: radio_module_init
4144==============================================================*/
4145/**
4146 Module entry - add a platform-level device.
4147
4148 @return Returns zero if the driver registered and bound to a device, else
4149 returns a negative error code when the driver not registered.
4150*/
4151static int __init radio_module_init(void)
4152{
4153 printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n");
4154 return platform_driver_probe(&tavarua_driver, tavarua_probe);
4155}
4156
4157/*==============================================================
4158FUNCTION: radio_module_exit
4159==============================================================*/
4160/**
4161 Module exit - removes a platform-level device.
4162
4163 NOTE:
4164 Note that this function will also release all memory- and port-based
4165 resources owned by the device (dev->resource).
4166
4167 @return none.
4168*/
4169static void __exit radio_module_exit(void)
4170{
4171 platform_driver_unregister(&tavarua_driver);
4172}
4173
4174MODULE_LICENSE("GPL v2");
4175MODULE_AUTHOR(DRIVER_AUTHOR);
4176MODULE_DESCRIPTION(DRIVER_DESC);
4177MODULE_VERSION(DRIVER_VERSION);
4178
4179module_init(radio_module_init);
4180module_exit(radio_module_exit);
4181