blob: 8f09b6a85ca1cf1b3d92c01e1d6cda76488cfa2a [file] [log] [blame]
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13/*
14 * Qualcomm Tavarua FM core driver
15 */
16
17/* driver definitions */
18#define DRIVER_AUTHOR "Qualcomm"
19#define DRIVER_NAME "radio-tavarua"
20#define DRIVER_CARD "Qualcomm FM Radio Transceiver"
21#define DRIVER_DESC "I2C radio driver for Qualcomm FM Radio Transceiver "
22#define DRIVER_VERSION "1.0.0"
23
24#include <linux/version.h>
25#include <linux/init.h> /* Initdata */
26#include <linux/delay.h> /* udelay */
27#include <linux/uaccess.h> /* copy to/from user */
28#include <linux/kfifo.h> /* lock free circular buffer */
29#include <linux/param.h>
30#include <linux/i2c.h>
31#include <linux/irq.h>
32#include <linux/interrupt.h>
33
34/* kernel includes */
35#include <linux/kernel.h>
36#include <linux/module.h>
37#include <linux/version.h>
38#include <linux/videodev2.h>
39#include <linux/mutex.h>
40#include <media/v4l2-common.h>
41#include <asm/unaligned.h>
42#include <media/v4l2-ioctl.h>
43#include <linux/unistd.h>
44#include <asm/atomic.h>
45#include <media/tavarua.h>
46#include <linux/mfd/marimba.h>
47#include <linux/platform_device.h>
48#include <linux/workqueue.h>
49#include <linux/slab.h>
50/*
51regional parameters for radio device
52*/
53struct region_params_t {
54 enum tavarua_region_t region;
55 unsigned int band_high;
56 unsigned int band_low;
57 char emphasis;
58 char rds_std;
59 char spacing;
60};
61
62struct srch_params_t {
63 unsigned short srch_pi;
64 unsigned char srch_pty;
65 unsigned int preset_num;
66 int get_list;
67};
68
69/* Main radio device structure,
70acts as a shadow copy of the
71actual tavaura registers */
72struct tavarua_device {
73 struct video_device *videodev;
74 /* driver management */
Anantha Krishnana2f98082011-10-04 20:02:11 +053075 atomic_t users;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070076 /* top level driver data */
77 struct marimba *marimba;
78 struct device *dev;
79 /* platform specific functionality */
80 struct marimba_fm_platform_data *pdata;
81 unsigned int chipID;
82 /*RDS buffers + Radio event buffer*/
83 struct kfifo data_buf[TAVARUA_BUF_MAX];
84 /* search paramters */
85 struct srch_params_t srch_params;
86 /* keep track of pending xfrs */
87 int pending_xfrs[TAVARUA_XFR_MAX];
88 int xfr_bytes_left;
89 int xfr_in_progress;
90 /* Transmit data */
91 enum tavarua_xfr_ctrl_t tx_mode;
92 /* synchrnous xfr data */
93 unsigned char sync_xfr_regs[XFR_REG_NUM];
94 struct completion sync_xfr_start;
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 */
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301419 if (region == TAVARUA_REGION_JAPAN)
1420 SET_REG_FIELD(radio->registers[RDCTRL], 1,
1421 RDCTRL_BAND_OFFSET, RDCTRL_BAND_MASK);
1422 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001423 SET_REG_FIELD(radio->registers[RDCTRL], 0,
1424 RDCTRL_BAND_OFFSET, RDCTRL_BAND_MASK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001425
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001426 /* Set De-emphasis and soft band range*/
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301427 SET_REG_FIELD(radio->registers[RDCTRL], radio->region_params.emphasis,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001428 RDCTRL_DEEMPHASIS_OFFSET, RDCTRL_DEEMPHASIS_MASK);
1429
1430 /* set RDS standard */
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301431 SET_REG_FIELD(radio->registers[RDSCTRL], radio->region_params.rds_std,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001432 RDSCTRL_STANDARD_OFFSET, RDSCTRL_STANDARD_MASK);
1433
1434 FMDBG("RDSCTRLL %x\n", radio->registers[RDSCTRL]);
1435 retval = tavarua_write_register(radio, RDSCTRL,
1436 radio->registers[RDSCTRL]);
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301437 if (retval < 0) {
1438 FMDERR("Failed to set RDS/RBDS standard\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439 return retval;
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301440 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001441
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301442 /* Set the lower and upper band limits*/
1443 retval = sync_read_xfr(radio, RADIO_CONFIG, xfr_buf);
1444 if (retval < 0) {
1445 FMDERR("failed to get RADIO_CONFIG\n");
1446 return retval;
1447 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001448
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301449 band_low = (radio->region_params.band_low -
1450 low_band_limit) / spacing;
1451 band_high = (radio->region_params.band_high -
1452 low_band_limit) / spacing;
1453
1454 xfr_buf[0] = RSH_DATA(band_low, 8);
1455 xfr_buf[1] = GET_ABS_VAL(band_low);
1456 xfr_buf[2] = RSH_DATA(band_high, 8);
1457 xfr_buf[3] = GET_ABS_VAL(band_high);
1458 retval = sync_write_xfr(radio, RADIO_CONFIG, xfr_buf);
1459 if (retval < 0) {
1460 FMDERR("Could not set regional settings\n");
1461 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001462 }
1463 radio->region_params.region = region;
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301464
1465 /* Check for the FM Algorithm used */
1466 if (radio->enable_optimized_srch_alg) {
1467 FMDBG("Optimized Srch Algorithm!!!");
1468 optimized_search_algorithm(radio, region);
1469 } else {
1470 FMDBG("Native Srch Algorithm!!!");
1471 /* Enable/Disable the 200KHz enforcer */
1472 switch (region) {
1473 case TAVARUA_REGION_US:
1474 if (adie_type_bahma) {
1475 FMDBG("Adie type : Bahama\n");
1476 /*Enable the 200KHz enforcer*/
1477 retval = tavarua_read_registers(radio,
1478 ADVCTRL, 1);
1479 if (retval >= 0) {
1480 rdsMask = radio->registers[ADVCTRL];
1481 SET_REG_FIELD(rdsMask, ENF_SRCH200khz,
1482 SRCH200KHZ_OFFSET, SRCH_MASK);
1483 retval = tavarua_write_register(radio,
1484 ADVCTRL, rdsMask);
1485 } else
1486 return retval;
1487 } /* if Marimba do nothing */
1488 break;
1489 case TAVARUA_REGION_EU:
1490 case TAVARUA_REGION_JAPAN:
1491 case TAVARUA_REGION_JAPAN_WIDE:
1492 default:
1493 if (adie_type_bahma) {
1494 FMDBG("Adie type : Bahama\n");
1495 /*
1496 Disable 200KHz enforcer for all 100/50 KHz
1497 spaced regions.
1498 */
1499 retval = tavarua_read_registers(radio,
1500 ADVCTRL, 1);
1501 if (retval >= 0) {
1502 rdsMask = radio->registers[ADVCTRL];
1503 SET_REG_FIELD(rdsMask, NO_SRCH200khz,
1504 SRCH200KHZ_OFFSET, SRCH_MASK);
1505 retval = tavarua_write_register(radio,
1506 ADVCTRL, rdsMask);
1507 } else
1508 return retval;
1509 } /* if Marimba do nothing */
1510 break;
1511 }
1512
1513 /* Set channel spacing */
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301514 if (region == TAVARUA_REGION_US) {
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301515 if (adie_type_bahma) {
1516 FMDBG("Adie type : Bahama\n");
1517 /*
1518 Configuring all 200KHZ spaced regions as
1519 100KHz due to change in the new Bahma
1520 FM SoC search algorithm.
1521 */
1522 value = FM_CH_SPACE_100KHZ;
1523 } else {
1524 FMDBG("Adie type : Marimba\n");
1525 value = FM_CH_SPACE_200KHZ;
1526 }
Anantha Krishnan29f1d932011-12-29 21:17:29 +05301527 } else {
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301528 /*
1529 Set the channel spacing as configured from
1530 the upper layers.
1531 */
1532 value = radio->region_params.spacing;
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301533 }
Anantha Krishnan40bcd052011-12-05 15:28:29 +05301534 SET_REG_FIELD(radio->registers[RDCTRL], value,
1535 RDCTRL_CHSPACE_OFFSET, RDCTRL_CHSPACE_MASK);
1536
1537 }
1538
1539 /* Write the config values into RDCTL register */
1540 FMDBG("RDCTRL: %x\n", radio->registers[RDCTRL]);
1541 retval = tavarua_write_register(radio, RDCTRL,
1542 radio->registers[RDCTRL]);
1543 if (retval < 0) {
1544 FMDERR("Could not set region in rdctrl\n");
1545 return retval;
1546 }
1547
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001548 return retval;
1549}
1550
1551/*=============================================================================
1552FUNCTION: tavarua_get_freq
1553=============================================================================*/
1554/**
1555 This interface gets the current frequency.
1556
1557 @param radio: structure pointer passed by client.
1558 @param freq: struct v4l2_frequency. This will be set to the resultant
1559 frequency in units of 62.5 kHz on success.
1560
1561 NOTE:
1562 To get the current tuner or modulator radio frequency applications set the
1563 tuner field of a struct v4l2_frequency to the respective tuner or modulator
1564 number (only input devices have tuners, only output devices have modulators),
1565 zero out the reserved array and call the VIDIOC_G_FREQUENCY ioctl with a
1566 pointer to this structure. The driver stores the current frequency in the
1567 frequency field.
1568
1569 Tuning frequency is in units of 62.5 kHz, or if the struct v4l2_tuner or
1570 struct v4l2_modulator capabilities flag V4L2_TUNER_CAP_LOW is set, in
1571 units of 62.5 Hz.
1572
1573 @return => 0 if successful.
1574 @return < 0 if failure.
1575*/
1576static int tavarua_get_freq(struct tavarua_device *radio,
1577 struct v4l2_frequency *freq)
1578{
1579 int retval;
1580 unsigned short chan;
1581 unsigned int band_bottom;
1582 unsigned int spacing;
1583 band_bottom = radio->region_params.band_low;
1584 spacing = 0.100 * FREQ_MUL;
1585 /* read channel */
1586 retval = tavarua_read_registers(radio, FREQ, 2);
1587 chan = radio->registers[FREQ];
1588
1589 /* Frequency (MHz) = 100 (kHz) x Channel + Bottom of Band (MHz) */
1590 freq->frequency = spacing * chan + band_bottom;
1591 if (radio->registers[TUNECTRL] & ADD_OFFSET)
1592 freq->frequency += 800;
1593 return retval;
1594}
1595
1596/*=============================================================================
1597FUNCTION: tavarua_set_freq
1598=============================================================================*/
1599/**
1600 This interface sets the current frequency.
1601
1602 @param radio: structure pointer passed by client.
1603 @param freq: desired frequency sent by the client in 62.5 kHz units.
1604
1605 NOTE:
1606 To change the current tuner or modulator radio frequency, applications
1607 initialize the tuner, type and frequency fields, and the reserved array of a
1608 struct v4l2_frequency and call the VIDIOC_S_FREQUENCY ioctl with a pointer to
1609 this structure. When the requested frequency is not possible the driver
1610 assumes the closest possible value. However VIDIOC_S_FREQUENCY is a
1611 write-only ioctl, it does not return the actual new frequency.
1612
1613 Tuning frequency is in units of 62.5 kHz, or if the struct v4l2_tuner
1614 or struct v4l2_modulator capabilities flag V4L2_TUNER_CAP_LOW is set,
1615 in units of 62.5 Hz.
1616
1617 @return => 0 if successful.
1618 @return < 0 if failure.
1619*/
1620static int tavarua_set_freq(struct tavarua_device *radio, unsigned int freq)
1621{
1622
1623 unsigned int band_bottom;
1624 unsigned char chan;
1625 unsigned char cmd[] = {0x00, 0x00};
1626 unsigned int spacing;
1627 int retval;
1628 band_bottom = radio->region_params.band_low;
1629 spacing = 0.100 * FREQ_MUL;
1630 if ((freq % 1600) == 800) {
1631 cmd[1] = ADD_OFFSET;
1632 freq -= 800;
1633 }
1634 /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / 100 (kHz) */
1635 chan = (freq - band_bottom) / spacing;
1636
1637 cmd[0] = chan;
1638 cmd[1] |= TUNE_STATION;
1639 radio->tune_req = 1;
1640 retval = tavarua_write_registers(radio, FREQ, cmd, 2);
1641 if (retval < 0)
1642 radio->tune_req = 0;
1643 return retval;
1644
1645}
1646
1647/**************************************************************************
1648 * File Operations Interface
1649 *************************************************************************/
1650
1651/*=============================================================================
1652FUNCTION: tavarua_fops_read
1653=============================================================================*/
1654/**
1655 This function is called when a process, which already opened the dev file,
1656 attempts to read from it.
1657
1658 In case of tavarua driver, it is called to read RDS data.
1659
1660 @param file: file descriptor.
1661 @param buf: The buffer to fill with data.
1662 @param count: The length of the buffer in bytes.
1663 @param ppos: Our offset in the file.
1664
1665 @return The number of bytes put into the buffer on sucess.
1666 -EFAULT if there is no access to user buffer
1667*/
1668static ssize_t tavarua_fops_read(struct file *file, char __user *buf,
1669 size_t count, loff_t *ppos)
1670{
1671 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
1672 struct kfifo *rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
1673
1674 /* block if no new data available */
1675 while (!kfifo_len(rds_buf)) {
1676 if (file->f_flags & O_NONBLOCK)
1677 return -EWOULDBLOCK;
1678 if (wait_event_interruptible(radio->read_queue,
1679 kfifo_len(rds_buf)) < 0)
1680 return -EINTR;
1681 }
1682
1683 /* calculate block count from byte count */
1684 count /= BYTES_PER_BLOCK;
1685
1686
1687 /* check if we can write to the user buffer */
1688 if (!access_ok(VERIFY_WRITE, buf, count*BYTES_PER_BLOCK))
1689 return -EFAULT;
1690
1691 /* copy RDS block out of internal buffer and to user buffer */
1692 return kfifo_out_locked(rds_buf, buf, count*BYTES_PER_BLOCK,
1693 &radio->buf_lock[TAVARUA_BUF_RAW_RDS]);
1694}
1695
1696/*=============================================================================
1697FUNCTION: tavarua_fops_write
1698=============================================================================*/
1699/**
1700 This function is called when a process, which already opened the dev file,
1701 attempts to write to it.
1702
1703 In case of tavarua driver, it is called to write RDS data to host.
1704
1705 @param file: file descriptor.
1706 @param buf: The buffer which has data to write.
1707 @param count: The length of the buffer.
1708 @param ppos: Our offset in the file.
1709
1710 @return The number of bytes written from the buffer.
1711*/
1712static ssize_t tavarua_fops_write(struct file *file, const char __user *data,
1713 size_t count, loff_t *ppos)
1714{
1715 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
1716 int retval = 0;
1717 int bytes_to_copy;
1718 int bytes_copied = 0;
1719 int bytes_left;
1720 int chunk_index = 0;
1721 unsigned char tx_data[XFR_REG_NUM];
1722 /* Disable TX of this type first */
1723 switch (radio->tx_mode) {
1724 case TAVARUA_TX_RT:
1725 bytes_left = min((int)count, MAX_RT_LENGTH);
1726 tx_data[1] = 0;
1727 break;
1728 case TAVARUA_TX_PS:
1729 bytes_left = min((int)count, MAX_PS_LENGTH);
1730 tx_data[4] = 0;
1731 break;
1732 default:
1733 FMDERR("%s: Unknown TX mode\n", __func__);
1734 return -1;
1735 }
1736 retval = sync_write_xfr(radio, radio->tx_mode, tx_data);
1737 if (retval < 0)
1738 return retval;
1739
1740 /* send payload to FM hardware */
1741 while (bytes_left) {
1742 chunk_index++;
1743 bytes_to_copy = min(bytes_left, XFR_REG_NUM);
1744 if (copy_from_user(tx_data, data + bytes_copied, bytes_to_copy))
1745 return -EFAULT;
1746 retval = sync_write_xfr(radio, radio->tx_mode +
1747 chunk_index, tx_data);
1748 if (retval < 0)
1749 return retval;
1750
1751 bytes_copied += bytes_to_copy;
1752 bytes_left -= bytes_to_copy;
1753 }
1754
1755 /* send the header */
1756 switch (radio->tx_mode) {
1757 case TAVARUA_TX_RT:
1758 FMDBG("Writing RT header\n");
1759 tx_data[0] = bytes_copied;
1760 tx_data[1] = TX_ON | 0x03; /* on | PTY */
1761 tx_data[2] = 0x12; /* PI high */
1762 tx_data[3] = 0x34; /* PI low */
1763 break;
1764 case TAVARUA_TX_PS:
1765 FMDBG("Writing PS header\n");
1766 tx_data[0] = chunk_index;
1767 tx_data[1] = 0x03; /* PTY */
1768 tx_data[2] = 0x12; /* PI high */
1769 tx_data[3] = 0x34; /* PI low */
1770 tx_data[4] = TX_ON | 0x01;
1771 break;
1772 default:
1773 FMDERR("%s: Unknown TX mode\n", __func__);
1774 return -1;
1775 }
1776 retval = sync_write_xfr(radio, radio->tx_mode, tx_data);
1777 if (retval < 0)
1778 return retval;
1779 FMDBG("done writing: %d\n", retval);
1780 return bytes_copied;
1781}
1782
1783/*=============================================================================
1784FUNCTION: tavarua_fops_open
1785=============================================================================*/
1786/**
1787 This function is called when a process tries to open the device file, like
1788 "cat /dev/mycharfile"
1789
1790 @param file: file descriptor.
1791
1792 @return => 0 if successful.
1793 @return < 0 if failure.
1794*/
1795static int tavarua_fops_open(struct file *file)
1796{
1797 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
1798 int retval = -ENODEV;
1799 unsigned char value;
1800 /* FM core bring up */
1801 int i = 0;
1802 char fm_ctl0_part1[] = { 0xCA, 0xCE, 0xD6 };
1803 char fm_ctl1[] = { 0x03 };
1804 char fm_ctl0_part2[] = { 0xB6, 0xB7 };
1805 char buffer[] = {0x00, 0x48, 0x8A, 0x8E, 0x97, 0xB7};
1806 int bahama_present = -ENODEV;
1807
Anantha Krishnana2f98082011-10-04 20:02:11 +05301808 if (!atomic_dec_and_test(&radio->users)) {
1809 pr_err("%s: Device already in use."
1810 "Try again later", __func__);
1811 atomic_inc(&radio->users);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001812 return -EBUSY;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001813 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001814
1815 /* initial gpio pin config & Power up */
1816 retval = radio->pdata->fm_setup(radio->pdata);
1817 if (retval) {
1818 printk(KERN_ERR "%s: failed config gpio & pmic\n", __func__);
1819 goto open_err_setup;
1820 }
1821 if (radio->pdata->config_i2s_gpio != NULL) {
1822 retval = radio->pdata->config_i2s_gpio(FM_I2S_ON);
1823 if (retval) {
1824 printk(KERN_ERR "%s: failed config gpio\n", __func__);
1825 goto config_i2s_err;
1826 }
1827 }
1828 /* enable irq */
1829 retval = tavarua_request_irq(radio);
1830 if (retval < 0) {
1831 printk(KERN_ERR "%s: failed to request irq\n", __func__);
1832 goto open_err_req_irq;
1833 }
1834 /* call top level marimba interface here to enable FM core */
1835 FMDBG("initializing SoC\n");
1836
1837 bahama_present = is_bahama();
1838
1839 if (bahama_present == -ENODEV)
1840 return -ENODEV;
1841
1842 if (bahama_present)
1843 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
1844 else
1845 radio->marimba->mod_id = MARIMBA_SLAVE_ID_MARIMBA;
1846
1847 value = FM_ENABLE;
1848 retval = marimba_write_bit_mask(radio->marimba,
1849 MARIMBA_XO_BUFF_CNTRL, &value, 1, value);
1850 if (retval < 0) {
1851 printk(KERN_ERR "%s:XO_BUFF_CNTRL write failed\n",
1852 __func__);
1853 goto open_err_all;
1854 }
1855
1856
1857 /* Bring up FM core */
1858 if (bahama_present) {
1859
1860 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
1861 /* Read the Bahama version*/
1862 retval = marimba_read_bit_mask(radio->marimba,
1863 0x00, &bahama_version, 1, 0x1F);
1864 if (retval < 0) {
1865 printk(KERN_ERR "%s: version read failed",
1866 __func__);
1867 goto open_err_all;
1868 }
Rahul Kashyapc88b6e32011-07-07 10:52:16 +05301869
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001870 /* Check for Bahama V2 variant*/
1871 if (bahama_version == 0x09) {
1872
1873 /* In case of Bahama v2, forcefully enable the
1874 * internal analog and digital voltage controllers
1875 */
1876 value = 0x06;
1877 /* value itself used as mask in these writes*/
1878 retval = marimba_write_bit_mask(radio->marimba,
1879 BAHAMA_LDO_DREG_CTL0, &value, 1, value);
1880 if (retval < 0) {
1881 printk(KERN_ERR "%s:0xF0 write failed\n",
1882 __func__);
1883 goto open_err_all;
1884 }
1885 value = 0x86;
1886 retval = marimba_write_bit_mask(radio->marimba,
1887 BAHAMA_LDO_AREG_CTL0, &value, 1, value);
1888 if (retval < 0) {
1889 printk(KERN_ERR "%s:0xF4 write failed\n",
1890 __func__);
1891 goto open_err_all;
1892 }
1893 }
1894
1895 /*write FM mode*/
1896 retval = tavarua_write_register(radio, BAHAMA_FM_MODE_REG,
1897 BAHAMA_FM_MODE_NORMAL);
1898 if (retval < 0) {
1899 printk(KERN_ERR "failed to set the FM mode: %d\n",
1900 retval);
1901 goto open_err_all;
1902 }
1903 /*Write first sequence of bytes to FM_CTL0*/
1904 for (i = 0; i < 3; i++) {
1905 retval = tavarua_write_register(radio,
1906 BAHAMA_FM_CTL0_REG, fm_ctl0_part1[i]);
1907 if (retval < 0) {
1908 printk(KERN_ERR "FM_CTL0:set-1 failure: %d\n",
1909 retval);
1910 goto open_err_all;
1911 }
1912 }
1913 /*Write the FM_CTL1 sequence*/
1914 for (i = 0; i < 1; i++) {
1915 retval = tavarua_write_register(radio,
1916 BAHAMA_FM_CTL1_REG, fm_ctl1[i]);
1917 if (retval < 0) {
1918 printk(KERN_ERR "FM_CTL1 write failure: %d\n",
1919 retval);
1920 goto open_err_all;
1921 }
1922 }
1923 /*Write second sequence of bytes to FM_CTL0*/
1924 for (i = 0; i < 2; i++) {
1925 retval = tavarua_write_register(radio,
1926 BAHAMA_FM_CTL0_REG, fm_ctl0_part2[i]);
1927 if (retval < 0) {
1928 printk(KERN_ERR "FM_CTL0:set-2 failure: %d\n",
1929 retval);
1930 goto open_err_all;
1931 }
1932 }
1933 } else {
1934 retval = tavarua_write_registers(radio, LEAKAGE_CNTRL,
1935 buffer, 6);
1936 if (retval < 0) {
1937 printk(KERN_ERR "%s: failed to bring up FM Core\n",
1938 __func__);
1939 goto open_err_all;
1940 }
1941 }
1942 /* Wait for interrupt i.e. complete(&radio->sync_req_done); call */
1943 /*Initialize the completion variable for
1944 for the proper behavior*/
1945 init_completion(&radio->sync_req_done);
1946 if (!wait_for_completion_timeout(&radio->sync_req_done,
1947 msecs_to_jiffies(wait_timeout))) {
1948 retval = -1;
1949 FMDERR("Timeout waiting for initialization\n");
1950 }
1951
1952 /* get Chip ID */
1953 retval = tavarua_write_register(radio, XFRCTRL, CHIPID);
1954 if (retval < 0)
1955 goto open_err_all;
1956 msleep(TAVARUA_DELAY);
1957 tavarua_read_registers(radio, XFRCTRL, XFR_REG_NUM+1);
1958 if (radio->registers[XFRCTRL] != CHIPID)
1959 goto open_err_all;
1960
1961 radio->chipID = (radio->registers[XFRCTRL+2] << 24) |
1962 (radio->registers[XFRCTRL+5] << 16) |
1963 (radio->registers[XFRCTRL+6] << 8) |
1964 (radio->registers[XFRCTRL+7]);
1965
1966 printk(KERN_WARNING DRIVER_NAME ": Chip ID %x\n", radio->chipID);
1967 if (radio->chipID == MARIMBA_A0) {
1968 printk(KERN_WARNING DRIVER_NAME ": Unsupported hardware: %x\n",
1969 radio->chipID);
1970 retval = -1;
1971 goto open_err_all;
1972 }
1973
1974 radio->handle_irq = 0;
1975 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
1976 marimba_set_fm_status(radio->marimba, true);
1977 return 0;
1978
1979
1980open_err_all:
1981 /*Disable FM in case of error*/
1982 value = 0x00;
1983 marimba_write_bit_mask(radio->marimba, MARIMBA_XO_BUFF_CNTRL,
1984 &value, 1, value);
1985 tavarua_disable_irq(radio);
1986open_err_req_irq:
1987 if (radio->pdata->config_i2s_gpio != NULL)
1988 radio->pdata->config_i2s_gpio(FM_I2S_OFF);
1989config_i2s_err:
1990 radio->pdata->fm_shutdown(radio->pdata);
1991open_err_setup:
1992 radio->handle_irq = 1;
Anantha Krishnana2f98082011-10-04 20:02:11 +05301993 atomic_inc(&radio->users);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001994 return retval;
1995}
1996
1997/*=============================================================================
1998FUNCTION: tavarua_fops_release
1999=============================================================================*/
2000/**
2001 This function is called when a process closes the device file.
2002
2003 @param file: file descriptor.
2004
2005 @return => 0 if successful.
2006 @return < 0 if failure.
2007*/
2008static int tavarua_fops_release(struct file *file)
2009{
2010 int retval;
2011 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2012 unsigned char value;
2013 int i = 0;
2014 /*FM Core shutdown sequence for Bahama*/
2015 char fm_ctl0_part1[] = { 0xB7 };
2016 char fm_ctl1[] = { 0x03 };
2017 char fm_ctl0_part2[] = { 0x9F, 0x48, 0x02 };
2018 int bahama_present = -ENODEV;
2019 /*FM Core shutdown sequence for Marimba*/
2020 char buffer[] = {0x18, 0xB7, 0x48};
2021 bool bt_status = false;
2022 int index;
2023 /* internal regulator controllers DREG_CTL0, AREG_CTL0
2024 * has to be kept in the valid state based on the bt status.
2025 * 1st row is the state when no clients are active,
2026 * and the second when bt is in on state.
2027 */
2028 char internal_vreg_ctl[2][2] = {
2029 { 0x04, 0x84 },
2030 { 0x00, 0x80 }
2031 };
2032
Anantha Krishnana2f98082011-10-04 20:02:11 +05302033 if (!radio) {
2034 pr_err("%s: Radio device not available...", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002035 return -ENODEV;
Anantha Krishnana2f98082011-10-04 20:02:11 +05302036 }
2037
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002038 FMDBG("In %s", __func__);
2039
2040 /* disable radio ctrl */
2041 retval = tavarua_write_register(radio, RDCTRL, 0x00);
2042
2043 FMDBG("%s, Disable IRQs\n", __func__);
2044 /* disable irq */
2045 retval = tavarua_disable_irq(radio);
2046 if (retval < 0) {
2047 printk(KERN_ERR "%s: failed to disable irq\n", __func__);
2048 return retval;
2049 }
2050
2051 bahama_present = is_bahama();
2052
2053 if (bahama_present == -ENODEV)
2054 return -ENODEV;
2055
2056 if (bahama_present) {
2057 /*Write first sequence of bytes to FM_CTL0*/
2058 for (i = 0; i < 1; i++) {
2059 retval = tavarua_write_register(radio,
2060 BAHAMA_FM_CTL0_REG, fm_ctl0_part1[i]);
2061 if (retval < 0) {
2062 printk(KERN_ERR "FM_CTL0:Set-1 failure: %d\n",
2063 retval);
2064 break;
2065 }
2066 }
2067 /*Write the FM_CTL1 sequence*/
2068 for (i = 0; i < 1; i++) {
2069 retval = tavarua_write_register(radio,
2070 BAHAMA_FM_CTL1_REG, fm_ctl1[i]);
2071 if (retval < 0) {
2072 printk(KERN_ERR "FM_CTL1 failure: %d\n",
2073 retval);
2074 break;
2075 }
2076 }
2077 /*Write second sequence of bytes to FM_CTL0*/
2078 for (i = 0; i < 3; i++) {
2079 retval = tavarua_write_register(radio,
2080 BAHAMA_FM_CTL0_REG, fm_ctl0_part2[i]);
2081 if (retval < 0) {
2082 printk(KERN_ERR "FM_CTL0:Set-2 failure: %d\n",
2083 retval);
2084 break;
2085 }
2086 }
2087 } else {
2088
2089 retval = tavarua_write_registers(radio, FM_CTL0,
2090 buffer, sizeof(buffer)/sizeof(buffer[0]));
2091 if (retval < 0) {
2092 printk(KERN_ERR "%s: failed to bring down the FM Core\n",
2093 __func__);
2094 return retval;
2095 }
2096 }
2097 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
2098 bt_status = marimba_get_bt_status(radio->marimba);
2099 /* Set the index based on the bt status*/
2100 index = bt_status ? 1 : 0;
2101 /* Check for Bahama's existance and Bahama V2 variant*/
2102 if (bahama_present && (bahama_version == 0x09)) {
2103 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
2104 /* actual value itself used as mask*/
2105 retval = marimba_write_bit_mask(radio->marimba,
2106 BAHAMA_LDO_DREG_CTL0, &internal_vreg_ctl[bt_status][0],
2107 1, internal_vreg_ctl[index][0]);
2108 if (retval < 0) {
2109 printk(KERN_ERR "%s:0xF0 write failed\n", __func__);
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302110 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002111 }
2112 /* actual value itself used as mask*/
2113 retval = marimba_write_bit_mask(radio->marimba,
2114 BAHAMA_LDO_AREG_CTL0, &internal_vreg_ctl[bt_status][1],
2115 1, internal_vreg_ctl[index][1]);
2116 if (retval < 0) {
2117 printk(KERN_ERR "%s:0xF4 write failed\n", __func__);
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302118 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002119 }
2120 } else {
2121 /* disable fm core */
2122 radio->marimba->mod_id = MARIMBA_SLAVE_ID_MARIMBA;
2123 }
2124
2125 value = 0x00;
2126 retval = marimba_write_bit_mask(radio->marimba, MARIMBA_XO_BUFF_CNTRL,
2127 &value, 1, FM_ENABLE);
2128 if (retval < 0) {
2129 printk(KERN_ERR "%s:XO_BUFF_CNTRL write failed\n", __func__);
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302130 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002131 }
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302132exit:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002133 FMDBG("%s, Calling fm_shutdown\n", __func__);
2134 /* teardown gpio and pmic */
Rahul Kashyapc88b6e32011-07-07 10:52:16 +05302135
2136 marimba_set_fm_status(radio->marimba, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002137 radio->pdata->fm_shutdown(radio->pdata);
2138 if (radio->pdata->config_i2s_gpio != NULL)
2139 radio->pdata->config_i2s_gpio(FM_I2S_OFF);
2140 radio->handle_irq = 1;
Anantha Krishnana2f98082011-10-04 20:02:11 +05302141 atomic_inc(&radio->users);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002142 radio->marimba->mod_id = SLAVE_ID_BAHAMA;
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302143 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002144}
2145
2146/*
2147 * tavarua_fops - file operations interface
2148 */
2149static const struct v4l2_file_operations tavarua_fops = {
2150 .owner = THIS_MODULE,
2151 .read = tavarua_fops_read,
2152 .write = tavarua_fops_write,
2153 .ioctl = video_ioctl2,
2154 .open = tavarua_fops_open,
2155 .release = tavarua_fops_release,
2156};
2157
2158/*************************************************************************
2159 * Video4Linux Interface
2160 *************************************************************************/
2161
2162/*
2163 * tavarua_v4l2_queryctrl - query control
2164 */
2165static struct v4l2_queryctrl tavarua_v4l2_queryctrl[] = {
2166 {
2167 .id = V4L2_CID_AUDIO_VOLUME,
2168 .type = V4L2_CTRL_TYPE_INTEGER,
2169 .name = "Volume",
2170 .minimum = 0,
2171 .maximum = 15,
2172 .step = 1,
2173 .default_value = 15,
2174 },
2175 {
2176 .id = V4L2_CID_AUDIO_BALANCE,
2177 .flags = V4L2_CTRL_FLAG_DISABLED,
2178 },
2179 {
2180 .id = V4L2_CID_AUDIO_BASS,
2181 .flags = V4L2_CTRL_FLAG_DISABLED,
2182 },
2183 {
2184 .id = V4L2_CID_AUDIO_TREBLE,
2185 .flags = V4L2_CTRL_FLAG_DISABLED,
2186 },
2187 {
2188 .id = V4L2_CID_AUDIO_MUTE,
2189 .type = V4L2_CTRL_TYPE_BOOLEAN,
2190 .name = "Mute",
2191 .minimum = 0,
2192 .maximum = 1,
2193 .step = 1,
2194 .default_value = 1,
2195 },
2196 {
2197 .id = V4L2_CID_AUDIO_LOUDNESS,
2198 .flags = V4L2_CTRL_FLAG_DISABLED,
2199 },
2200 {
2201 .id = V4L2_CID_PRIVATE_TAVARUA_SRCHMODE,
2202 .type = V4L2_CTRL_TYPE_INTEGER,
2203 .name = "Search mode",
2204 .minimum = 0,
2205 .maximum = 7,
2206 .step = 1,
2207 .default_value = 0,
2208 },
2209 {
2210 .id = V4L2_CID_PRIVATE_TAVARUA_SCANDWELL,
2211 .type = V4L2_CTRL_TYPE_INTEGER,
2212 .name = "Search dwell time",
2213 .minimum = 0,
2214 .maximum = 7,
2215 .step = 1,
2216 .default_value = 0,
2217 },
2218 {
2219 .id = V4L2_CID_PRIVATE_TAVARUA_SRCHON,
2220 .type = V4L2_CTRL_TYPE_BOOLEAN,
2221 .name = "Search on/off",
2222 .minimum = 0,
2223 .maximum = 1,
2224 .step = 1,
2225 .default_value = 1,
2226
2227 },
2228 {
2229 .id = V4L2_CID_PRIVATE_TAVARUA_STATE,
2230 .type = V4L2_CTRL_TYPE_INTEGER,
2231 .name = "radio 0ff/rx/tx/reset",
2232 .minimum = 0,
2233 .maximum = 3,
2234 .step = 1,
2235 .default_value = 1,
2236
2237 },
2238 {
2239 .id = V4L2_CID_PRIVATE_TAVARUA_REGION,
2240 .type = V4L2_CTRL_TYPE_INTEGER,
2241 .name = "radio standard",
2242 .minimum = 0,
2243 .maximum = 2,
2244 .step = 1,
2245 .default_value = 0,
2246 },
2247 {
2248 .id = V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH,
2249 .type = V4L2_CTRL_TYPE_INTEGER,
2250 .name = "Signal Threshold",
2251 .minimum = 0x80,
2252 .maximum = 0x7F,
2253 .step = 1,
2254 .default_value = 0,
2255 },
2256 {
2257 .id = V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY,
2258 .type = V4L2_CTRL_TYPE_INTEGER,
2259 .name = "Search PTY",
2260 .minimum = 0,
2261 .maximum = 31,
2262 .default_value = 0,
2263 },
2264 {
2265 .id = V4L2_CID_PRIVATE_TAVARUA_SRCH_PI,
2266 .type = V4L2_CTRL_TYPE_INTEGER,
2267 .name = "Search PI",
2268 .minimum = 0,
2269 .maximum = 0xFF,
2270 .default_value = 0,
2271 },
2272 {
2273 .id = V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT,
2274 .type = V4L2_CTRL_TYPE_INTEGER,
2275 .name = "Preset num",
2276 .minimum = 0,
2277 .maximum = 12,
2278 .default_value = 0,
2279 },
2280 {
2281 .id = V4L2_CID_PRIVATE_TAVARUA_EMPHASIS,
2282 .type = V4L2_CTRL_TYPE_BOOLEAN,
2283 .name = "Emphasis",
2284 .minimum = 0,
2285 .maximum = 1,
2286 .default_value = 0,
2287 },
2288 {
2289 .id = V4L2_CID_PRIVATE_TAVARUA_RDS_STD,
2290 .type = V4L2_CTRL_TYPE_BOOLEAN,
2291 .name = "RDS standard",
2292 .minimum = 0,
2293 .maximum = 1,
2294 .default_value = 0,
2295 },
2296 {
2297 .id = V4L2_CID_PRIVATE_TAVARUA_SPACING,
2298 .type = V4L2_CTRL_TYPE_INTEGER,
2299 .name = "Channel spacing",
2300 .minimum = 0,
2301 .maximum = 2,
2302 .default_value = 0,
2303 },
2304 {
2305 .id = V4L2_CID_PRIVATE_TAVARUA_RDSON,
2306 .type = V4L2_CTRL_TYPE_BOOLEAN,
2307 .name = "RDS on/off",
2308 .minimum = 0,
2309 .maximum = 1,
2310 .default_value = 0,
2311 },
2312 {
2313 .id = V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK,
2314 .type = V4L2_CTRL_TYPE_INTEGER,
2315 .name = "RDS group mask",
2316 .minimum = 0,
2317 .maximum = 0xFFFFFFFF,
2318 .default_value = 0,
2319 },
2320 {
2321 .id = V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC,
2322 .type = V4L2_CTRL_TYPE_INTEGER,
2323 .name = "RDS processing",
2324 .minimum = 0,
2325 .maximum = 0xFF,
2326 .default_value = 0,
2327 },
2328 {
2329 .id = V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF,
2330 .type = V4L2_CTRL_TYPE_INTEGER,
2331 .name = "RDS data groups to buffer",
2332 .minimum = 1,
2333 .maximum = 21,
2334 .default_value = 0,
2335 },
2336 {
2337 .id = V4L2_CID_PRIVATE_TAVARUA_PSALL,
2338 .type = V4L2_CTRL_TYPE_BOOLEAN,
2339 .name = "pass all ps strings",
2340 .minimum = 0,
2341 .maximum = 1,
2342 .default_value = 0,
2343 },
2344 {
2345 .id = V4L2_CID_PRIVATE_TAVARUA_LP_MODE,
2346 .type = V4L2_CTRL_TYPE_BOOLEAN,
2347 .name = "Low power mode",
2348 .minimum = 0,
2349 .maximum = 1,
2350 .default_value = 0,
2351 },
2352 {
2353 .id = V4L2_CID_PRIVATE_TAVARUA_ANTENNA,
2354 .type = V4L2_CTRL_TYPE_BOOLEAN,
2355 .name = "headset/internal",
2356 .minimum = 0,
2357 .maximum = 1,
2358 .default_value = 0,
2359 },
2360 /* Private controls for FM TX*/
2361 {
2362 .id = V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT,
2363 .type = V4L2_CTRL_TYPE_INTEGER,
2364 .name = "Set PS REPEATCOUNT",
2365 .minimum = 0,
2366 .maximum = 15,
2367 },
2368 {
2369 .id = V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_PS_NAME,
2370 .type = V4L2_CTRL_TYPE_BOOLEAN,
2371 .name = "Stop PS NAME",
2372 .minimum = 0,
2373 .maximum = 1,
2374 },
2375 {
2376 .id = V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_RT,
2377 .type = V4L2_CTRL_TYPE_BOOLEAN,
2378 .name = "Stop RT",
2379 .minimum = 0,
2380 .maximum = 1,
2381 },
Anantha Krishnan71d6fa62011-12-13 19:30:51 +05302382 { .id = V4L2_CID_PRIVATE_SET_NOTCH_FILTER,
Srinivasa Rao Uppala4e38bfc2011-09-15 16:00:31 +05302383 .type = V4L2_CTRL_TYPE_INTEGER,
2384 .name = "Notch filter",
2385 .minimum = 0,
2386 .maximum = 2,
2387 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002388
2389};
2390
2391/*=============================================================================
2392FUNCTION: tavarua_vidioc_querycap
2393=============================================================================*/
2394/**
2395 This function is called to query device capabilities.
2396
2397 NOTE:
2398 All V4L2 devices support the VIDIOC_QUERYCAP ioctl. It is used to identify
2399 kernel devices compatible with this specification and to obtain information
2400 about driver and hardware capabilities. The ioctl takes a pointer to a struct
2401 v4l2_capability which is filled by the driver. When the driver is not
2402 compatible with this specification the ioctl returns an EINVAL error code.
2403
2404 @param file: File descriptor returned by open().
2405 @param capability: pointer to struct v4l2_capability.
2406
2407 @return On success 0 is returned, else error code.
2408 @return EINVAL: The device is not compatible with this specification.
2409*/
2410static int tavarua_vidioc_querycap(struct file *file, void *priv,
2411 struct v4l2_capability *capability)
2412{
2413 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2414
2415 strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
2416 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
2417 sprintf(capability->bus_info, "I2C");
2418 capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
2419
2420 capability->version = radio->chipID;
2421
2422 return 0;
2423}
2424
2425/*=============================================================================
2426FUNCTION: tavarua_vidioc_queryctrl
2427=============================================================================*/
2428/**
2429 This function is called to query the device and driver for supported video
2430 controls (enumerate control items).
2431
2432 NOTE:
2433 To query the attributes of a control, the applications set the id field of
2434 a struct v4l2_queryctrl and call the VIDIOC_QUERYCTRL ioctl with a pointer
2435 to this structure. The driver fills the rest of the structure or returns an
2436 EINVAL error code when the id is invalid.
2437
2438 @param file: File descriptor returned by open().
2439 @param qc: pointer to struct v4l2_queryctrl.
2440
2441 @return On success 0 is returned, else error code.
2442 @return EINVAL: The struct v4l2_queryctrl id is invalid.
2443*/
2444static int tavarua_vidioc_queryctrl(struct file *file, void *priv,
2445 struct v4l2_queryctrl *qc)
2446{
2447 unsigned char i;
2448 int retval = -EINVAL;
2449
2450 for (i = 0; i < ARRAY_SIZE(tavarua_v4l2_queryctrl); i++) {
2451 if (qc->id && qc->id == tavarua_v4l2_queryctrl[i].id) {
2452 memcpy(qc, &(tavarua_v4l2_queryctrl[i]), sizeof(*qc));
2453 retval = 0;
2454 break;
2455 }
2456 }
2457 if (retval < 0)
2458 printk(KERN_WARNING DRIVER_NAME
2459 ": query conv4ltrol failed with %d\n", retval);
2460
2461 return retval;
2462}
2463static int peek_MPX_DCC(struct tavarua_device *radio)
2464{
2465 int retval = 0;
2466 unsigned char xfr_buf[XFR_REG_NUM];
2467 int MPX_DCC[] = { 0 };
2468 int DCC = 0;
2469 int ct = 0;
2470 unsigned char size = 0;
2471
2472 /*
2473 Poking the MPX_DCC_BYPASS register to freeze the
2474 value of MPX_DCC from changing while we access it
2475 */
2476
2477 /*Poking the MPX_DCC_BYPASS register : 0x88C0 */
2478 size = 0x01;
2479 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
2480 xfr_buf[1] = MPX_DCC_BYPASS_POKE_MSB;
2481 xfr_buf[2] = MPX_DCC_BYPASS_POKE_LSB;
2482 xfr_buf[3] = 0x01;
2483
2484 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 4);
2485 if (retval < 0) {
2486 FMDBG("Failed to write\n");
2487 return retval;
2488 }
2489 /*Wait for the XFR interrupt */
2490 msleep(TAVARUA_DELAY*15);
2491
2492 for (ct = 0; ct < 5; ct++)
2493 xfr_buf[ct] = 0;
2494
2495 /* Peeking Regs 0x88C2-0x88C4 */
2496 size = 0x03;
2497 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
2498 xfr_buf[1] = MPX_DCC_PEEK_MSB_REG1;
2499 xfr_buf[2] = MPX_DCC_PEEK_LSB_REG1;
2500 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
2501 if (retval < 0) {
2502 FMDBG("Failed to write\n");
2503 return retval;
2504 }
2505 /*Wait for the XFR interrupt */
2506 msleep(TAVARUA_DELAY*10);
2507 retval = tavarua_read_registers(radio, XFRDAT0, 3);
2508 if (retval < 0) {
2509 printk(KERN_INFO "INT_DET: Read failure\n");
2510 return retval;
2511 }
2512 MPX_DCC[0] = (int)radio->registers[XFRDAT0];
2513 MPX_DCC[1] = (int)radio->registers[XFRDAT1];
2514 MPX_DCC[2] = (int)radio->registers[XFRDAT2];
2515
2516 /*
2517 Form the final MPX_DCC parameter
2518 MPX_DCC[0] will form the LSB part
2519 MPX_DCC[1] will be the middle part and 4 bits of
2520 MPX_DCC[2] will be the MSB par of the 20-bit signed MPX_DCC
2521 */
2522
2523 DCC = ((int)MPX_DCC[2] << 16) | ((int)MPX_DCC[1] << 8) |
2524 ((int)MPX_DCC[0]);
2525
2526 /*
2527 if bit-19 is '1',set remaining bits to '1' & make it -tive
2528 */
2529 if (DCC & 0x00080000) {
2530 FMDBG(KERN_INFO "bit-19 is '1'\n");
2531 DCC |= 0xFFF00000;
2532 }
2533
2534 /*
2535 Poking the MPX_DCC_BYPASS register to be back to normal
2536 */
2537
2538 /*Poking the MPX_DCC_BYPASS register : 0x88C0 */
2539 size = 0x01;
2540 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
2541 xfr_buf[1] = MPX_DCC_BYPASS_POKE_MSB;
2542 xfr_buf[2] = MPX_DCC_BYPASS_POKE_LSB;
2543 xfr_buf[3] = 0x00;
2544
2545 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 4);
2546 if (retval < 0) {
2547 FMDBG("Failed to write\n");
2548 return retval;
2549 }
2550 /*Wait for the XFR interrupt */
2551 msleep(TAVARUA_DELAY*10);
2552
2553 return DCC;
2554}
2555/*=============================================================================
2556FUNCTION: tavarua_vidioc_g_ctrl
2557=============================================================================*/
2558/**
2559 This function is called to get the value of a control.
2560
2561 NOTE:
2562 To get the current value of a control, applications initialize the id field
2563 of a struct v4l2_control and call the VIDIOC_G_CTRL ioctl with a pointer to
2564 this structure.
2565
2566 When the id is invalid drivers return an EINVAL error code. When the value is
2567 out of bounds drivers can choose to take the closest valid value or return an
2568 ERANGE error code, whatever seems more appropriate.
2569
2570 @param file: File descriptor returned by open().
2571 @param ctrl: pointer to struct v4l2_control.
2572
2573 @return On success 0 is returned, else error code.
2574 @return EINVAL: The struct v4l2_control id is invalid.
2575 @return ERANGE: The struct v4l2_control value is out of bounds.
2576 @return EBUSY: The control is temporarily not changeable, possibly because
2577 another applications took over control of the device function this control
2578 belongs to.
2579*/
2580static int tavarua_vidioc_g_ctrl(struct file *file, void *priv,
2581 struct v4l2_control *ctrl)
2582{
2583 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2584 int retval = 0;
2585 unsigned char xfr_buf[XFR_REG_NUM];
2586 signed char cRmssiThreshold;
2587 signed char ioc;
2588 unsigned char size = 0;
2589
2590 switch (ctrl->id) {
2591 case V4L2_CID_AUDIO_VOLUME:
2592 break;
2593 case V4L2_CID_AUDIO_MUTE:
2594 ctrl->value = radio->registers[IOCTRL] & 0x03 ;
2595 break;
2596 case V4L2_CID_PRIVATE_TAVARUA_SRCHMODE:
2597 ctrl->value = radio->registers[SRCHCTRL] & SRCH_MODE;
2598 break;
2599 case V4L2_CID_PRIVATE_TAVARUA_SCANDWELL:
2600 ctrl->value = (radio->registers[SRCHCTRL] & SCAN_DWELL) >> 4;
2601 break;
2602 case V4L2_CID_PRIVATE_TAVARUA_SRCHON:
2603 ctrl->value = (radio->registers[SRCHCTRL] & SRCH_ON) >> 7 ;
2604 break;
2605 case V4L2_CID_PRIVATE_TAVARUA_STATE:
2606 ctrl->value = (radio->registers[RDCTRL] & 0x03);
2607 break;
2608 case V4L2_CID_PRIVATE_TAVARUA_IOVERC:
2609 retval = tavarua_read_registers(radio, IOVERC, 1);
2610 if (retval < 0)
2611 return retval;
2612 ioc = radio->registers[IOVERC];
2613 ctrl->value = ioc;
2614 break;
2615 case V4L2_CID_PRIVATE_TAVARUA_INTDET:
2616 size = 0x1;
2617 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
2618 xfr_buf[1] = INTDET_PEEK_MSB;
2619 xfr_buf[2] = INTDET_PEEK_LSB;
2620 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
2621 if (retval < 0) {
2622 FMDBG("Failed to write\n");
2623 return retval;
2624 }
2625 FMDBG("INT_DET:Sync write success\n");
2626 /*Wait for the XFR interrupt */
2627 msleep(TAVARUA_DELAY*10);
2628 /* Read the XFRDAT0 register populated by FM SoC */
2629 retval = tavarua_read_registers(radio, XFRDAT0, 3);
2630 if (retval < 0) {
2631 FMDBG("INT_DET: Read failure\n");
2632 return retval;
2633 }
2634 ctrl->value = radio->registers[XFRDAT0];
2635 break;
2636 case V4L2_CID_PRIVATE_TAVARUA_MPX_DCC:
2637 ctrl->value = peek_MPX_DCC(radio);
2638 break;
2639 case V4L2_CID_PRIVATE_TAVARUA_REGION:
2640 ctrl->value = radio->region_params.region;
2641 break;
2642 case V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH:
2643 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
2644 if (retval < 0) {
2645 FMDBG("[G IOCTL=V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
2646 FMDBG("sync_read_xfr error: [retval=%d]\n", retval);
2647 break;
2648 }
2649 /* Since RMSSI Threshold is signed value */
2650 cRmssiThreshold = (signed char)xfr_buf[0];
2651 ctrl->value = cRmssiThreshold;
2652 FMDBG("cRmssiThreshold: %d\n", cRmssiThreshold);
2653 break;
2654 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY:
2655 ctrl->value = radio->srch_params.srch_pty;
2656 break;
2657 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PI:
2658 ctrl->value = radio->srch_params.srch_pi;
2659 break;
2660 case V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT:
2661 ctrl->value = radio->srch_params.preset_num;
2662 break;
2663 case V4L2_CID_PRIVATE_TAVARUA_EMPHASIS:
2664 ctrl->value = radio->region_params.emphasis;
2665 break;
2666 case V4L2_CID_PRIVATE_TAVARUA_RDS_STD:
2667 ctrl->value = radio->region_params.rds_std;
2668 break;
2669 case V4L2_CID_PRIVATE_TAVARUA_SPACING:
2670 ctrl->value = radio->region_params.spacing;
2671 break;
2672 case V4L2_CID_PRIVATE_TAVARUA_RDSON:
2673 ctrl->value = radio->registers[RDSCTRL] & RDS_ON;
2674 break;
2675 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK:
2676 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
2677 if (retval > -1)
2678 ctrl->value = (xfr_buf[8] << 24) |
2679 (xfr_buf[9] << 16) |
2680 (xfr_buf[10] << 8) |
2681 xfr_buf[11];
2682 break;
2683 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC:
2684 retval = tavarua_read_registers(radio, ADVCTRL, 1);
2685 if (retval > -1)
2686 ctrl->value = radio->registers[ADVCTRL];
Anantha Krishnane46ef6f2011-06-29 23:56:03 +05302687 msleep(TAVARUA_DELAY*5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002688 break;
Anantha Krishnan3be3b262011-09-05 17:22:48 +05302689 case V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA:
2690 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
2691 if (retval < 0) {
2692 FMDERR("V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA]\n");
2693 FMDERR("sync_read_xfr [retval=%d]\n", retval);
2694 break;
2695 }
2696 ctrl->value = (unsigned char)xfr_buf[4];
2697 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002698 case V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF:
2699 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
2700 if (retval > -1)
2701 ctrl->value = xfr_buf[1];
2702 break;
2703 case V4L2_CID_PRIVATE_TAVARUA_PSALL:
2704 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
2705 if (retval > -1)
2706 ctrl->value = xfr_buf[12] & RDS_CONFIG_PSALL;
2707 break;
2708 case V4L2_CID_PRIVATE_TAVARUA_LP_MODE:
2709 ctrl->value = radio->lp_mode;
2710 break;
2711 case V4L2_CID_PRIVATE_TAVARUA_ANTENNA:
2712 ctrl->value = GET_REG_FIELD(radio->registers[IOCTRL],
2713 IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
2714 break;
2715 default:
2716 retval = -EINVAL;
2717 }
2718 if (retval < 0)
2719 printk(KERN_WARNING DRIVER_NAME
2720 ": get control failed with %d, id: %d\n", retval, ctrl->id);
2721
2722 return retval;
2723}
2724
2725static int tavarua_vidioc_s_ext_ctrls(struct file *file, void *priv,
2726 struct v4l2_ext_controls *ctrl)
2727{
2728 int retval = 0;
2729 int bytes_to_copy;
2730 int bytes_copied = 0;
2731 int bytes_left = 0;
2732 int chunk_index = 0;
2733 char tx_data[XFR_REG_NUM];
2734 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2735 char *data = NULL;
2736 int extra_name_byte = 0;
2737 int name_bytes = 0;
2738
2739 switch ((ctrl->controls[0]).id) {
2740 case V4L2_CID_RDS_TX_PS_NAME: {
2741 FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
2742 /*Pass a sample PS string */
2743
2744 chunk_index = 0;
2745 bytes_copied = 0;
2746 bytes_left = min((int)(ctrl->controls[0]).size,
2747 MAX_PS_LENGTH);
2748 data = (ctrl->controls[0]).string;
2749
2750 /* send payload to FM hardware */
2751 while (bytes_left) {
2752 chunk_index++;
2753 FMDBG("chunk is %d", chunk_index);
2754 bytes_to_copy = min(bytes_left, XFR_REG_NUM);
2755 /*Clear the tx_data */
2756 memset(tx_data, 0, XFR_REG_NUM);
2757 if (copy_from_user(tx_data,
2758 data + bytes_copied, bytes_to_copy))
2759 return -EFAULT;
2760 retval = sync_write_xfr(radio,
2761 RDS_PS_0 + chunk_index, tx_data);
2762 if (retval < 0) {
2763 FMDBG("sync_write_xfr: %d", retval);
2764 return retval;
2765 }
2766 bytes_copied += bytes_to_copy;
2767 bytes_left -= bytes_to_copy;
2768 }
2769 memset(tx_data, 0, XFR_REG_NUM);
2770 /*Write the PS Header*/
2771 FMDBG("Writing PS header\n");
2772 extra_name_byte = (bytes_copied%8) ? 1 : 0;
2773 name_bytes = (bytes_copied/8) + extra_name_byte;
2774 /*8 bytes are grouped as 1 name */
2775 tx_data[0] = (name_bytes) & MASK_TXREPCOUNT;
2776 tx_data[1] = radio->pty & MASK_PTY; /* PTY */
2777 tx_data[2] = ((radio->pi & MASK_PI_MSB) >> 8);
2778 tx_data[3] = radio->pi & MASK_PI_LSB;
2779 /* TX ctrl + repeatCount*/
2780 tx_data[4] = TX_ON |
2781 (radio->ps_repeatcount & MASK_TXREPCOUNT);
2782 retval = sync_write_xfr(radio, RDS_PS_0, tx_data);
2783 if (retval < 0) {
2784 FMDBG("sync_write_xfr returned %d", retval);
2785 return retval;
2786 }
2787 } break;
2788 case V4L2_CID_RDS_TX_RADIO_TEXT: {
2789 chunk_index = 0;
2790 bytes_copied = 0;
2791 FMDBG("In V4L2_CID_RDS_TX_RADIO_TEXT\n");
2792 /*Pass a sample PS string */
2793 FMDBG("Passed RT String : %s\n",
2794 (ctrl->controls[0]).string);
2795 bytes_left =
2796 min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
2797 data = (ctrl->controls[0]).string;
2798 /* send payload to FM hardware */
2799 while (bytes_left) {
2800 chunk_index++;
2801 bytes_to_copy = min(bytes_left, XFR_REG_NUM);
2802 memset(tx_data, 0, XFR_REG_NUM);
2803 if (copy_from_user(tx_data,
2804 data + bytes_copied, bytes_to_copy))
2805 return -EFAULT;
2806 retval = sync_write_xfr(radio,
2807 RDS_RT_0 + chunk_index, tx_data);
2808 if (retval < 0)
2809 return retval;
2810 bytes_copied += bytes_to_copy;
2811 bytes_left -= bytes_to_copy;
2812 }
2813 /*Write the RT Header */
2814 tx_data[0] = bytes_copied;
2815 /* PTY */
2816 tx_data[1] = TX_ON | ((radio->pty & MASK_PTY) >> 8);
2817 /* PI high */
2818 tx_data[2] = ((radio->pi & MASK_PI_MSB) >> 8);
2819 /* PI low */
2820 tx_data[3] = radio->pi & MASK_PI_LSB;
2821 retval = sync_write_xfr(radio, RDS_RT_0 , tx_data);
2822 if (retval < 0)
2823 return retval;
2824 FMDBG("done RT writing: %d\n", retval);
2825 } break;
2826 default:
2827 {
2828 FMDBG("Shouldn't reach here\n");
2829 retval = -1;
2830 }
2831 }
2832 return retval;
2833}
2834
2835/*=============================================================================
2836FUNCTION: tavarua_vidioc_s_ctrl
2837=============================================================================*/
2838/**
2839 This function is called to set the value of a control.
2840
2841 NOTE:
2842 To change the value of a control, applications initialize the id and value
2843 fields of a struct v4l2_control and call the VIDIOC_S_CTRL ioctl.
2844
2845 When the id is invalid drivers return an EINVAL error code. When the value is
2846 out of bounds drivers can choose to take the closest valid value or return an
2847 ERANGE error code, whatever seems more appropriate.
2848
2849 @param file: File descriptor returned by open().
2850 @param ctrl: pointer to struct v4l2_control.
2851
2852 @return On success 0 is returned, else error code.
2853 @return EINVAL: The struct v4l2_control id is invalid.
2854 @return ERANGE: The struct v4l2_control value is out of bounds.
2855 @return EBUSY: The control is temporarily not changeable, possibly because
2856 another applications took over control of the device function this control
2857 belongs to.
2858*/
2859static int tavarua_vidioc_s_ctrl(struct file *file, void *priv,
2860 struct v4l2_control *ctrl)
2861{
2862 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2863 int retval = 0;
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05302864 int size = 0, cnt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002865 unsigned char value;
2866 unsigned char xfr_buf[XFR_REG_NUM];
2867 unsigned char tx_data[XFR_REG_NUM];
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302868 unsigned char dis_buf[XFR_REG_NUM];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002869
2870 switch (ctrl->id) {
2871 case V4L2_CID_AUDIO_VOLUME:
2872 break;
2873 case V4L2_CID_AUDIO_MUTE:
2874 value = (radio->registers[IOCTRL] & ~IOC_HRD_MUTE) |
2875 (ctrl->value & 0x03);
2876 retval = tavarua_write_register(radio, IOCTRL, value);
2877 break;
2878 case V4L2_CID_PRIVATE_TAVARUA_SRCHMODE:
2879 value = (radio->registers[SRCHCTRL] & ~SRCH_MODE) |
2880 ctrl->value;
2881 radio->registers[SRCHCTRL] = value;
2882 break;
2883 case V4L2_CID_PRIVATE_TAVARUA_SCANDWELL:
2884 value = (radio->registers[SRCHCTRL] & ~SCAN_DWELL) |
2885 (ctrl->value << 4);
2886 radio->registers[SRCHCTRL] = value;
2887 break;
2888 /* start/stop search */
2889 case V4L2_CID_PRIVATE_TAVARUA_SRCHON:
2890 FMDBG("starting search\n");
2891 tavarua_search(radio, ctrl->value, SRCH_DIR_UP);
2892 break;
2893 case V4L2_CID_PRIVATE_TAVARUA_STATE:
2894 /* check if already on */
2895 radio->handle_irq = 1;
2896 if (((ctrl->value == FM_RECV) || (ctrl->value == FM_TRANS))
2897 && !(radio->registers[RDCTRL] &
2898 ctrl->value)) {
2899 FMDBG("clearing flags\n");
2900 init_completion(&radio->sync_xfr_start);
2901 init_completion(&radio->sync_req_done);
2902 radio->xfr_in_progress = 0;
2903 radio->xfr_bytes_left = 0;
2904 FMDBG("turning on ..\n");
2905 retval = tavarua_start(radio, ctrl->value);
2906 if (retval >= 0) {
Anantha Krishnanc72725a2011-09-06 09:28:22 +05302907 /* Enabling 'SoftMute' & 'SignalBlending' */
2908 value = (radio->registers[IOCTRL] |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002909 IOC_SFT_MUTE | IOC_SIG_BLND);
Anantha Krishnanc72725a2011-09-06 09:28:22 +05302910 retval = tavarua_write_register(radio,
2911 IOCTRL, value);
2912 if (retval < 0)
2913 FMDBG("SMute and SBlending"
2914 "not enabled\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002915 }
2916 }
2917 /* check if off */
2918 else if ((ctrl->value == FM_OFF) && radio->registers[RDCTRL]) {
2919 FMDBG("turning off...\n");
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302920 tavarua_write_register(radio, RDCTRL, ctrl->value);
2921 /* flush the event and work queues */
2922 kfifo_reset(&radio->data_buf[TAVARUA_BUF_EVENTS]);
2923 flush_workqueue(radio->wqueue);
2924 /*
2925 * queue the READY event from the host side
2926 * in case of FM off
2927 */
2928 tavarua_q_event(radio, TAVARUA_EVT_RADIO_READY);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002929
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302930 FMDBG("%s, Disable All Interrupts\n", __func__);
2931 /* disable irq */
2932 dis_buf[STATUS_REG1] = 0x00;
2933 dis_buf[STATUS_REG2] = 0x00;
2934 dis_buf[STATUS_REG3] = TRANSFER;
2935 retval = sync_write_xfr(radio, INT_CTRL, dis_buf);
2936 if (retval < 0) {
2937 pr_err("%s: failed to disable"
2938 "Interrupts\n", __func__);
2939 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002940 }
2941 }
2942 break;
Anantha Krishnanc72725a2011-09-06 09:28:22 +05302943 case V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH:
2944 FMDBG("Setting audio path ...\n");
2945 if (ctrl->value == FM_DIGITAL_PATH) {
2946 FMDBG("Digital audio path enabled ...\n");
2947 retval = tavarua_set_audio_path(
2948 TAVARUA_AUDIO_OUT_DIGITAL_ON,
2949 TAVARUA_AUDIO_OUT_ANALOG_OFF);
2950 if (retval < 0) {
2951 FMDERR("Error in tavarua_set_audio_path"
2952 " %d\n", retval);
2953 }
2954 } else if (ctrl->value == FM_ANALOG_PATH) {
2955 FMDBG("Analog audio path enabled ...\n");
2956 retval = tavarua_set_audio_path(
2957 TAVARUA_AUDIO_OUT_ANALOG_ON,
2958 TAVARUA_AUDIO_OUT_DIGITAL_OFF);
2959 if (retval < 0) {
2960 FMDERR("Error in tavarua_set_audio_path"
2961 " %d\n", retval);
2962 }
2963 }
2964 break;
Anantha Krishnan40bcd052011-12-05 15:28:29 +05302965 case V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM:
2966 radio->enable_optimized_srch_alg = ctrl->value;
2967 FMDBG("V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM : %d",
2968 radio->enable_optimized_srch_alg);
2969 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002970 case V4L2_CID_PRIVATE_TAVARUA_REGION:
2971 retval = tavarua_set_region(radio, ctrl->value);
2972 break;
2973 case V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH:
2974 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
2975 if (retval < 0) {
2976 FMDERR("V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
2977 FMDERR("sync_read_xfr [retval=%d]\n", retval);
2978 break;
2979 }
2980 /* RMSSI Threshold is a signed 8 bit value */
2981 xfr_buf[0] = (unsigned char)ctrl->value;
2982 xfr_buf[1] = (unsigned char)ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002983 retval = sync_write_xfr(radio, RX_CONFIG, xfr_buf);
2984 if (retval < 0) {
2985 FMDERR("V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
2986 FMDERR("sync_write_xfr [retval=%d]\n", retval);
2987 break;
2988 }
2989 break;
2990 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY:
2991 radio->srch_params.srch_pty = ctrl->value;
2992 break;
2993 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PI:
2994 radio->srch_params.srch_pi = ctrl->value;
2995 break;
2996 case V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT:
2997 radio->srch_params.preset_num = ctrl->value;
2998 break;
2999 case V4L2_CID_PRIVATE_TAVARUA_EMPHASIS:
3000 radio->region_params.emphasis = ctrl->value;
3001 break;
3002 case V4L2_CID_PRIVATE_TAVARUA_RDS_STD:
3003 radio->region_params.rds_std = ctrl->value;
3004 break;
3005 case V4L2_CID_PRIVATE_TAVARUA_SPACING:
3006 radio->region_params.spacing = ctrl->value;
3007 break;
3008 case V4L2_CID_PRIVATE_TAVARUA_RDSON:
3009 retval = 0;
3010 if (ctrl->value != (radio->registers[RDSCTRL] & RDS_ON)) {
3011 value = radio->registers[RDSCTRL] | ctrl->value;
3012 retval = tavarua_write_register(radio, RDSCTRL, value);
3013 }
3014 break;
3015 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK:
3016 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
3017 if (retval < 0)
3018 break;
3019 xfr_buf[8] = (ctrl->value & 0xFF000000) >> 24;
3020 xfr_buf[9] = (ctrl->value & 0x00FF0000) >> 16;
3021 xfr_buf[10] = (ctrl->value & 0x0000FF00) >> 8;
3022 xfr_buf[11] = (ctrl->value & 0x000000FF);
3023 retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
3024 break;
3025 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC:
Anantha Krishnane46ef6f2011-06-29 23:56:03 +05303026 value = radio->registers[ADVCTRL] | ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003027 retval = tavarua_write_register(radio, ADVCTRL, value);
3028 break;
Anantha Krishnane46ef6f2011-06-29 23:56:03 +05303029 case V4L2_CID_PRIVATE_TAVARUA_AF_JUMP:
3030 retval = tavarua_read_registers(radio, ADVCTRL, 1);
3031 SET_REG_FIELD(radio->registers[ADVCTRL], ctrl->value,
3032 RDSAF_OFFSET, RDSAF_MASK);
3033 msleep(TAVARUA_DELAY*5);
3034 retval = tavarua_write_register(radio,
3035 ADVCTRL, radio->registers[ADVCTRL]);
3036 msleep(TAVARUA_DELAY*5);
3037 break;
Anantha Krishnan3b44cd42011-07-06 12:36:15 +05303038 case V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA:
3039 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
3040 if (retval < 0) {
3041 FMDERR("V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA]\n");
3042 FMDERR("sync_read_xfr [retval=%d]\n", retval);
3043 break;
3044 }
3045 xfr_buf[4] = (unsigned char)ctrl->value;
3046 retval = sync_write_xfr(radio, RX_CONFIG, xfr_buf);
3047 if (retval < 0) {
3048 FMDERR("V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA]\n");
3049 FMDERR("sync_write_xfr [retval=%d]\n", retval);
3050 break;
3051 }
3052 break;
Anantha Krishnanf2258602011-06-30 01:32:09 +05303053 case V4L2_CID_PRIVATE_TAVARUA_HLSI:
3054 retval = tavarua_read_registers(radio, RDCTRL, 1);
3055 SET_REG_FIELD(radio->registers[RDCTRL], ctrl->value,
3056 RDCTRL_HLSI_OFFSET, RDCTRL_HLSI_MASK);
3057 retval = tavarua_write_register(radio, RDCTRL,
3058 radio->registers[RDCTRL]);
3059 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003060 case V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF:
3061 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
3062 if (retval < 0)
3063 break;
3064 xfr_buf[1] = ctrl->value;
3065 retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
3066 break;
3067 case V4L2_CID_PRIVATE_TAVARUA_PSALL:
3068 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
3069 value = ctrl->value & RDS_CONFIG_PSALL;
3070 if (retval < 0)
3071 break;
3072 xfr_buf[12] &= ~RDS_CONFIG_PSALL;
3073 xfr_buf[12] |= value;
3074 retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
3075 break;
3076 case V4L2_CID_PRIVATE_TAVARUA_LP_MODE:
3077 retval = 0;
3078 if (ctrl->value == radio->lp_mode)
3079 break;
3080 if (ctrl->value) {
3081 FMDBG("going into low power mode\n");
3082 retval = tavarua_disable_interrupts(radio);
3083 } else {
3084 FMDBG("going into normal power mode\n");
3085 tavarua_setup_interrupts(radio,
3086 (radio->registers[RDCTRL] & 0x03));
3087 }
3088 break;
3089 case V4L2_CID_PRIVATE_TAVARUA_ANTENNA:
3090 SET_REG_FIELD(radio->registers[IOCTRL], ctrl->value,
3091 IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
3092 break;
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303093 case V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD:
3094 size = 0x04;
3095 /* Poking the value of ON Channel Threshold value */
3096 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
3097 xfr_buf[1] = ON_CHANNEL_TH_MSB;
3098 xfr_buf[2] = ON_CHANNEL_TH_LSB;
3099 /* Data to be poked into the register */
3100 xfr_buf[3] = (ctrl->value & 0xFF000000) >> 24;
3101 xfr_buf[4] = (ctrl->value & 0x00FF0000) >> 16;
3102 xfr_buf[5] = (ctrl->value & 0x0000FF00) >> 8;
3103 xfr_buf[6] = (ctrl->value & 0x000000FF);
3104
3105 for (cnt = 3; cnt < 7; cnt++) {
3106 FMDBG("On-channel data to be poked is : %d",
3107 (int)xfr_buf[cnt]);
3108 }
3109
3110 retval = tavarua_write_registers(radio, XFRCTRL,
3111 xfr_buf, size+3);
3112 if (retval < 0) {
3113 FMDBG("Failed to write\n");
3114 return retval;
3115 }
3116 /*Wait for the XFR interrupt */
3117 msleep(TAVARUA_DELAY*15);
3118
3119 for (cnt = 0; cnt < 5; cnt++) {
3120 xfr_buf[cnt] = 0;
3121 radio->registers[XFRDAT0+cnt] = 0x0;
3122 }
3123
3124 /* Peeking Regs 0x88C2-0x88C4 */
3125 size = 0x04;
3126 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
3127 xfr_buf[1] = ON_CHANNEL_TH_MSB;
3128 xfr_buf[2] = ON_CHANNEL_TH_LSB;
3129 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
3130 if (retval < 0) {
3131 pr_err("%s: Failed to write\n", __func__);
3132 return retval;
3133 }
3134 /*Wait for the XFR interrupt */
3135 msleep(TAVARUA_DELAY*10);
3136 retval = tavarua_read_registers(radio, XFRDAT0, 4);
3137 if (retval < 0) {
3138 pr_err("%s: On Ch. DET: Read failure\n", __func__);
3139 return retval;
3140 }
3141 for (cnt = 0; cnt < 4; cnt++)
3142 FMDBG("On-Channel data set is : 0x%x\t",
3143 (int)radio->registers[XFRDAT0+cnt]);
3144 break;
3145 case V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD:
3146 size = 0x04;
3147 /* Poking the value of OFF Channel Threshold value */
3148 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
3149 xfr_buf[1] = OFF_CHANNEL_TH_MSB;
3150 xfr_buf[2] = OFF_CHANNEL_TH_LSB;
3151 /* Data to be poked into the register */
3152 xfr_buf[3] = (ctrl->value & 0xFF000000) >> 24;
3153 xfr_buf[4] = (ctrl->value & 0x00FF0000) >> 16;
3154 xfr_buf[5] = (ctrl->value & 0x0000FF00) >> 8;
3155 xfr_buf[6] = (ctrl->value & 0x000000FF);
3156
3157 for (cnt = 3; cnt < 7; cnt++) {
3158 FMDBG("Off-channel data to be poked is : %d",
3159 (int)xfr_buf[cnt]);
3160 }
3161
3162 retval = tavarua_write_registers(radio, XFRCTRL,
3163 xfr_buf, size+3);
3164 if (retval < 0) {
3165 pr_err("%s: Failed to write\n", __func__);
3166 return retval;
3167 }
3168 /*Wait for the XFR interrupt */
3169 msleep(TAVARUA_DELAY*10);
3170
3171 for (cnt = 0; cnt < 5; cnt++) {
3172 xfr_buf[cnt] = 0;
3173 radio->registers[XFRDAT0+cnt] = 0x0;
3174 }
3175
3176 /* Peeking Regs 0x88C2-0x88C4 */
3177 size = 0x04;
3178 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
3179 xfr_buf[1] = OFF_CHANNEL_TH_MSB;
3180 xfr_buf[2] = OFF_CHANNEL_TH_LSB;
3181 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
3182 if (retval < 0) {
3183 pr_err("%s: Failed to write\n", __func__);
3184 return retval;
3185 }
3186 /*Wait for the XFR interrupt */
3187 msleep(TAVARUA_DELAY*10);
3188 retval = tavarua_read_registers(radio, XFRDAT0, 4);
3189 if (retval < 0) {
3190 pr_err("%s: Off Ch. DET: Read failure\n", __func__);
3191 return retval;
3192 }
3193 for (cnt = 0; cnt < 4; cnt++)
3194 FMDBG("Off-channel data set is : 0x%x\t",
3195 (int)radio->registers[XFRDAT0+cnt]);
3196 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003197 /* TX Controls */
3198
3199 case V4L2_CID_RDS_TX_PTY: {
3200 radio->pty = ctrl->value;
3201 } break;
3202 case V4L2_CID_RDS_TX_PI: {
3203 radio->pi = ctrl->value;
3204 } break;
3205 case V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_PS_NAME: {
3206 FMDBG("In STOP_RDS_TX_PS_NAME\n");
3207 /*Pass a sample PS string */
3208 memset(tx_data, '0', XFR_REG_NUM);
3209 FMDBG("Writing PS header\n");
3210 retval = sync_write_xfr(radio, RDS_PS_0, tx_data);
3211 FMDBG("retval of PS Header write: %d", retval);
3212
3213 } break;
3214
3215 case V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_RT: {
3216 memset(tx_data, '0', XFR_REG_NUM);
3217 FMDBG("Writing RT header\n");
3218 retval = sync_write_xfr(radio, RDS_RT_0, tx_data);
3219 FMDBG("retval of Header write: %d", retval);
3220
3221 } break;
3222
3223 case V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT: {
3224 radio->ps_repeatcount = ctrl->value;
3225 } break;
3226 case V4L2_CID_TUNE_POWER_LEVEL: {
3227 unsigned char tx_power_lvl_config[FM_TX_PWR_LVL_MAX+1] = {
3228 0x85, /* tx_da<5:3> = 0 lpf<2:0> = 5*/
3229 0x95, /* tx_da<5:3> = 2 lpf<2:0> = 5*/
3230 0x9D, /* tx_da<5:3> = 3 lpf<2:0> = 5*/
3231 0xA5, /* tx_da<5:3> = 4 lpf<2:0> = 5*/
3232 0xAD, /* tx_da<5:3> = 5 lpf<2:0> = 5*/
3233 0xB5, /* tx_da<5:3> = 6 lpf<2:0> = 5*/
3234 0xBD, /* tx_da<5:3> = 7 lpf<2:0> = 5*/
3235 0xBF /* tx_da<5:3> = 7 lpf<2:0> = 7*/
3236 };
3237 if (ctrl->value > FM_TX_PWR_LVL_MAX)
3238 ctrl->value = FM_TX_PWR_LVL_MAX;
3239 if (ctrl->value < FM_TX_PWR_LVL_0)
3240 ctrl->value = FM_TX_PWR_LVL_0;
3241 retval = sync_read_xfr(radio, PHY_TXGAIN, xfr_buf);
3242 FMDBG("return for PHY_TXGAIN is %d", retval);
3243 if (retval < 0) {
3244 FMDBG("read failed");
3245 break;
3246 }
3247 xfr_buf[2] = tx_power_lvl_config[ctrl->value];
3248 retval = sync_write_xfr(radio, PHY_TXGAIN, xfr_buf);
3249 FMDBG("return for write PHY_TXGAIN is %d", retval);
3250 if (retval < 0)
3251 FMDBG("write failed");
3252 } break;
Anantha Krishnan71d6fa62011-12-13 19:30:51 +05303253 /*These IOCTL's are place holders to keep the
Srinivasa Rao Uppala4e38bfc2011-09-15 16:00:31 +05303254 driver compatible with change in frame works for IRIS */
Anantha Krishnan71d6fa62011-12-13 19:30:51 +05303255 case V4L2_CID_PRIVATE_SOFT_MUTE:
3256 case V4L2_CID_PRIVATE_RIVA_ACCS_ADDR:
3257 case V4L2_CID_PRIVATE_RIVA_ACCS_LEN:
3258 case V4L2_CID_PRIVATE_RIVA_PEEK:
3259 case V4L2_CID_PRIVATE_RIVA_POKE:
3260 case V4L2_CID_PRIVATE_SSBI_ACCS_ADDR:
3261 case V4L2_CID_PRIVATE_SSBI_PEEK:
3262 case V4L2_CID_PRIVATE_SSBI_POKE:
3263 case V4L2_CID_PRIVATE_TX_TONE:
3264 case V4L2_CID_PRIVATE_RDS_GRP_COUNTERS:
3265 case V4L2_CID_PRIVATE_SET_NOTCH_FILTER:
3266 case V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION:
Srinivasa Rao Uppala4e38bfc2011-09-15 16:00:31 +05303267 retval = 0;
3268 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003269 default:
3270 retval = -EINVAL;
3271 }
3272 if (retval < 0)
3273 printk(KERN_WARNING DRIVER_NAME
3274 ": set control failed with %d, id : %d\n", retval, ctrl->id);
3275
3276 return retval;
3277}
3278
3279/*=============================================================================
3280FUNCTION: tavarua_vidioc_g_tuner
3281=============================================================================*/
3282/**
3283 This function is called to get tuner attributes.
3284
3285 NOTE:
3286 To query the attributes of a tuner, applications initialize the index field
3287 and zero out the reserved array of a struct v4l2_tuner and call the
3288 VIDIOC_G_TUNER ioctl with a pointer to this structure. Drivers fill the rest
3289 of the structure or return an EINVAL error code when the index is out of
3290 bounds. To enumerate all tuners applications shall begin at index zero,
3291 incrementing by one until the driver returns EINVAL.
3292
3293 @param file: File descriptor returned by open().
3294 @param tuner: pointer to struct v4l2_tuner.
3295
3296 @return On success 0 is returned, else error code.
3297 @return EINVAL: The struct v4l2_tuner index is out of bounds.
3298*/
3299static int tavarua_vidioc_g_tuner(struct file *file, void *priv,
3300 struct v4l2_tuner *tuner)
3301{
3302 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3303 int retval;
3304 unsigned char xfr_buf[XFR_REG_NUM];
3305 char rmssi = 0;
3306 unsigned char size = 0;
3307
3308 if (tuner->index > 0)
3309 return -EINVAL;
3310
3311 /* read status rssi */
3312 retval = tavarua_read_registers(radio, IOCTRL, 1);
3313 if (retval < 0)
3314 return retval;
3315 /* read RMSSI */
3316 size = 0x1;
3317 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
3318 xfr_buf[1] = RMSSI_PEEK_MSB;
3319 xfr_buf[2] = RMSSI_PEEK_LSB;
3320 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
3321 msleep(TAVARUA_DELAY*10);
3322 retval = tavarua_read_registers(radio, XFRDAT0, 3);
3323 rmssi = radio->registers[XFRDAT0];
3324 tuner->signal = rmssi;
3325
3326 strcpy(tuner->name, "FM");
3327 tuner->type = V4L2_TUNER_RADIO;
3328 tuner->rangelow = radio->region_params.band_low;
3329 tuner->rangehigh = radio->region_params.band_high;
3330 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
3331 tuner->capability = V4L2_TUNER_CAP_LOW;
3332
3333 /* Stereo indicator == Stereo (instead of Mono) */
3334 if (radio->registers[IOCTRL] & IOC_MON_STR)
3335 tuner->audmode = V4L2_TUNER_MODE_STEREO;
3336 else
3337 tuner->audmode = V4L2_TUNER_MODE_MONO;
3338
3339 /* automatic frequency control: -1: freq to low, 1 freq to high */
3340 tuner->afc = 0;
3341
3342 return 0;
3343}
3344
3345/*=============================================================================
3346FUNCTION: tavarua_vidioc_s_tuner
3347=============================================================================*/
3348/**
3349 This function is called to set tuner attributes. Used to set mono/stereo mode.
3350
3351 NOTE:
3352 Tuners have two writable properties, the audio mode and the radio frequency.
3353 To change the audio mode, applications initialize the index, audmode and
3354 reserved fields and call the VIDIOC_S_TUNER ioctl. This will not change the
3355 current tuner, which is determined by the current video input. Drivers may
3356 choose a different audio mode if the requested mode is invalid or unsupported.
3357 Since this is a write-only ioctl, it does not return the actually selected
3358 audio mode.
3359
3360 To change the radio frequency the VIDIOC_S_FREQUENCY ioctl is available.
3361
3362 @param file: File descriptor returned by open().
3363 @param tuner: pointer to struct v4l2_tuner.
3364
3365 @return On success 0 is returned, else error code.
3366 @return -EINVAL: The struct v4l2_tuner index is out of bounds.
3367*/
3368static int tavarua_vidioc_s_tuner(struct file *file, void *priv,
3369 struct v4l2_tuner *tuner)
3370{
3371 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3372 int retval;
3373 int audmode;
3374 if (tuner->index > 0)
3375 return -EINVAL;
3376
3377 FMDBG("%s: set low to %d\n", __func__, tuner->rangelow);
3378 radio->region_params.band_low = tuner->rangelow;
3379 radio->region_params.band_high = tuner->rangehigh;
3380 if (tuner->audmode == V4L2_TUNER_MODE_MONO)
3381 /* Mono */
3382 audmode = (radio->registers[IOCTRL] | IOC_MON_STR);
3383 else
3384 /* Stereo */
3385 audmode = (radio->registers[IOCTRL] & ~IOC_MON_STR);
3386 retval = tavarua_write_register(radio, IOCTRL, audmode);
3387 if (retval < 0)
3388 printk(KERN_WARNING DRIVER_NAME
3389 ": set tuner failed with %d\n", retval);
3390
3391 return retval;
3392}
3393
3394/*=============================================================================
3395FUNCTION: tavarua_vidioc_g_frequency
3396=============================================================================*/
3397/**
3398 This function is called to get tuner or modulator radio frequency.
3399
3400 NOTE:
3401 To get the current tuner or modulator radio frequency applications set the
3402 tuner field of a struct v4l2_frequency to the respective tuner or modulator
3403 number (only input devices have tuners, only output devices have modulators),
3404 zero out the reserved array and call the VIDIOC_G_FREQUENCY ioctl with a
3405 pointer to this structure. The driver stores the current frequency in the
3406 frequency field.
3407
3408 @param file: File descriptor returned by open().
3409 @param freq: pointer to struct v4l2_frequency. This will be set to the
3410 resultant
3411 frequency in 62.5 khz on success.
3412
3413 @return On success 0 is returned, else error code.
3414 @return EINVAL: The tuner index is out of bounds or the value in the type
3415 field is wrong.
3416*/
3417static int tavarua_vidioc_g_frequency(struct file *file, void *priv,
3418 struct v4l2_frequency *freq)
3419{
3420 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3421 freq->type = V4L2_TUNER_RADIO;
3422 return tavarua_get_freq(radio, freq);
3423
3424}
3425
3426/*=============================================================================
3427FUNCTION: tavarua_vidioc_s_frequency
3428=============================================================================*/
3429/**
3430 This function is called to set tuner or modulator radio frequency.
3431
3432 NOTE:
3433 To change the current tuner or modulator radio frequency applications
3434 initialize the tuner, type and frequency fields, and the reserved array of
3435 a struct v4l2_frequency and call the VIDIOC_S_FREQUENCY ioctl with a pointer
3436 to this structure. When the requested frequency is not possible the driver
3437 assumes the closest possible value. However VIDIOC_S_FREQUENCY is a
3438 write-only ioctl, it does not return the actual new frequency.
3439
3440 @param file: File descriptor returned by open().
3441 @param freq: pointer to struct v4l2_frequency.
3442
3443 @return On success 0 is returned, else error code.
3444 @return EINVAL: The tuner index is out of bounds or the value in the type
3445 field is wrong.
3446*/
3447static int tavarua_vidioc_s_frequency(struct file *file, void *priv,
3448 struct v4l2_frequency *freq)
3449{
3450 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3451 int retval = -1;
3452 struct v4l2_frequency getFreq;
3453
3454 FMDBG("%s\n", __func__);
3455
3456 if (freq->type != V4L2_TUNER_RADIO)
3457 return -EINVAL;
3458
3459 FMDBG("Calling tavarua_set_freq\n");
3460
3461 INIT_COMPLETION(radio->sync_req_done);
3462 retval = tavarua_set_freq(radio, freq->frequency);
3463 if (retval < 0) {
3464 printk(KERN_WARNING DRIVER_NAME
3465 ": set frequency failed with %d\n", retval);
3466 } else {
3467 /* Wait for interrupt i.e. complete
3468 (&radio->sync_req_done); call */
3469 if (!wait_for_completion_timeout(&radio->sync_req_done,
3470 msecs_to_jiffies(wait_timeout))) {
3471 FMDERR("Timeout: No Tune response");
3472 retval = tavarua_get_freq(radio, &getFreq);
3473 radio->tune_req = 0;
3474 if (retval > 0) {
3475 if (getFreq.frequency == freq->frequency) {
3476 /** This is success, queut the event*/
3477 tavarua_q_event(radio,
3478 TAVARUA_EVT_TUNE_SUCC);
3479 return 0;
3480 } else {
3481 return -EIO;
3482 }
3483 }
3484 }
3485 }
3486 radio->tune_req = 0;
3487 return retval;
3488}
3489
3490/*=============================================================================
3491FUNCTION: tavarua_vidioc_dqbuf
3492=============================================================================*/
3493/**
3494 This function is called to exchange a buffer with the driver.
3495 This is main buffer function, in essense its equivalent to a blocking
3496 read call.
3497
3498 Applications call the VIDIOC_DQBUF ioctl to dequeue a filled (capturing) or
3499 displayed (output) buffer from the driver's outgoing queue. They just set
3500 the type and memory fields of a struct v4l2_buffer as above, when VIDIOC_DQBUF
3501 is called with a pointer to this structure the driver fills the remaining
3502 fields or returns an error code.
3503
3504 NOTE:
3505 By default VIDIOC_DQBUF blocks when no buffer is in the outgoing queue.
3506 When the O_NONBLOCK flag was given to the open() function, VIDIOC_DQBUF
3507 returns immediately with an EAGAIN error code when no buffer is available.
3508
3509 @param file: File descriptor returned by open().
3510 @param buffer: pointer to struct v4l2_buffer.
3511
3512 @return On success 0 is returned, else error code.
3513 @return EAGAIN: Non-blocking I/O has been selected using O_NONBLOCK and no
3514 buffer was in the outgoing queue.
3515 @return EINVAL: The buffer type is not supported, or the index is out of
3516 bounds, or no buffers have been allocated yet, or the userptr or length are
3517 invalid.
3518 @return ENOMEM: Not enough physical or virtual memory was available to enqueue
3519 a user pointer buffer.
3520 @return EIO: VIDIOC_DQBUF failed due to an internal error. Can also indicate
3521 temporary problems like signal loss. Note the driver might dequeue an (empty)
3522 buffer despite returning an error, or even stop capturing.
3523*/
3524static int tavarua_vidioc_dqbuf(struct file *file, void *priv,
3525 struct v4l2_buffer *buffer)
3526{
3527
3528 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3529 enum tavarua_buf_t buf_type = buffer->index;
3530 struct kfifo *data_fifo;
3531 unsigned char *buf = (unsigned char *)buffer->m.userptr;
3532 unsigned int len = buffer->length;
3533 FMDBG("%s: requesting buffer %d\n", __func__, buf_type);
3534 /* check if we can access the user buffer */
3535 if (!access_ok(VERIFY_WRITE, buf, len))
3536 return -EFAULT;
3537 if ((buf_type < TAVARUA_BUF_MAX) && (buf_type >= 0)) {
3538 data_fifo = &radio->data_buf[buf_type];
3539 if (buf_type == TAVARUA_BUF_EVENTS) {
3540 if (wait_event_interruptible(radio->event_queue,
3541 kfifo_len(data_fifo)) < 0) {
3542 return -EINTR;
3543 }
3544 }
3545 } else {
3546 FMDERR("invalid buffer type\n");
3547 return -EINVAL;
3548 }
3549 buffer->bytesused = kfifo_out_locked(data_fifo, buf, len,
3550 &radio->buf_lock[buf_type]);
3551
3552 return 0;
3553}
3554
3555/*=============================================================================
3556FUNCTION: tavarua_vidioc_g_fmt_type_private
3557=============================================================================*/
3558/**
3559 This function is here to make the v4l2 framework happy.
3560 We cannot use private buffers without it.
3561
3562 @param file: File descriptor returned by open().
3563 @param f: pointer to struct v4l2_format.
3564
3565 @return On success 0 is returned, else error code.
3566 @return EINVAL: The tuner index is out of bounds or the value in the type
3567 field is wrong.
3568*/
3569static int tavarua_vidioc_g_fmt_type_private(struct file *file, void *priv,
3570 struct v4l2_format *f)
3571{
3572 return 0;
3573
3574}
3575
3576/*=============================================================================
3577FUNCTION: tavarua_vidioc_s_hw_freq_seek
3578=============================================================================*/
3579/**
3580 This function is called to perform a hardware frequency seek.
3581
3582 Start a hardware frequency seek from the current frequency. To do this
3583 applications initialize the tuner, type, seek_upward and wrap_around fields,
3584 and zero out the reserved array of a struct v4l2_hw_freq_seek and call the
3585 VIDIOC_S_HW_FREQ_SEEK ioctl with a pointer to this structure.
3586
3587 This ioctl is supported if the V4L2_CAP_HW_FREQ_SEEK capability is set.
3588
3589 @param file: File descriptor returned by open().
3590 @param seek: pointer to struct v4l2_hw_freq_seek.
3591
3592 @return On success 0 is returned, else error code.
3593 @return EINVAL: The tuner index is out of bounds or the value in the type
3594 field is wrong.
3595 @return EAGAIN: The ioctl timed-out. Try again.
3596*/
3597static int tavarua_vidioc_s_hw_freq_seek(struct file *file, void *priv,
3598 struct v4l2_hw_freq_seek *seek)
3599{
3600 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3601 int dir;
3602 if (seek->seek_upward)
3603 dir = SRCH_DIR_UP;
3604 else
3605 dir = SRCH_DIR_DOWN;
3606 FMDBG("starting search\n");
3607 return tavarua_search(radio, CTRL_ON, dir);
3608}
3609
3610/*
3611 * tavarua_viddev_tamples - video device interface
3612 */
3613static const struct v4l2_ioctl_ops tavarua_ioctl_ops = {
3614 .vidioc_querycap = tavarua_vidioc_querycap,
3615 .vidioc_queryctrl = tavarua_vidioc_queryctrl,
3616 .vidioc_g_ctrl = tavarua_vidioc_g_ctrl,
3617 .vidioc_s_ctrl = tavarua_vidioc_s_ctrl,
3618 .vidioc_g_tuner = tavarua_vidioc_g_tuner,
3619 .vidioc_s_tuner = tavarua_vidioc_s_tuner,
3620 .vidioc_g_frequency = tavarua_vidioc_g_frequency,
3621 .vidioc_s_frequency = tavarua_vidioc_s_frequency,
3622 .vidioc_s_hw_freq_seek = tavarua_vidioc_s_hw_freq_seek,
3623 .vidioc_dqbuf = tavarua_vidioc_dqbuf,
3624 .vidioc_g_fmt_type_private = tavarua_vidioc_g_fmt_type_private,
3625 .vidioc_s_ext_ctrls = tavarua_vidioc_s_ext_ctrls,
3626};
3627
3628static struct video_device tavarua_viddev_template = {
3629 .fops = &tavarua_fops,
3630 .ioctl_ops = &tavarua_ioctl_ops,
3631 .name = DRIVER_NAME,
3632 .release = video_device_release,
3633};
3634
3635/*==============================================================
3636FUNCTION: FmQSocCom_EnableInterrupts
3637==============================================================*/
3638/**
3639 This function enable interrupts.
3640
3641 @param radio: structure pointer passed by client.
3642 @param state: FM radio state (receiver/transmitter/off/reset).
3643
3644 @return => 0 if successful.
3645 @return < 0 if failure.
3646*/
3647static int tavarua_setup_interrupts(struct tavarua_device *radio,
3648 enum radio_state_t state)
3649{
3650 int retval;
3651 unsigned char int_ctrl[XFR_REG_NUM];
3652
3653 if (!radio->lp_mode)
3654 return 0;
3655
3656 int_ctrl[STATUS_REG1] = READY | TUNE | SEARCH | SCANNEXT |
3657 SIGNAL | INTF | SYNC | AUDIO;
3658 if (state == FM_RECV)
3659 int_ctrl[STATUS_REG2] = RDSDAT | RDSRT | RDSPS | RDSAF;
3660 else
3661 int_ctrl[STATUS_REG2] = TXRDSDAT | TXRDSDONE;
3662
3663 int_ctrl[STATUS_REG3] = TRANSFER | ERROR;
3664
3665 /* use xfr for interrupt setup */
3666 if (radio->chipID == MARIMBA_2_1 || radio->chipID == BAHAMA_1_0
3667 || radio->chipID == BAHAMA_2_0) {
3668 FMDBG("Setting interrupts\n");
3669 retval = sync_write_xfr(radio, INT_CTRL, int_ctrl);
3670 /* use register write to setup interrupts */
3671 } else {
3672 retval = tavarua_write_register(radio,
3673 STATUS_REG1, int_ctrl[STATUS_REG1]);
3674 if (retval < 0)
3675 return retval;
3676
3677 retval = tavarua_write_register(radio,
3678 STATUS_REG2, int_ctrl[STATUS_REG2]);
3679 if (retval < 0)
3680 return retval;
3681
3682 retval = tavarua_write_register(radio,
3683 STATUS_REG3, int_ctrl[STATUS_REG3]);
3684 if (retval < 0)
3685 return retval;
3686 }
3687
3688 radio->lp_mode = 0;
3689 /* tavarua_handle_interrupts force reads all the interrupt status
3690 * registers and it is not valid for MBA 2.1
3691 */
3692 if ((radio->chipID != MARIMBA_2_1) && (radio->chipID != BAHAMA_1_0)
3693 && (radio->chipID != BAHAMA_2_0))
3694 tavarua_handle_interrupts(radio);
3695
3696 return retval;
3697
3698}
3699
3700/*==============================================================
3701FUNCTION: tavarua_disable_interrupts
3702==============================================================*/
3703/**
3704 This function disables interrupts.
3705
3706 @param radio: structure pointer passed by client.
3707
3708 @return => 0 if successful.
3709 @return < 0 if failure.
3710*/
3711static int tavarua_disable_interrupts(struct tavarua_device *radio)
3712{
3713 unsigned char lpm_buf[XFR_REG_NUM];
3714 int retval;
3715 if (radio->lp_mode)
3716 return 0;
3717 FMDBG("%s\n", __func__);
3718 /* In Low power mode, disable all the interrupts that are not being
3719 waited by the Application */
3720 lpm_buf[STATUS_REG1] = TUNE | SEARCH | SCANNEXT;
3721 lpm_buf[STATUS_REG2] = 0x00;
3722 lpm_buf[STATUS_REG3] = TRANSFER;
3723 /* use xfr for interrupt setup */
3724 wait_timeout = 100;
3725 if (radio->chipID == MARIMBA_2_1 || radio->chipID == BAHAMA_1_0
3726 || radio->chipID == BAHAMA_2_0)
3727 retval = sync_write_xfr(radio, INT_CTRL, lpm_buf);
3728 /* use register write to setup interrupts */
3729 else
3730 retval = tavarua_write_registers(radio, STATUS_REG1, lpm_buf,
3731 ARRAY_SIZE(lpm_buf));
3732
3733 /*INT_CTL writes may fail with TIME_OUT as all the
3734 interrupts have been disabled
3735 */
3736 if (retval > -1 || retval == -ETIME) {
3737 radio->lp_mode = 1;
3738 /*Consider timeout as a valid case here*/
3739 retval = 0;
3740 }
3741 wait_timeout = WAIT_TIMEOUT;
3742 return retval;
3743
3744}
3745
3746/*==============================================================
3747FUNCTION: tavarua_start
3748==============================================================*/
3749/**
3750 Starts/enables the device (FM radio).
3751
3752 @param radio: structure pointer passed by client.
3753 @param state: FM radio state (receiver/transmitter/off/reset).
3754
3755 @return On success 0 is returned, else error code.
3756*/
3757static int tavarua_start(struct tavarua_device *radio,
3758 enum radio_state_t state)
3759{
3760
3761 int retval;
3762 FMDBG("%s <%d>\n", __func__, state);
3763 /* set geographic region */
3764 radio->region_params.region = TAVARUA_REGION_US;
3765
3766 /* set radio mode */
3767 retval = tavarua_write_register(radio, RDCTRL, state);
3768 if (retval < 0)
3769 return retval;
3770 /* wait for radio to init */
3771 msleep(RADIO_INIT_TIME);
3772 /* enable interrupts */
3773 tavarua_setup_interrupts(radio, state);
3774 /* default region is US */
3775 radio->region_params.band_low = US_LOW_BAND * FREQ_MUL;
3776 radio->region_params.band_high = US_HIGH_BAND * FREQ_MUL;
3777
3778 return 0;
3779}
3780
3781/*==============================================================
3782FUNCTION: tavarua_suspend
3783==============================================================*/
3784/**
3785 Save state and stop all devices in system.
3786
3787 @param pdev: platform device to be suspended.
3788 @param state: Power state to put each device in.
3789
3790 @return On success 0 is returned, else error code.
3791*/
3792static int tavarua_suspend(struct platform_device *pdev, pm_message_t state)
3793{
3794 struct tavarua_device *radio = platform_get_drvdata(pdev);
3795 int retval;
3796 int users = 0;
3797 printk(KERN_INFO DRIVER_NAME "%s: radio suspend\n\n", __func__);
3798 if (radio) {
Anantha Krishnana2f98082011-10-04 20:02:11 +05303799 users = atomic_read(&radio->users);
Anantha Krishnan71bea3c2011-11-15 07:36:49 +05303800 if (!users) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003801 retval = tavarua_disable_interrupts(radio);
3802 if (retval < 0) {
3803 printk(KERN_INFO DRIVER_NAME
3804 "tavarua_suspend error %d\n", retval);
3805 return -EIO;
3806 }
3807 }
3808 }
3809 return 0;
3810}
3811
3812/*==============================================================
3813FUNCTION: tavarua_resume
3814==============================================================*/
3815/**
3816 Restore state of each device in system.
3817
3818 @param pdev: platform device to be resumed.
3819
3820 @return On success 0 is returned, else error code.
3821*/
3822static int tavarua_resume(struct platform_device *pdev)
3823{
3824
3825 struct tavarua_device *radio = platform_get_drvdata(pdev);
3826 int retval;
3827 int users = 0;
3828 printk(KERN_INFO DRIVER_NAME "%s: radio resume\n\n", __func__);
3829 if (radio) {
Anantha Krishnana2f98082011-10-04 20:02:11 +05303830 users = atomic_read(&radio->users);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003831
Anantha Krishnan71bea3c2011-11-15 07:36:49 +05303832 if (!users) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003833 retval = tavarua_setup_interrupts(radio,
3834 (radio->registers[RDCTRL] & 0x03));
3835 if (retval < 0) {
3836 printk(KERN_INFO DRIVER_NAME "Error in \
3837 tavarua_resume %d\n", retval);
3838 return -EIO;
3839 }
3840 }
3841 }
3842 return 0;
3843}
3844
3845/*==============================================================
3846FUNCTION: tavarua_set_audio_path
3847==============================================================*/
3848/**
3849 This function will configure the audio path to and from the
3850 FM core.
3851
3852 This interface is expected to be called from the multimedia
3853 driver's thread. This interface should only be called when
3854 the FM hardware is enabled. If the FM hardware is not
3855 currently enabled, this interface will return an error.
3856
3857 @param digital_on: Digital audio from the FM core should be enabled/disbled.
3858 @param analog_on: Analog audio from the FM core should be enabled/disbled.
3859
3860 @return On success 0 is returned, else error code.
3861*/
3862int tavarua_set_audio_path(int digital_on, int analog_on)
3863{
3864 struct tavarua_device *radio = private_data;
3865 int rx_on = radio->registers[RDCTRL] & FM_RECV;
3866 if (!radio)
3867 return -ENOMEM;
3868 /* RX */
3869 FMDBG("%s: digital: %d analog: %d\n", __func__, digital_on, analog_on);
3870 SET_REG_FIELD(radio->registers[AUDIOCTRL],
3871 ((rx_on && analog_on) ? 1 : 0),
3872 AUDIORX_ANALOG_OFFSET,
3873 AUDIORX_ANALOG_MASK);
3874 SET_REG_FIELD(radio->registers[AUDIOCTRL],
3875 ((rx_on && digital_on) ? 1 : 0),
3876 AUDIORX_DIGITAL_OFFSET,
3877 AUDIORX_DIGITAL_MASK);
3878 SET_REG_FIELD(radio->registers[AUDIOCTRL],
3879 (rx_on ? 0 : 1),
3880 AUDIOTX_OFFSET,
3881 AUDIOTX_MASK);
3882 /*
3883
3884 I2S Master/Slave configuration:
3885 Setting the FM SoC as I2S Master/Slave
3886 'false' - FM SoC is I2S Slave
3887 'true' - FM SoC is I2S Master
3888
3889 We get this infomation from the respective target's board file :
3890 MSM7x30 - FM SoC is I2S Slave
3891 MSM8x60 - FM SoC is I2S Slave
3892 MSM7x27A - FM SoC is I2S Master
3893 */
3894
3895 if (!radio->pdata->is_fm_soc_i2s_master) {
3896 FMDBG("FM SoC is I2S Slave\n");
3897 SET_REG_FIELD(radio->registers[AUDIOCTRL],
3898 (0),
3899 I2SCTRL_OFFSET,
3900 I2SCTRL_MASK);
3901 } else {
3902 FMDBG("FM SoC is I2S Master\n");
3903 SET_REG_FIELD(radio->registers[AUDIOCTRL],
3904 (1),
3905 I2SCTRL_OFFSET,
3906 I2SCTRL_MASK);
3907 }
3908 FMDBG("%s: %x\n", __func__, radio->registers[AUDIOCTRL]);
3909 return tavarua_write_register(radio, AUDIOCTRL,
3910 radio->registers[AUDIOCTRL]);
3911
3912}
3913
3914/*==============================================================
3915FUNCTION: tavarua_probe
3916==============================================================*/
3917/**
3918 Once called this functions initiates, allocates resources and registers video
3919 tuner device with the v4l2 framework.
3920
3921 NOTE:
3922 probe() should verify that the specified device hardware
3923 actually exists; sometimes platform setup code can't be sure. The probing
3924 can use device resources, including clocks, and device platform_data.
3925
3926 @param pdev: platform device to be probed.
3927
3928 @return On success 0 is returned, else error code.
3929 -ENOMEM in low memory cases
3930*/
3931static int __init tavarua_probe(struct platform_device *pdev)
3932{
3933
3934 struct marimba_fm_platform_data *tavarua_pdata;
3935 struct tavarua_device *radio;
3936 int retval;
3937 int i;
3938 FMDBG("%s: probe called\n", __func__);
3939 /* private data allocation */
3940 radio = kzalloc(sizeof(struct tavarua_device), GFP_KERNEL);
3941 if (!radio) {
3942 retval = -ENOMEM;
3943 goto err_initial;
3944 }
3945
3946 radio->marimba = platform_get_drvdata(pdev);
3947 tavarua_pdata = pdev->dev.platform_data;
3948 radio->pdata = tavarua_pdata;
3949 radio->dev = &pdev->dev;
3950 platform_set_drvdata(pdev, radio);
3951
3952 /* video device allocation */
3953 radio->videodev = video_device_alloc();
3954 if (!radio->videodev)
3955 goto err_radio;
3956
3957 /* initial configuration */
3958 memcpy(radio->videodev, &tavarua_viddev_template,
3959 sizeof(tavarua_viddev_template));
3960
3961 /*allocate internal buffers for decoded rds and event buffer*/
3962 for (i = 0; i < TAVARUA_BUF_MAX; i++) {
3963 int kfifo_alloc_rc=0;
3964 spin_lock_init(&radio->buf_lock[i]);
3965
3966 if (i == TAVARUA_BUF_RAW_RDS)
3967 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3968 rds_buf*3, GFP_KERNEL);
3969 else
3970 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3971 STD_BUF_SIZE, GFP_KERNEL);
3972
3973 if (kfifo_alloc_rc!=0) {
3974 printk(KERN_ERR "%s: failed allocating buffers %d\n",
3975 __func__, kfifo_alloc_rc);
3976 goto err_bufs;
3977 }
3978 }
Anantha Krishnana2f98082011-10-04 20:02:11 +05303979 /* initializing the device count */
3980 atomic_set(&radio->users, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003981 radio->xfr_in_progress = 0;
3982 radio->xfr_bytes_left = 0;
3983 for (i = 0; i < TAVARUA_XFR_MAX; i++)
3984 radio->pending_xfrs[i] = 0;
3985
3986 /* init transmit data */
3987 radio->tx_mode = TAVARUA_TX_RT;
3988 /* Init RT and PS Tx datas*/
3989 radio->pty = 0;
3990 radio->pi = 0;
3991 radio->ps_repeatcount = 0;
3992 /* init search params */
3993 radio->srch_params.srch_pty = 0;
3994 radio->srch_params.srch_pi = 0;
3995 radio->srch_params.preset_num = 0;
3996 radio->srch_params.get_list = 0;
3997 /* radio initializes to low power mode */
3998 radio->lp_mode = 1;
3999 radio->handle_irq = 1;
4000 /* init lock */
4001 mutex_init(&radio->lock);
4002 /* init completion flags */
4003 init_completion(&radio->sync_xfr_start);
4004 init_completion(&radio->sync_req_done);
4005 radio->tune_req = 0;
4006 /* initialize wait queue for event read */
4007 init_waitqueue_head(&radio->event_queue);
4008 /* initialize wait queue for raw rds read */
4009 init_waitqueue_head(&radio->read_queue);
4010
4011 video_set_drvdata(radio->videodev, radio);
4012 /*Start the worker thread for event handling and register read_int_stat
4013 as worker function*/
4014 INIT_DELAYED_WORK(&radio->work, read_int_stat);
4015
4016 /* register video device */
4017 if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
4018 printk(KERN_WARNING DRIVER_NAME
4019 ": Could not register video device\n");
4020 goto err_all;
4021 }
4022 private_data = radio;
4023 return 0;
4024
4025err_all:
4026 video_device_release(radio->videodev);
4027err_bufs:
4028 for (; i > -1; i--)
4029 kfifo_free(&radio->data_buf[i]);
4030err_radio:
4031 kfree(radio);
4032err_initial:
4033 return retval;
4034}
4035
4036/*==============================================================
4037FUNCTION: tavarua_remove
4038==============================================================*/
4039/**
4040 Removes the device.
4041
4042 @param pdev: platform device to be removed.
4043
4044 @return On success 0 is returned, else error code.
4045*/
4046static int __devexit tavarua_remove(struct platform_device *pdev)
4047{
4048 int i;
4049 struct tavarua_device *radio = platform_get_drvdata(pdev);
4050
4051 /* disable irq */
4052 tavarua_disable_irq(radio);
4053
4054 video_unregister_device(radio->videodev);
4055
4056 /* free internal buffers */
4057 for (i = 0; i < TAVARUA_BUF_MAX; i++)
4058 kfifo_free(&radio->data_buf[i]);
4059
4060 /* free state struct */
4061 kfree(radio);
4062
4063 platform_set_drvdata(pdev, NULL);
4064
4065 return 0;
4066}
4067
4068/*
4069 Platform drivers follow the standard driver model convention, where
4070 discovery/enumeration is handled outside the drivers, and drivers
4071 provide probe() and remove() methods. They support power management
4072 and shutdown notifications using the standard conventions.
4073*/
4074static struct platform_driver tavarua_driver = {
4075 .driver = {
4076 .owner = THIS_MODULE,
4077 .name = "marimba_fm",
4078 },
4079 .remove = __devexit_p(tavarua_remove),
4080 .suspend = tavarua_suspend,
4081 .resume = tavarua_resume,
4082}; /* platform device we're adding */
4083
4084
4085/*************************************************************************
4086 * Module Interface
4087 ************************************************************************/
4088
4089/*==============================================================
4090FUNCTION: radio_module_init
4091==============================================================*/
4092/**
4093 Module entry - add a platform-level device.
4094
4095 @return Returns zero if the driver registered and bound to a device, else
4096 returns a negative error code when the driver not registered.
4097*/
4098static int __init radio_module_init(void)
4099{
4100 printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n");
4101 return platform_driver_probe(&tavarua_driver, tavarua_probe);
4102}
4103
4104/*==============================================================
4105FUNCTION: radio_module_exit
4106==============================================================*/
4107/**
4108 Module exit - removes a platform-level device.
4109
4110 NOTE:
4111 Note that this function will also release all memory- and port-based
4112 resources owned by the device (dev->resource).
4113
4114 @return none.
4115*/
4116static void __exit radio_module_exit(void)
4117{
4118 platform_driver_unregister(&tavarua_driver);
4119}
4120
4121MODULE_LICENSE("GPL v2");
4122MODULE_AUTHOR(DRIVER_AUTHOR);
4123MODULE_DESCRIPTION(DRIVER_DESC);
4124MODULE_VERSION(DRIVER_VERSION);
4125
4126module_init(radio_module_init);
4127module_exit(radio_module_exit);
4128