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