blob: 5ec2932d0dee761c54deb220db26e35b17a1738f [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;
Anantha Krishnana3dcce42012-01-05 19:27:57 +05302585 int cnt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002586 unsigned char xfr_buf[XFR_REG_NUM];
2587 signed char cRmssiThreshold;
2588 signed char ioc;
2589 unsigned char size = 0;
2590
2591 switch (ctrl->id) {
2592 case V4L2_CID_AUDIO_VOLUME:
2593 break;
2594 case V4L2_CID_AUDIO_MUTE:
2595 ctrl->value = radio->registers[IOCTRL] & 0x03 ;
2596 break;
2597 case V4L2_CID_PRIVATE_TAVARUA_SRCHMODE:
2598 ctrl->value = radio->registers[SRCHCTRL] & SRCH_MODE;
2599 break;
2600 case V4L2_CID_PRIVATE_TAVARUA_SCANDWELL:
2601 ctrl->value = (radio->registers[SRCHCTRL] & SCAN_DWELL) >> 4;
2602 break;
2603 case V4L2_CID_PRIVATE_TAVARUA_SRCHON:
2604 ctrl->value = (radio->registers[SRCHCTRL] & SRCH_ON) >> 7 ;
2605 break;
2606 case V4L2_CID_PRIVATE_TAVARUA_STATE:
2607 ctrl->value = (radio->registers[RDCTRL] & 0x03);
2608 break;
2609 case V4L2_CID_PRIVATE_TAVARUA_IOVERC:
2610 retval = tavarua_read_registers(radio, IOVERC, 1);
2611 if (retval < 0)
2612 return retval;
2613 ioc = radio->registers[IOVERC];
2614 ctrl->value = ioc;
2615 break;
2616 case V4L2_CID_PRIVATE_TAVARUA_INTDET:
2617 size = 0x1;
2618 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
2619 xfr_buf[1] = INTDET_PEEK_MSB;
2620 xfr_buf[2] = INTDET_PEEK_LSB;
2621 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
2622 if (retval < 0) {
2623 FMDBG("Failed to write\n");
2624 return retval;
2625 }
2626 FMDBG("INT_DET:Sync write success\n");
2627 /*Wait for the XFR interrupt */
2628 msleep(TAVARUA_DELAY*10);
2629 /* Read the XFRDAT0 register populated by FM SoC */
2630 retval = tavarua_read_registers(radio, XFRDAT0, 3);
2631 if (retval < 0) {
2632 FMDBG("INT_DET: Read failure\n");
2633 return retval;
2634 }
2635 ctrl->value = radio->registers[XFRDAT0];
2636 break;
2637 case V4L2_CID_PRIVATE_TAVARUA_MPX_DCC:
2638 ctrl->value = peek_MPX_DCC(radio);
2639 break;
2640 case V4L2_CID_PRIVATE_TAVARUA_REGION:
2641 ctrl->value = radio->region_params.region;
2642 break;
2643 case V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH:
2644 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
2645 if (retval < 0) {
2646 FMDBG("[G IOCTL=V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
2647 FMDBG("sync_read_xfr error: [retval=%d]\n", retval);
2648 break;
2649 }
2650 /* Since RMSSI Threshold is signed value */
2651 cRmssiThreshold = (signed char)xfr_buf[0];
2652 ctrl->value = cRmssiThreshold;
2653 FMDBG("cRmssiThreshold: %d\n", cRmssiThreshold);
2654 break;
2655 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY:
2656 ctrl->value = radio->srch_params.srch_pty;
2657 break;
2658 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PI:
2659 ctrl->value = radio->srch_params.srch_pi;
2660 break;
2661 case V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT:
2662 ctrl->value = radio->srch_params.preset_num;
2663 break;
2664 case V4L2_CID_PRIVATE_TAVARUA_EMPHASIS:
2665 ctrl->value = radio->region_params.emphasis;
2666 break;
2667 case V4L2_CID_PRIVATE_TAVARUA_RDS_STD:
2668 ctrl->value = radio->region_params.rds_std;
2669 break;
2670 case V4L2_CID_PRIVATE_TAVARUA_SPACING:
2671 ctrl->value = radio->region_params.spacing;
2672 break;
2673 case V4L2_CID_PRIVATE_TAVARUA_RDSON:
2674 ctrl->value = radio->registers[RDSCTRL] & RDS_ON;
2675 break;
2676 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK:
2677 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
2678 if (retval > -1)
2679 ctrl->value = (xfr_buf[8] << 24) |
2680 (xfr_buf[9] << 16) |
2681 (xfr_buf[10] << 8) |
2682 xfr_buf[11];
2683 break;
2684 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC:
2685 retval = tavarua_read_registers(radio, ADVCTRL, 1);
2686 if (retval > -1)
2687 ctrl->value = radio->registers[ADVCTRL];
Anantha Krishnane46ef6f2011-06-29 23:56:03 +05302688 msleep(TAVARUA_DELAY*5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002689 break;
Anantha Krishnan3be3b262011-09-05 17:22:48 +05302690 case V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA:
2691 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
2692 if (retval < 0) {
2693 FMDERR("V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA]\n");
2694 FMDERR("sync_read_xfr [retval=%d]\n", retval);
2695 break;
2696 }
2697 ctrl->value = (unsigned char)xfr_buf[4];
2698 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002699 case V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF:
2700 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
2701 if (retval > -1)
2702 ctrl->value = xfr_buf[1];
2703 break;
2704 case V4L2_CID_PRIVATE_TAVARUA_PSALL:
2705 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
2706 if (retval > -1)
2707 ctrl->value = xfr_buf[12] & RDS_CONFIG_PSALL;
2708 break;
2709 case V4L2_CID_PRIVATE_TAVARUA_LP_MODE:
2710 ctrl->value = radio->lp_mode;
2711 break;
2712 case V4L2_CID_PRIVATE_TAVARUA_ANTENNA:
2713 ctrl->value = GET_REG_FIELD(radio->registers[IOCTRL],
2714 IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
2715 break;
Anantha Krishnana3dcce42012-01-05 19:27:57 +05302716 case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
2717 size = 0x04;
2718 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
2719 xfr_buf[1] = ON_CHANNEL_TH_MSB;
2720 xfr_buf[2] = ON_CHANNEL_TH_LSB;
2721 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
2722 if (retval < 0) {
2723 pr_err("%s: Failed to write\n", __func__);
2724 return retval;
2725 }
2726 /*Wait for the XFR interrupt */
2727 msleep(TAVARUA_DELAY*10);
2728 retval = tavarua_read_registers(radio, XFRDAT0, 4);
2729 if (retval < 0) {
2730 pr_err("%s: On Ch. DET: Read failure\n", __func__);
2731 return retval;
2732 }
2733 for (cnt = 0; cnt < 4; cnt++)
2734 FMDBG("On-Channel data set is : 0x%x\t",
2735 (int)radio->registers[XFRDAT0+cnt]);
2736
2737 ctrl->value = LSH_DATA(radio->registers[XFRDAT0], 24) |
2738 LSH_DATA(radio->registers[XFRDAT0+1], 16) |
2739 LSH_DATA(radio->registers[XFRDAT0+2], 8) |
2740 (radio->registers[XFRDAT0+3]);
2741 FMDBG("The On Channel Threshold value is : 0x%x", ctrl->value);
2742 break;
2743 case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
2744 size = 0x04;
2745 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
2746 xfr_buf[1] = OFF_CHANNEL_TH_MSB;
2747 xfr_buf[2] = OFF_CHANNEL_TH_LSB;
2748 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
2749 if (retval < 0) {
2750 pr_err("%s: Failed to write\n", __func__);
2751 return retval;
2752 }
2753 /*Wait for the XFR interrupt */
2754 msleep(TAVARUA_DELAY*10);
2755 retval = tavarua_read_registers(radio, XFRDAT0, 4);
2756 if (retval < 0) {
2757 pr_err("%s: Off Ch. DET: Read failure\n", __func__);
2758 return retval;
2759 }
2760 for (cnt = 0; cnt < 4; cnt++)
2761 FMDBG("Off-channel data set is : 0x%x\t",
2762 (int)radio->registers[XFRDAT0+cnt]);
2763
2764 ctrl->value = LSH_DATA(radio->registers[XFRDAT0], 24) |
2765 LSH_DATA(radio->registers[XFRDAT0+1], 16) |
2766 LSH_DATA(radio->registers[XFRDAT0+2], 8) |
2767 (radio->registers[XFRDAT0+3]);
2768 FMDBG("The Off Channel Threshold value is : 0x%x", ctrl->value);
2769 break;
2770 /*
2771 * These IOCTL's are place holders to keep the
2772 * driver compatible with change in frame works for IRIS
2773 */
2774 case V4L2_CID_PRIVATE_SINR_THRESHOLD:
2775 case V4L2_CID_PRIVATE_SINR_SAMPLES:
2776 case V4L2_CID_PRIVATE_IRIS_GET_SINR:
2777 retval = 0;
2778 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002779 default:
2780 retval = -EINVAL;
2781 }
2782 if (retval < 0)
2783 printk(KERN_WARNING DRIVER_NAME
2784 ": get control failed with %d, id: %d\n", retval, ctrl->id);
2785
2786 return retval;
2787}
2788
2789static int tavarua_vidioc_s_ext_ctrls(struct file *file, void *priv,
2790 struct v4l2_ext_controls *ctrl)
2791{
2792 int retval = 0;
2793 int bytes_to_copy;
2794 int bytes_copied = 0;
2795 int bytes_left = 0;
2796 int chunk_index = 0;
2797 char tx_data[XFR_REG_NUM];
2798 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2799 char *data = NULL;
2800 int extra_name_byte = 0;
2801 int name_bytes = 0;
2802
2803 switch ((ctrl->controls[0]).id) {
2804 case V4L2_CID_RDS_TX_PS_NAME: {
2805 FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
2806 /*Pass a sample PS string */
2807
2808 chunk_index = 0;
2809 bytes_copied = 0;
2810 bytes_left = min((int)(ctrl->controls[0]).size,
2811 MAX_PS_LENGTH);
2812 data = (ctrl->controls[0]).string;
2813
2814 /* send payload to FM hardware */
2815 while (bytes_left) {
2816 chunk_index++;
2817 FMDBG("chunk is %d", chunk_index);
2818 bytes_to_copy = min(bytes_left, XFR_REG_NUM);
2819 /*Clear the tx_data */
2820 memset(tx_data, 0, XFR_REG_NUM);
2821 if (copy_from_user(tx_data,
2822 data + bytes_copied, bytes_to_copy))
2823 return -EFAULT;
2824 retval = sync_write_xfr(radio,
2825 RDS_PS_0 + chunk_index, tx_data);
2826 if (retval < 0) {
2827 FMDBG("sync_write_xfr: %d", retval);
2828 return retval;
2829 }
2830 bytes_copied += bytes_to_copy;
2831 bytes_left -= bytes_to_copy;
2832 }
2833 memset(tx_data, 0, XFR_REG_NUM);
2834 /*Write the PS Header*/
2835 FMDBG("Writing PS header\n");
2836 extra_name_byte = (bytes_copied%8) ? 1 : 0;
2837 name_bytes = (bytes_copied/8) + extra_name_byte;
2838 /*8 bytes are grouped as 1 name */
2839 tx_data[0] = (name_bytes) & MASK_TXREPCOUNT;
2840 tx_data[1] = radio->pty & MASK_PTY; /* PTY */
2841 tx_data[2] = ((radio->pi & MASK_PI_MSB) >> 8);
2842 tx_data[3] = radio->pi & MASK_PI_LSB;
2843 /* TX ctrl + repeatCount*/
2844 tx_data[4] = TX_ON |
2845 (radio->ps_repeatcount & MASK_TXREPCOUNT);
2846 retval = sync_write_xfr(radio, RDS_PS_0, tx_data);
2847 if (retval < 0) {
2848 FMDBG("sync_write_xfr returned %d", retval);
2849 return retval;
2850 }
2851 } break;
2852 case V4L2_CID_RDS_TX_RADIO_TEXT: {
2853 chunk_index = 0;
2854 bytes_copied = 0;
2855 FMDBG("In V4L2_CID_RDS_TX_RADIO_TEXT\n");
2856 /*Pass a sample PS string */
2857 FMDBG("Passed RT String : %s\n",
2858 (ctrl->controls[0]).string);
2859 bytes_left =
2860 min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
2861 data = (ctrl->controls[0]).string;
2862 /* send payload to FM hardware */
2863 while (bytes_left) {
2864 chunk_index++;
2865 bytes_to_copy = min(bytes_left, XFR_REG_NUM);
2866 memset(tx_data, 0, XFR_REG_NUM);
2867 if (copy_from_user(tx_data,
2868 data + bytes_copied, bytes_to_copy))
2869 return -EFAULT;
2870 retval = sync_write_xfr(radio,
2871 RDS_RT_0 + chunk_index, tx_data);
2872 if (retval < 0)
2873 return retval;
2874 bytes_copied += bytes_to_copy;
2875 bytes_left -= bytes_to_copy;
2876 }
2877 /*Write the RT Header */
2878 tx_data[0] = bytes_copied;
2879 /* PTY */
2880 tx_data[1] = TX_ON | ((radio->pty & MASK_PTY) >> 8);
2881 /* PI high */
2882 tx_data[2] = ((radio->pi & MASK_PI_MSB) >> 8);
2883 /* PI low */
2884 tx_data[3] = radio->pi & MASK_PI_LSB;
2885 retval = sync_write_xfr(radio, RDS_RT_0 , tx_data);
2886 if (retval < 0)
2887 return retval;
2888 FMDBG("done RT writing: %d\n", retval);
2889 } break;
2890 default:
2891 {
2892 FMDBG("Shouldn't reach here\n");
2893 retval = -1;
2894 }
2895 }
2896 return retval;
2897}
2898
2899/*=============================================================================
2900FUNCTION: tavarua_vidioc_s_ctrl
2901=============================================================================*/
2902/**
2903 This function is called to set the value of a control.
2904
2905 NOTE:
2906 To change the value of a control, applications initialize the id and value
2907 fields of a struct v4l2_control and call the VIDIOC_S_CTRL ioctl.
2908
2909 When the id is invalid drivers return an EINVAL error code. When the value is
2910 out of bounds drivers can choose to take the closest valid value or return an
2911 ERANGE error code, whatever seems more appropriate.
2912
2913 @param file: File descriptor returned by open().
2914 @param ctrl: pointer to struct v4l2_control.
2915
2916 @return On success 0 is returned, else error code.
2917 @return EINVAL: The struct v4l2_control id is invalid.
2918 @return ERANGE: The struct v4l2_control value is out of bounds.
2919 @return EBUSY: The control is temporarily not changeable, possibly because
2920 another applications took over control of the device function this control
2921 belongs to.
2922*/
2923static int tavarua_vidioc_s_ctrl(struct file *file, void *priv,
2924 struct v4l2_control *ctrl)
2925{
2926 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
2927 int retval = 0;
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05302928 int size = 0, cnt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002929 unsigned char value;
2930 unsigned char xfr_buf[XFR_REG_NUM];
2931 unsigned char tx_data[XFR_REG_NUM];
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302932 unsigned char dis_buf[XFR_REG_NUM];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002933
2934 switch (ctrl->id) {
2935 case V4L2_CID_AUDIO_VOLUME:
2936 break;
2937 case V4L2_CID_AUDIO_MUTE:
2938 value = (radio->registers[IOCTRL] & ~IOC_HRD_MUTE) |
2939 (ctrl->value & 0x03);
2940 retval = tavarua_write_register(radio, IOCTRL, value);
2941 break;
2942 case V4L2_CID_PRIVATE_TAVARUA_SRCHMODE:
2943 value = (radio->registers[SRCHCTRL] & ~SRCH_MODE) |
2944 ctrl->value;
2945 radio->registers[SRCHCTRL] = value;
2946 break;
2947 case V4L2_CID_PRIVATE_TAVARUA_SCANDWELL:
2948 value = (radio->registers[SRCHCTRL] & ~SCAN_DWELL) |
2949 (ctrl->value << 4);
2950 radio->registers[SRCHCTRL] = value;
2951 break;
2952 /* start/stop search */
2953 case V4L2_CID_PRIVATE_TAVARUA_SRCHON:
2954 FMDBG("starting search\n");
2955 tavarua_search(radio, ctrl->value, SRCH_DIR_UP);
2956 break;
2957 case V4L2_CID_PRIVATE_TAVARUA_STATE:
2958 /* check if already on */
2959 radio->handle_irq = 1;
2960 if (((ctrl->value == FM_RECV) || (ctrl->value == FM_TRANS))
2961 && !(radio->registers[RDCTRL] &
2962 ctrl->value)) {
2963 FMDBG("clearing flags\n");
2964 init_completion(&radio->sync_xfr_start);
2965 init_completion(&radio->sync_req_done);
2966 radio->xfr_in_progress = 0;
2967 radio->xfr_bytes_left = 0;
2968 FMDBG("turning on ..\n");
2969 retval = tavarua_start(radio, ctrl->value);
2970 if (retval >= 0) {
Anantha Krishnanc72725a2011-09-06 09:28:22 +05302971 /* Enabling 'SoftMute' & 'SignalBlending' */
2972 value = (radio->registers[IOCTRL] |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002973 IOC_SFT_MUTE | IOC_SIG_BLND);
Anantha Krishnanc72725a2011-09-06 09:28:22 +05302974 retval = tavarua_write_register(radio,
2975 IOCTRL, value);
2976 if (retval < 0)
2977 FMDBG("SMute and SBlending"
2978 "not enabled\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002979 }
2980 }
2981 /* check if off */
2982 else if ((ctrl->value == FM_OFF) && radio->registers[RDCTRL]) {
2983 FMDBG("turning off...\n");
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302984 tavarua_write_register(radio, RDCTRL, ctrl->value);
2985 /* flush the event and work queues */
2986 kfifo_reset(&radio->data_buf[TAVARUA_BUF_EVENTS]);
2987 flush_workqueue(radio->wqueue);
2988 /*
2989 * queue the READY event from the host side
2990 * in case of FM off
2991 */
2992 tavarua_q_event(radio, TAVARUA_EVT_RADIO_READY);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002993
Venkateshwarlu Domakonda31f45da2012-01-06 14:58:13 +05302994 FMDBG("%s, Disable All Interrupts\n", __func__);
2995 /* disable irq */
2996 dis_buf[STATUS_REG1] = 0x00;
2997 dis_buf[STATUS_REG2] = 0x00;
2998 dis_buf[STATUS_REG3] = TRANSFER;
2999 retval = sync_write_xfr(radio, INT_CTRL, dis_buf);
3000 if (retval < 0) {
3001 pr_err("%s: failed to disable"
3002 "Interrupts\n", __func__);
3003 return retval;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003004 }
3005 }
3006 break;
Anantha Krishnanc72725a2011-09-06 09:28:22 +05303007 case V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH:
3008 FMDBG("Setting audio path ...\n");
3009 if (ctrl->value == FM_DIGITAL_PATH) {
3010 FMDBG("Digital audio path enabled ...\n");
3011 retval = tavarua_set_audio_path(
3012 TAVARUA_AUDIO_OUT_DIGITAL_ON,
3013 TAVARUA_AUDIO_OUT_ANALOG_OFF);
3014 if (retval < 0) {
3015 FMDERR("Error in tavarua_set_audio_path"
3016 " %d\n", retval);
3017 }
3018 } else if (ctrl->value == FM_ANALOG_PATH) {
3019 FMDBG("Analog audio path enabled ...\n");
3020 retval = tavarua_set_audio_path(
3021 TAVARUA_AUDIO_OUT_ANALOG_ON,
3022 TAVARUA_AUDIO_OUT_DIGITAL_OFF);
3023 if (retval < 0) {
3024 FMDERR("Error in tavarua_set_audio_path"
3025 " %d\n", retval);
3026 }
3027 }
3028 break;
Anantha Krishnan40bcd052011-12-05 15:28:29 +05303029 case V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM:
3030 radio->enable_optimized_srch_alg = ctrl->value;
3031 FMDBG("V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM : %d",
3032 radio->enable_optimized_srch_alg);
3033 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003034 case V4L2_CID_PRIVATE_TAVARUA_REGION:
3035 retval = tavarua_set_region(radio, ctrl->value);
3036 break;
3037 case V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH:
3038 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
3039 if (retval < 0) {
3040 FMDERR("V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
3041 FMDERR("sync_read_xfr [retval=%d]\n", retval);
3042 break;
3043 }
3044 /* RMSSI Threshold is a signed 8 bit value */
3045 xfr_buf[0] = (unsigned char)ctrl->value;
3046 xfr_buf[1] = (unsigned char)ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003047 retval = sync_write_xfr(radio, RX_CONFIG, xfr_buf);
3048 if (retval < 0) {
3049 FMDERR("V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH]\n");
3050 FMDERR("sync_write_xfr [retval=%d]\n", retval);
3051 break;
3052 }
3053 break;
3054 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY:
3055 radio->srch_params.srch_pty = ctrl->value;
3056 break;
3057 case V4L2_CID_PRIVATE_TAVARUA_SRCH_PI:
3058 radio->srch_params.srch_pi = ctrl->value;
3059 break;
3060 case V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT:
3061 radio->srch_params.preset_num = ctrl->value;
3062 break;
3063 case V4L2_CID_PRIVATE_TAVARUA_EMPHASIS:
3064 radio->region_params.emphasis = ctrl->value;
3065 break;
3066 case V4L2_CID_PRIVATE_TAVARUA_RDS_STD:
3067 radio->region_params.rds_std = ctrl->value;
3068 break;
3069 case V4L2_CID_PRIVATE_TAVARUA_SPACING:
3070 radio->region_params.spacing = ctrl->value;
3071 break;
3072 case V4L2_CID_PRIVATE_TAVARUA_RDSON:
3073 retval = 0;
3074 if (ctrl->value != (radio->registers[RDSCTRL] & RDS_ON)) {
3075 value = radio->registers[RDSCTRL] | ctrl->value;
3076 retval = tavarua_write_register(radio, RDSCTRL, value);
3077 }
3078 break;
3079 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK:
3080 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
3081 if (retval < 0)
3082 break;
3083 xfr_buf[8] = (ctrl->value & 0xFF000000) >> 24;
3084 xfr_buf[9] = (ctrl->value & 0x00FF0000) >> 16;
3085 xfr_buf[10] = (ctrl->value & 0x0000FF00) >> 8;
3086 xfr_buf[11] = (ctrl->value & 0x000000FF);
3087 retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
3088 break;
3089 case V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC:
Anantha Krishnane46ef6f2011-06-29 23:56:03 +05303090 value = radio->registers[ADVCTRL] | ctrl->value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003091 retval = tavarua_write_register(radio, ADVCTRL, value);
3092 break;
Anantha Krishnane46ef6f2011-06-29 23:56:03 +05303093 case V4L2_CID_PRIVATE_TAVARUA_AF_JUMP:
3094 retval = tavarua_read_registers(radio, ADVCTRL, 1);
3095 SET_REG_FIELD(radio->registers[ADVCTRL], ctrl->value,
3096 RDSAF_OFFSET, RDSAF_MASK);
3097 msleep(TAVARUA_DELAY*5);
3098 retval = tavarua_write_register(radio,
3099 ADVCTRL, radio->registers[ADVCTRL]);
3100 msleep(TAVARUA_DELAY*5);
3101 break;
Anantha Krishnan3b44cd42011-07-06 12:36:15 +05303102 case V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA:
3103 retval = sync_read_xfr(radio, RX_CONFIG, xfr_buf);
3104 if (retval < 0) {
3105 FMDERR("V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA]\n");
3106 FMDERR("sync_read_xfr [retval=%d]\n", retval);
3107 break;
3108 }
3109 xfr_buf[4] = (unsigned char)ctrl->value;
3110 retval = sync_write_xfr(radio, RX_CONFIG, xfr_buf);
3111 if (retval < 0) {
3112 FMDERR("V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA]\n");
3113 FMDERR("sync_write_xfr [retval=%d]\n", retval);
3114 break;
3115 }
3116 break;
Anantha Krishnanf2258602011-06-30 01:32:09 +05303117 case V4L2_CID_PRIVATE_TAVARUA_HLSI:
3118 retval = tavarua_read_registers(radio, RDCTRL, 1);
3119 SET_REG_FIELD(radio->registers[RDCTRL], ctrl->value,
3120 RDCTRL_HLSI_OFFSET, RDCTRL_HLSI_MASK);
3121 retval = tavarua_write_register(radio, RDCTRL,
3122 radio->registers[RDCTRL]);
3123 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003124 case V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF:
3125 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
3126 if (retval < 0)
3127 break;
3128 xfr_buf[1] = ctrl->value;
3129 retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
3130 break;
3131 case V4L2_CID_PRIVATE_TAVARUA_PSALL:
3132 retval = sync_read_xfr(radio, RDS_CONFIG, xfr_buf);
3133 value = ctrl->value & RDS_CONFIG_PSALL;
3134 if (retval < 0)
3135 break;
3136 xfr_buf[12] &= ~RDS_CONFIG_PSALL;
3137 xfr_buf[12] |= value;
3138 retval = sync_write_xfr(radio, RDS_CONFIG, xfr_buf);
3139 break;
3140 case V4L2_CID_PRIVATE_TAVARUA_LP_MODE:
3141 retval = 0;
3142 if (ctrl->value == radio->lp_mode)
3143 break;
3144 if (ctrl->value) {
3145 FMDBG("going into low power mode\n");
3146 retval = tavarua_disable_interrupts(radio);
3147 } else {
3148 FMDBG("going into normal power mode\n");
3149 tavarua_setup_interrupts(radio,
3150 (radio->registers[RDCTRL] & 0x03));
3151 }
3152 break;
3153 case V4L2_CID_PRIVATE_TAVARUA_ANTENNA:
3154 SET_REG_FIELD(radio->registers[IOCTRL], ctrl->value,
3155 IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
3156 break;
Anantha Krishnana3dcce42012-01-05 19:27:57 +05303157 case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303158 size = 0x04;
3159 /* Poking the value of ON Channel Threshold value */
3160 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
3161 xfr_buf[1] = ON_CHANNEL_TH_MSB;
3162 xfr_buf[2] = ON_CHANNEL_TH_LSB;
3163 /* Data to be poked into the register */
3164 xfr_buf[3] = (ctrl->value & 0xFF000000) >> 24;
3165 xfr_buf[4] = (ctrl->value & 0x00FF0000) >> 16;
3166 xfr_buf[5] = (ctrl->value & 0x0000FF00) >> 8;
3167 xfr_buf[6] = (ctrl->value & 0x000000FF);
3168
3169 for (cnt = 3; cnt < 7; cnt++) {
3170 FMDBG("On-channel data to be poked is : %d",
3171 (int)xfr_buf[cnt]);
3172 }
3173
3174 retval = tavarua_write_registers(radio, XFRCTRL,
3175 xfr_buf, size+3);
3176 if (retval < 0) {
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303177 pr_err("%s: Failed to write\n", __func__);
3178 return retval;
3179 }
3180 /*Wait for the XFR interrupt */
3181 msleep(TAVARUA_DELAY*10);
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303182 break;
Anantha Krishnana3dcce42012-01-05 19:27:57 +05303183 case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303184 size = 0x04;
3185 /* Poking the value of OFF Channel Threshold value */
3186 xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
3187 xfr_buf[1] = OFF_CHANNEL_TH_MSB;
3188 xfr_buf[2] = OFF_CHANNEL_TH_LSB;
3189 /* Data to be poked into the register */
3190 xfr_buf[3] = (ctrl->value & 0xFF000000) >> 24;
3191 xfr_buf[4] = (ctrl->value & 0x00FF0000) >> 16;
3192 xfr_buf[5] = (ctrl->value & 0x0000FF00) >> 8;
3193 xfr_buf[6] = (ctrl->value & 0x000000FF);
3194
3195 for (cnt = 3; cnt < 7; cnt++) {
3196 FMDBG("Off-channel data to be poked is : %d",
3197 (int)xfr_buf[cnt]);
3198 }
3199
3200 retval = tavarua_write_registers(radio, XFRCTRL,
3201 xfr_buf, size+3);
3202 if (retval < 0) {
3203 pr_err("%s: Failed to write\n", __func__);
3204 return retval;
3205 }
3206 /*Wait for the XFR interrupt */
3207 msleep(TAVARUA_DELAY*10);
Anantha Krishnanbdb128c2011-11-21 17:51:26 +05303208 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003209 /* TX Controls */
3210
3211 case V4L2_CID_RDS_TX_PTY: {
3212 radio->pty = ctrl->value;
3213 } break;
3214 case V4L2_CID_RDS_TX_PI: {
3215 radio->pi = ctrl->value;
3216 } break;
3217 case V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_PS_NAME: {
3218 FMDBG("In STOP_RDS_TX_PS_NAME\n");
3219 /*Pass a sample PS string */
3220 memset(tx_data, '0', XFR_REG_NUM);
3221 FMDBG("Writing PS header\n");
3222 retval = sync_write_xfr(radio, RDS_PS_0, tx_data);
3223 FMDBG("retval of PS Header write: %d", retval);
3224
3225 } break;
3226
3227 case V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_RT: {
3228 memset(tx_data, '0', XFR_REG_NUM);
3229 FMDBG("Writing RT header\n");
3230 retval = sync_write_xfr(radio, RDS_RT_0, tx_data);
3231 FMDBG("retval of Header write: %d", retval);
3232
3233 } break;
3234
3235 case V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT: {
3236 radio->ps_repeatcount = ctrl->value;
3237 } break;
3238 case V4L2_CID_TUNE_POWER_LEVEL: {
3239 unsigned char tx_power_lvl_config[FM_TX_PWR_LVL_MAX+1] = {
3240 0x85, /* tx_da<5:3> = 0 lpf<2:0> = 5*/
3241 0x95, /* tx_da<5:3> = 2 lpf<2:0> = 5*/
3242 0x9D, /* tx_da<5:3> = 3 lpf<2:0> = 5*/
3243 0xA5, /* tx_da<5:3> = 4 lpf<2:0> = 5*/
3244 0xAD, /* tx_da<5:3> = 5 lpf<2:0> = 5*/
3245 0xB5, /* tx_da<5:3> = 6 lpf<2:0> = 5*/
3246 0xBD, /* tx_da<5:3> = 7 lpf<2:0> = 5*/
3247 0xBF /* tx_da<5:3> = 7 lpf<2:0> = 7*/
3248 };
3249 if (ctrl->value > FM_TX_PWR_LVL_MAX)
3250 ctrl->value = FM_TX_PWR_LVL_MAX;
3251 if (ctrl->value < FM_TX_PWR_LVL_0)
3252 ctrl->value = FM_TX_PWR_LVL_0;
3253 retval = sync_read_xfr(radio, PHY_TXGAIN, xfr_buf);
3254 FMDBG("return for PHY_TXGAIN is %d", retval);
3255 if (retval < 0) {
3256 FMDBG("read failed");
3257 break;
3258 }
3259 xfr_buf[2] = tx_power_lvl_config[ctrl->value];
3260 retval = sync_write_xfr(radio, PHY_TXGAIN, xfr_buf);
3261 FMDBG("return for write PHY_TXGAIN is %d", retval);
3262 if (retval < 0)
3263 FMDBG("write failed");
3264 } break;
Anantha Krishnan71d6fa62011-12-13 19:30:51 +05303265 /*These IOCTL's are place holders to keep the
Srinivasa Rao Uppala4e38bfc2011-09-15 16:00:31 +05303266 driver compatible with change in frame works for IRIS */
Anantha Krishnan71d6fa62011-12-13 19:30:51 +05303267 case V4L2_CID_PRIVATE_SOFT_MUTE:
3268 case V4L2_CID_PRIVATE_RIVA_ACCS_ADDR:
3269 case V4L2_CID_PRIVATE_RIVA_ACCS_LEN:
3270 case V4L2_CID_PRIVATE_RIVA_PEEK:
3271 case V4L2_CID_PRIVATE_RIVA_POKE:
3272 case V4L2_CID_PRIVATE_SSBI_ACCS_ADDR:
3273 case V4L2_CID_PRIVATE_SSBI_PEEK:
3274 case V4L2_CID_PRIVATE_SSBI_POKE:
3275 case V4L2_CID_PRIVATE_TX_TONE:
3276 case V4L2_CID_PRIVATE_RDS_GRP_COUNTERS:
3277 case V4L2_CID_PRIVATE_SET_NOTCH_FILTER:
3278 case V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION:
Anantha Krishnana3dcce42012-01-05 19:27:57 +05303279 case V4L2_CID_PRIVATE_SINR_THRESHOLD:
3280 case V4L2_CID_PRIVATE_SINR_SAMPLES:
Srinivasa Rao Uppala4e38bfc2011-09-15 16:00:31 +05303281 retval = 0;
3282 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003283 default:
3284 retval = -EINVAL;
3285 }
3286 if (retval < 0)
3287 printk(KERN_WARNING DRIVER_NAME
3288 ": set control failed with %d, id : %d\n", retval, ctrl->id);
3289
3290 return retval;
3291}
3292
3293/*=============================================================================
3294FUNCTION: tavarua_vidioc_g_tuner
3295=============================================================================*/
3296/**
3297 This function is called to get tuner attributes.
3298
3299 NOTE:
3300 To query the attributes of a tuner, applications initialize the index field
3301 and zero out the reserved array of a struct v4l2_tuner and call the
3302 VIDIOC_G_TUNER ioctl with a pointer to this structure. Drivers fill the rest
3303 of the structure or return an EINVAL error code when the index is out of
3304 bounds. To enumerate all tuners applications shall begin at index zero,
3305 incrementing by one until the driver returns EINVAL.
3306
3307 @param file: File descriptor returned by open().
3308 @param tuner: pointer to struct v4l2_tuner.
3309
3310 @return On success 0 is returned, else error code.
3311 @return EINVAL: The struct v4l2_tuner index is out of bounds.
3312*/
3313static int tavarua_vidioc_g_tuner(struct file *file, void *priv,
3314 struct v4l2_tuner *tuner)
3315{
3316 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3317 int retval;
3318 unsigned char xfr_buf[XFR_REG_NUM];
3319 char rmssi = 0;
3320 unsigned char size = 0;
3321
3322 if (tuner->index > 0)
3323 return -EINVAL;
3324
3325 /* read status rssi */
3326 retval = tavarua_read_registers(radio, IOCTRL, 1);
3327 if (retval < 0)
3328 return retval;
3329 /* read RMSSI */
3330 size = 0x1;
3331 xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
3332 xfr_buf[1] = RMSSI_PEEK_MSB;
3333 xfr_buf[2] = RMSSI_PEEK_LSB;
3334 retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
3335 msleep(TAVARUA_DELAY*10);
3336 retval = tavarua_read_registers(radio, XFRDAT0, 3);
3337 rmssi = radio->registers[XFRDAT0];
3338 tuner->signal = rmssi;
3339
3340 strcpy(tuner->name, "FM");
3341 tuner->type = V4L2_TUNER_RADIO;
3342 tuner->rangelow = radio->region_params.band_low;
3343 tuner->rangehigh = radio->region_params.band_high;
3344 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
3345 tuner->capability = V4L2_TUNER_CAP_LOW;
3346
3347 /* Stereo indicator == Stereo (instead of Mono) */
3348 if (radio->registers[IOCTRL] & IOC_MON_STR)
3349 tuner->audmode = V4L2_TUNER_MODE_STEREO;
3350 else
3351 tuner->audmode = V4L2_TUNER_MODE_MONO;
3352
3353 /* automatic frequency control: -1: freq to low, 1 freq to high */
3354 tuner->afc = 0;
3355
3356 return 0;
3357}
3358
3359/*=============================================================================
3360FUNCTION: tavarua_vidioc_s_tuner
3361=============================================================================*/
3362/**
3363 This function is called to set tuner attributes. Used to set mono/stereo mode.
3364
3365 NOTE:
3366 Tuners have two writable properties, the audio mode and the radio frequency.
3367 To change the audio mode, applications initialize the index, audmode and
3368 reserved fields and call the VIDIOC_S_TUNER ioctl. This will not change the
3369 current tuner, which is determined by the current video input. Drivers may
3370 choose a different audio mode if the requested mode is invalid or unsupported.
3371 Since this is a write-only ioctl, it does not return the actually selected
3372 audio mode.
3373
3374 To change the radio frequency the VIDIOC_S_FREQUENCY ioctl is available.
3375
3376 @param file: File descriptor returned by open().
3377 @param tuner: pointer to struct v4l2_tuner.
3378
3379 @return On success 0 is returned, else error code.
3380 @return -EINVAL: The struct v4l2_tuner index is out of bounds.
3381*/
3382static int tavarua_vidioc_s_tuner(struct file *file, void *priv,
3383 struct v4l2_tuner *tuner)
3384{
3385 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3386 int retval;
3387 int audmode;
3388 if (tuner->index > 0)
3389 return -EINVAL;
3390
3391 FMDBG("%s: set low to %d\n", __func__, tuner->rangelow);
3392 radio->region_params.band_low = tuner->rangelow;
3393 radio->region_params.band_high = tuner->rangehigh;
3394 if (tuner->audmode == V4L2_TUNER_MODE_MONO)
3395 /* Mono */
3396 audmode = (radio->registers[IOCTRL] | IOC_MON_STR);
3397 else
3398 /* Stereo */
3399 audmode = (radio->registers[IOCTRL] & ~IOC_MON_STR);
3400 retval = tavarua_write_register(radio, IOCTRL, audmode);
3401 if (retval < 0)
3402 printk(KERN_WARNING DRIVER_NAME
3403 ": set tuner failed with %d\n", retval);
3404
3405 return retval;
3406}
3407
3408/*=============================================================================
3409FUNCTION: tavarua_vidioc_g_frequency
3410=============================================================================*/
3411/**
3412 This function is called to get tuner or modulator radio frequency.
3413
3414 NOTE:
3415 To get the current tuner or modulator radio frequency applications set the
3416 tuner field of a struct v4l2_frequency to the respective tuner or modulator
3417 number (only input devices have tuners, only output devices have modulators),
3418 zero out the reserved array and call the VIDIOC_G_FREQUENCY ioctl with a
3419 pointer to this structure. The driver stores the current frequency in the
3420 frequency field.
3421
3422 @param file: File descriptor returned by open().
3423 @param freq: pointer to struct v4l2_frequency. This will be set to the
3424 resultant
3425 frequency in 62.5 khz on success.
3426
3427 @return On success 0 is returned, else error code.
3428 @return EINVAL: The tuner index is out of bounds or the value in the type
3429 field is wrong.
3430*/
3431static int tavarua_vidioc_g_frequency(struct file *file, void *priv,
3432 struct v4l2_frequency *freq)
3433{
3434 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3435 freq->type = V4L2_TUNER_RADIO;
3436 return tavarua_get_freq(radio, freq);
3437
3438}
3439
3440/*=============================================================================
3441FUNCTION: tavarua_vidioc_s_frequency
3442=============================================================================*/
3443/**
3444 This function is called to set tuner or modulator radio frequency.
3445
3446 NOTE:
3447 To change the current tuner or modulator radio frequency applications
3448 initialize the tuner, type and frequency fields, and the reserved array of
3449 a struct v4l2_frequency and call the VIDIOC_S_FREQUENCY ioctl with a pointer
3450 to this structure. When the requested frequency is not possible the driver
3451 assumes the closest possible value. However VIDIOC_S_FREQUENCY is a
3452 write-only ioctl, it does not return the actual new frequency.
3453
3454 @param file: File descriptor returned by open().
3455 @param freq: pointer to struct v4l2_frequency.
3456
3457 @return On success 0 is returned, else error code.
3458 @return EINVAL: The tuner index is out of bounds or the value in the type
3459 field is wrong.
3460*/
3461static int tavarua_vidioc_s_frequency(struct file *file, void *priv,
3462 struct v4l2_frequency *freq)
3463{
3464 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3465 int retval = -1;
3466 struct v4l2_frequency getFreq;
3467
3468 FMDBG("%s\n", __func__);
3469
3470 if (freq->type != V4L2_TUNER_RADIO)
3471 return -EINVAL;
3472
3473 FMDBG("Calling tavarua_set_freq\n");
3474
3475 INIT_COMPLETION(radio->sync_req_done);
3476 retval = tavarua_set_freq(radio, freq->frequency);
3477 if (retval < 0) {
3478 printk(KERN_WARNING DRIVER_NAME
3479 ": set frequency failed with %d\n", retval);
3480 } else {
3481 /* Wait for interrupt i.e. complete
3482 (&radio->sync_req_done); call */
3483 if (!wait_for_completion_timeout(&radio->sync_req_done,
3484 msecs_to_jiffies(wait_timeout))) {
3485 FMDERR("Timeout: No Tune response");
3486 retval = tavarua_get_freq(radio, &getFreq);
3487 radio->tune_req = 0;
3488 if (retval > 0) {
3489 if (getFreq.frequency == freq->frequency) {
3490 /** This is success, queut the event*/
3491 tavarua_q_event(radio,
3492 TAVARUA_EVT_TUNE_SUCC);
3493 return 0;
3494 } else {
3495 return -EIO;
3496 }
3497 }
3498 }
3499 }
3500 radio->tune_req = 0;
3501 return retval;
3502}
3503
3504/*=============================================================================
3505FUNCTION: tavarua_vidioc_dqbuf
3506=============================================================================*/
3507/**
3508 This function is called to exchange a buffer with the driver.
3509 This is main buffer function, in essense its equivalent to a blocking
3510 read call.
3511
3512 Applications call the VIDIOC_DQBUF ioctl to dequeue a filled (capturing) or
3513 displayed (output) buffer from the driver's outgoing queue. They just set
3514 the type and memory fields of a struct v4l2_buffer as above, when VIDIOC_DQBUF
3515 is called with a pointer to this structure the driver fills the remaining
3516 fields or returns an error code.
3517
3518 NOTE:
3519 By default VIDIOC_DQBUF blocks when no buffer is in the outgoing queue.
3520 When the O_NONBLOCK flag was given to the open() function, VIDIOC_DQBUF
3521 returns immediately with an EAGAIN error code when no buffer is available.
3522
3523 @param file: File descriptor returned by open().
3524 @param buffer: pointer to struct v4l2_buffer.
3525
3526 @return On success 0 is returned, else error code.
3527 @return EAGAIN: Non-blocking I/O has been selected using O_NONBLOCK and no
3528 buffer was in the outgoing queue.
3529 @return EINVAL: The buffer type is not supported, or the index is out of
3530 bounds, or no buffers have been allocated yet, or the userptr or length are
3531 invalid.
3532 @return ENOMEM: Not enough physical or virtual memory was available to enqueue
3533 a user pointer buffer.
3534 @return EIO: VIDIOC_DQBUF failed due to an internal error. Can also indicate
3535 temporary problems like signal loss. Note the driver might dequeue an (empty)
3536 buffer despite returning an error, or even stop capturing.
3537*/
3538static int tavarua_vidioc_dqbuf(struct file *file, void *priv,
3539 struct v4l2_buffer *buffer)
3540{
3541
3542 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3543 enum tavarua_buf_t buf_type = buffer->index;
3544 struct kfifo *data_fifo;
3545 unsigned char *buf = (unsigned char *)buffer->m.userptr;
3546 unsigned int len = buffer->length;
3547 FMDBG("%s: requesting buffer %d\n", __func__, buf_type);
3548 /* check if we can access the user buffer */
3549 if (!access_ok(VERIFY_WRITE, buf, len))
3550 return -EFAULT;
3551 if ((buf_type < TAVARUA_BUF_MAX) && (buf_type >= 0)) {
3552 data_fifo = &radio->data_buf[buf_type];
3553 if (buf_type == TAVARUA_BUF_EVENTS) {
3554 if (wait_event_interruptible(radio->event_queue,
3555 kfifo_len(data_fifo)) < 0) {
3556 return -EINTR;
3557 }
3558 }
3559 } else {
3560 FMDERR("invalid buffer type\n");
3561 return -EINVAL;
3562 }
3563 buffer->bytesused = kfifo_out_locked(data_fifo, buf, len,
3564 &radio->buf_lock[buf_type]);
3565
3566 return 0;
3567}
3568
3569/*=============================================================================
3570FUNCTION: tavarua_vidioc_g_fmt_type_private
3571=============================================================================*/
3572/**
3573 This function is here to make the v4l2 framework happy.
3574 We cannot use private buffers without it.
3575
3576 @param file: File descriptor returned by open().
3577 @param f: pointer to struct v4l2_format.
3578
3579 @return On success 0 is returned, else error code.
3580 @return EINVAL: The tuner index is out of bounds or the value in the type
3581 field is wrong.
3582*/
3583static int tavarua_vidioc_g_fmt_type_private(struct file *file, void *priv,
3584 struct v4l2_format *f)
3585{
3586 return 0;
3587
3588}
3589
3590/*=============================================================================
3591FUNCTION: tavarua_vidioc_s_hw_freq_seek
3592=============================================================================*/
3593/**
3594 This function is called to perform a hardware frequency seek.
3595
3596 Start a hardware frequency seek from the current frequency. To do this
3597 applications initialize the tuner, type, seek_upward and wrap_around fields,
3598 and zero out the reserved array of a struct v4l2_hw_freq_seek and call the
3599 VIDIOC_S_HW_FREQ_SEEK ioctl with a pointer to this structure.
3600
3601 This ioctl is supported if the V4L2_CAP_HW_FREQ_SEEK capability is set.
3602
3603 @param file: File descriptor returned by open().
3604 @param seek: pointer to struct v4l2_hw_freq_seek.
3605
3606 @return On success 0 is returned, else error code.
3607 @return EINVAL: The tuner index is out of bounds or the value in the type
3608 field is wrong.
3609 @return EAGAIN: The ioctl timed-out. Try again.
3610*/
3611static int tavarua_vidioc_s_hw_freq_seek(struct file *file, void *priv,
3612 struct v4l2_hw_freq_seek *seek)
3613{
3614 struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
3615 int dir;
3616 if (seek->seek_upward)
3617 dir = SRCH_DIR_UP;
3618 else
3619 dir = SRCH_DIR_DOWN;
3620 FMDBG("starting search\n");
3621 return tavarua_search(radio, CTRL_ON, dir);
3622}
3623
3624/*
3625 * tavarua_viddev_tamples - video device interface
3626 */
3627static const struct v4l2_ioctl_ops tavarua_ioctl_ops = {
3628 .vidioc_querycap = tavarua_vidioc_querycap,
3629 .vidioc_queryctrl = tavarua_vidioc_queryctrl,
3630 .vidioc_g_ctrl = tavarua_vidioc_g_ctrl,
3631 .vidioc_s_ctrl = tavarua_vidioc_s_ctrl,
3632 .vidioc_g_tuner = tavarua_vidioc_g_tuner,
3633 .vidioc_s_tuner = tavarua_vidioc_s_tuner,
3634 .vidioc_g_frequency = tavarua_vidioc_g_frequency,
3635 .vidioc_s_frequency = tavarua_vidioc_s_frequency,
3636 .vidioc_s_hw_freq_seek = tavarua_vidioc_s_hw_freq_seek,
3637 .vidioc_dqbuf = tavarua_vidioc_dqbuf,
3638 .vidioc_g_fmt_type_private = tavarua_vidioc_g_fmt_type_private,
3639 .vidioc_s_ext_ctrls = tavarua_vidioc_s_ext_ctrls,
3640};
3641
3642static struct video_device tavarua_viddev_template = {
3643 .fops = &tavarua_fops,
3644 .ioctl_ops = &tavarua_ioctl_ops,
3645 .name = DRIVER_NAME,
3646 .release = video_device_release,
3647};
3648
3649/*==============================================================
3650FUNCTION: FmQSocCom_EnableInterrupts
3651==============================================================*/
3652/**
3653 This function enable interrupts.
3654
3655 @param radio: structure pointer passed by client.
3656 @param state: FM radio state (receiver/transmitter/off/reset).
3657
3658 @return => 0 if successful.
3659 @return < 0 if failure.
3660*/
3661static int tavarua_setup_interrupts(struct tavarua_device *radio,
3662 enum radio_state_t state)
3663{
3664 int retval;
3665 unsigned char int_ctrl[XFR_REG_NUM];
3666
3667 if (!radio->lp_mode)
3668 return 0;
3669
3670 int_ctrl[STATUS_REG1] = READY | TUNE | SEARCH | SCANNEXT |
3671 SIGNAL | INTF | SYNC | AUDIO;
3672 if (state == FM_RECV)
3673 int_ctrl[STATUS_REG2] = RDSDAT | RDSRT | RDSPS | RDSAF;
3674 else
3675 int_ctrl[STATUS_REG2] = TXRDSDAT | TXRDSDONE;
3676
3677 int_ctrl[STATUS_REG3] = TRANSFER | ERROR;
3678
3679 /* use xfr for interrupt setup */
3680 if (radio->chipID == MARIMBA_2_1 || radio->chipID == BAHAMA_1_0
3681 || radio->chipID == BAHAMA_2_0) {
3682 FMDBG("Setting interrupts\n");
3683 retval = sync_write_xfr(radio, INT_CTRL, int_ctrl);
3684 /* use register write to setup interrupts */
3685 } else {
3686 retval = tavarua_write_register(radio,
3687 STATUS_REG1, int_ctrl[STATUS_REG1]);
3688 if (retval < 0)
3689 return retval;
3690
3691 retval = tavarua_write_register(radio,
3692 STATUS_REG2, int_ctrl[STATUS_REG2]);
3693 if (retval < 0)
3694 return retval;
3695
3696 retval = tavarua_write_register(radio,
3697 STATUS_REG3, int_ctrl[STATUS_REG3]);
3698 if (retval < 0)
3699 return retval;
3700 }
3701
3702 radio->lp_mode = 0;
3703 /* tavarua_handle_interrupts force reads all the interrupt status
3704 * registers and it is not valid for MBA 2.1
3705 */
3706 if ((radio->chipID != MARIMBA_2_1) && (radio->chipID != BAHAMA_1_0)
3707 && (radio->chipID != BAHAMA_2_0))
3708 tavarua_handle_interrupts(radio);
3709
3710 return retval;
3711
3712}
3713
3714/*==============================================================
3715FUNCTION: tavarua_disable_interrupts
3716==============================================================*/
3717/**
3718 This function disables interrupts.
3719
3720 @param radio: structure pointer passed by client.
3721
3722 @return => 0 if successful.
3723 @return < 0 if failure.
3724*/
3725static int tavarua_disable_interrupts(struct tavarua_device *radio)
3726{
3727 unsigned char lpm_buf[XFR_REG_NUM];
3728 int retval;
3729 if (radio->lp_mode)
3730 return 0;
3731 FMDBG("%s\n", __func__);
3732 /* In Low power mode, disable all the interrupts that are not being
3733 waited by the Application */
3734 lpm_buf[STATUS_REG1] = TUNE | SEARCH | SCANNEXT;
3735 lpm_buf[STATUS_REG2] = 0x00;
3736 lpm_buf[STATUS_REG3] = TRANSFER;
3737 /* use xfr for interrupt setup */
3738 wait_timeout = 100;
3739 if (radio->chipID == MARIMBA_2_1 || radio->chipID == BAHAMA_1_0
3740 || radio->chipID == BAHAMA_2_0)
3741 retval = sync_write_xfr(radio, INT_CTRL, lpm_buf);
3742 /* use register write to setup interrupts */
3743 else
3744 retval = tavarua_write_registers(radio, STATUS_REG1, lpm_buf,
3745 ARRAY_SIZE(lpm_buf));
3746
3747 /*INT_CTL writes may fail with TIME_OUT as all the
3748 interrupts have been disabled
3749 */
3750 if (retval > -1 || retval == -ETIME) {
3751 radio->lp_mode = 1;
3752 /*Consider timeout as a valid case here*/
3753 retval = 0;
3754 }
3755 wait_timeout = WAIT_TIMEOUT;
3756 return retval;
3757
3758}
3759
3760/*==============================================================
3761FUNCTION: tavarua_start
3762==============================================================*/
3763/**
3764 Starts/enables the device (FM radio).
3765
3766 @param radio: structure pointer passed by client.
3767 @param state: FM radio state (receiver/transmitter/off/reset).
3768
3769 @return On success 0 is returned, else error code.
3770*/
3771static int tavarua_start(struct tavarua_device *radio,
3772 enum radio_state_t state)
3773{
3774
3775 int retval;
3776 FMDBG("%s <%d>\n", __func__, state);
3777 /* set geographic region */
3778 radio->region_params.region = TAVARUA_REGION_US;
3779
3780 /* set radio mode */
3781 retval = tavarua_write_register(radio, RDCTRL, state);
3782 if (retval < 0)
3783 return retval;
3784 /* wait for radio to init */
3785 msleep(RADIO_INIT_TIME);
3786 /* enable interrupts */
3787 tavarua_setup_interrupts(radio, state);
3788 /* default region is US */
3789 radio->region_params.band_low = US_LOW_BAND * FREQ_MUL;
3790 radio->region_params.band_high = US_HIGH_BAND * FREQ_MUL;
3791
3792 return 0;
3793}
3794
3795/*==============================================================
3796FUNCTION: tavarua_suspend
3797==============================================================*/
3798/**
3799 Save state and stop all devices in system.
3800
3801 @param pdev: platform device to be suspended.
3802 @param state: Power state to put each device in.
3803
3804 @return On success 0 is returned, else error code.
3805*/
3806static int tavarua_suspend(struct platform_device *pdev, pm_message_t state)
3807{
3808 struct tavarua_device *radio = platform_get_drvdata(pdev);
3809 int retval;
3810 int users = 0;
3811 printk(KERN_INFO DRIVER_NAME "%s: radio suspend\n\n", __func__);
3812 if (radio) {
Anantha Krishnana2f98082011-10-04 20:02:11 +05303813 users = atomic_read(&radio->users);
Anantha Krishnan71bea3c2011-11-15 07:36:49 +05303814 if (!users) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003815 retval = tavarua_disable_interrupts(radio);
3816 if (retval < 0) {
3817 printk(KERN_INFO DRIVER_NAME
3818 "tavarua_suspend error %d\n", retval);
3819 return -EIO;
3820 }
3821 }
3822 }
3823 return 0;
3824}
3825
3826/*==============================================================
3827FUNCTION: tavarua_resume
3828==============================================================*/
3829/**
3830 Restore state of each device in system.
3831
3832 @param pdev: platform device to be resumed.
3833
3834 @return On success 0 is returned, else error code.
3835*/
3836static int tavarua_resume(struct platform_device *pdev)
3837{
3838
3839 struct tavarua_device *radio = platform_get_drvdata(pdev);
3840 int retval;
3841 int users = 0;
3842 printk(KERN_INFO DRIVER_NAME "%s: radio resume\n\n", __func__);
3843 if (radio) {
Anantha Krishnana2f98082011-10-04 20:02:11 +05303844 users = atomic_read(&radio->users);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003845
Anantha Krishnan71bea3c2011-11-15 07:36:49 +05303846 if (!users) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003847 retval = tavarua_setup_interrupts(radio,
3848 (radio->registers[RDCTRL] & 0x03));
3849 if (retval < 0) {
3850 printk(KERN_INFO DRIVER_NAME "Error in \
3851 tavarua_resume %d\n", retval);
3852 return -EIO;
3853 }
3854 }
3855 }
3856 return 0;
3857}
3858
3859/*==============================================================
3860FUNCTION: tavarua_set_audio_path
3861==============================================================*/
3862/**
3863 This function will configure the audio path to and from the
3864 FM core.
3865
3866 This interface is expected to be called from the multimedia
3867 driver's thread. This interface should only be called when
3868 the FM hardware is enabled. If the FM hardware is not
3869 currently enabled, this interface will return an error.
3870
3871 @param digital_on: Digital audio from the FM core should be enabled/disbled.
3872 @param analog_on: Analog audio from the FM core should be enabled/disbled.
3873
3874 @return On success 0 is returned, else error code.
3875*/
3876int tavarua_set_audio_path(int digital_on, int analog_on)
3877{
3878 struct tavarua_device *radio = private_data;
3879 int rx_on = radio->registers[RDCTRL] & FM_RECV;
3880 if (!radio)
3881 return -ENOMEM;
3882 /* RX */
3883 FMDBG("%s: digital: %d analog: %d\n", __func__, digital_on, analog_on);
3884 SET_REG_FIELD(radio->registers[AUDIOCTRL],
3885 ((rx_on && analog_on) ? 1 : 0),
3886 AUDIORX_ANALOG_OFFSET,
3887 AUDIORX_ANALOG_MASK);
3888 SET_REG_FIELD(radio->registers[AUDIOCTRL],
3889 ((rx_on && digital_on) ? 1 : 0),
3890 AUDIORX_DIGITAL_OFFSET,
3891 AUDIORX_DIGITAL_MASK);
3892 SET_REG_FIELD(radio->registers[AUDIOCTRL],
3893 (rx_on ? 0 : 1),
3894 AUDIOTX_OFFSET,
3895 AUDIOTX_MASK);
3896 /*
3897
3898 I2S Master/Slave configuration:
3899 Setting the FM SoC as I2S Master/Slave
3900 'false' - FM SoC is I2S Slave
3901 'true' - FM SoC is I2S Master
3902
3903 We get this infomation from the respective target's board file :
3904 MSM7x30 - FM SoC is I2S Slave
3905 MSM8x60 - FM SoC is I2S Slave
3906 MSM7x27A - FM SoC is I2S Master
3907 */
3908
3909 if (!radio->pdata->is_fm_soc_i2s_master) {
3910 FMDBG("FM SoC is I2S Slave\n");
3911 SET_REG_FIELD(radio->registers[AUDIOCTRL],
3912 (0),
3913 I2SCTRL_OFFSET,
3914 I2SCTRL_MASK);
3915 } else {
3916 FMDBG("FM SoC is I2S Master\n");
3917 SET_REG_FIELD(radio->registers[AUDIOCTRL],
3918 (1),
3919 I2SCTRL_OFFSET,
3920 I2SCTRL_MASK);
3921 }
3922 FMDBG("%s: %x\n", __func__, radio->registers[AUDIOCTRL]);
3923 return tavarua_write_register(radio, AUDIOCTRL,
3924 radio->registers[AUDIOCTRL]);
3925
3926}
3927
3928/*==============================================================
3929FUNCTION: tavarua_probe
3930==============================================================*/
3931/**
3932 Once called this functions initiates, allocates resources and registers video
3933 tuner device with the v4l2 framework.
3934
3935 NOTE:
3936 probe() should verify that the specified device hardware
3937 actually exists; sometimes platform setup code can't be sure. The probing
3938 can use device resources, including clocks, and device platform_data.
3939
3940 @param pdev: platform device to be probed.
3941
3942 @return On success 0 is returned, else error code.
3943 -ENOMEM in low memory cases
3944*/
3945static int __init tavarua_probe(struct platform_device *pdev)
3946{
3947
3948 struct marimba_fm_platform_data *tavarua_pdata;
3949 struct tavarua_device *radio;
3950 int retval;
3951 int i;
3952 FMDBG("%s: probe called\n", __func__);
3953 /* private data allocation */
3954 radio = kzalloc(sizeof(struct tavarua_device), GFP_KERNEL);
3955 if (!radio) {
3956 retval = -ENOMEM;
3957 goto err_initial;
3958 }
3959
3960 radio->marimba = platform_get_drvdata(pdev);
3961 tavarua_pdata = pdev->dev.platform_data;
3962 radio->pdata = tavarua_pdata;
3963 radio->dev = &pdev->dev;
3964 platform_set_drvdata(pdev, radio);
3965
3966 /* video device allocation */
3967 radio->videodev = video_device_alloc();
3968 if (!radio->videodev)
3969 goto err_radio;
3970
3971 /* initial configuration */
3972 memcpy(radio->videodev, &tavarua_viddev_template,
3973 sizeof(tavarua_viddev_template));
3974
3975 /*allocate internal buffers for decoded rds and event buffer*/
3976 for (i = 0; i < TAVARUA_BUF_MAX; i++) {
3977 int kfifo_alloc_rc=0;
3978 spin_lock_init(&radio->buf_lock[i]);
3979
3980 if (i == TAVARUA_BUF_RAW_RDS)
3981 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3982 rds_buf*3, GFP_KERNEL);
Srinivasa Rao Uppalad09f24a2012-01-13 19:10:39 +05303983 else if (i == TAVARUA_BUF_RT_RDS)
3984 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3985 STD_BUF_SIZE * 2, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003986 else
3987 kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
3988 STD_BUF_SIZE, GFP_KERNEL);
3989
3990 if (kfifo_alloc_rc!=0) {
3991 printk(KERN_ERR "%s: failed allocating buffers %d\n",
3992 __func__, kfifo_alloc_rc);
3993 goto err_bufs;
3994 }
3995 }
Anantha Krishnana2f98082011-10-04 20:02:11 +05303996 /* initializing the device count */
3997 atomic_set(&radio->users, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003998 radio->xfr_in_progress = 0;
3999 radio->xfr_bytes_left = 0;
4000 for (i = 0; i < TAVARUA_XFR_MAX; i++)
4001 radio->pending_xfrs[i] = 0;
4002
4003 /* init transmit data */
4004 radio->tx_mode = TAVARUA_TX_RT;
4005 /* Init RT and PS Tx datas*/
4006 radio->pty = 0;
4007 radio->pi = 0;
4008 radio->ps_repeatcount = 0;
4009 /* init search params */
4010 radio->srch_params.srch_pty = 0;
4011 radio->srch_params.srch_pi = 0;
4012 radio->srch_params.preset_num = 0;
4013 radio->srch_params.get_list = 0;
4014 /* radio initializes to low power mode */
4015 radio->lp_mode = 1;
4016 radio->handle_irq = 1;
4017 /* init lock */
4018 mutex_init(&radio->lock);
4019 /* init completion flags */
4020 init_completion(&radio->sync_xfr_start);
4021 init_completion(&radio->sync_req_done);
4022 radio->tune_req = 0;
4023 /* initialize wait queue for event read */
4024 init_waitqueue_head(&radio->event_queue);
4025 /* initialize wait queue for raw rds read */
4026 init_waitqueue_head(&radio->read_queue);
4027
4028 video_set_drvdata(radio->videodev, radio);
4029 /*Start the worker thread for event handling and register read_int_stat
4030 as worker function*/
4031 INIT_DELAYED_WORK(&radio->work, read_int_stat);
4032
4033 /* register video device */
4034 if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
4035 printk(KERN_WARNING DRIVER_NAME
4036 ": Could not register video device\n");
4037 goto err_all;
4038 }
4039 private_data = radio;
4040 return 0;
4041
4042err_all:
4043 video_device_release(radio->videodev);
4044err_bufs:
4045 for (; i > -1; i--)
4046 kfifo_free(&radio->data_buf[i]);
4047err_radio:
4048 kfree(radio);
4049err_initial:
4050 return retval;
4051}
4052
4053/*==============================================================
4054FUNCTION: tavarua_remove
4055==============================================================*/
4056/**
4057 Removes the device.
4058
4059 @param pdev: platform device to be removed.
4060
4061 @return On success 0 is returned, else error code.
4062*/
4063static int __devexit tavarua_remove(struct platform_device *pdev)
4064{
4065 int i;
4066 struct tavarua_device *radio = platform_get_drvdata(pdev);
4067
4068 /* disable irq */
4069 tavarua_disable_irq(radio);
4070
4071 video_unregister_device(radio->videodev);
4072
4073 /* free internal buffers */
4074 for (i = 0; i < TAVARUA_BUF_MAX; i++)
4075 kfifo_free(&radio->data_buf[i]);
4076
4077 /* free state struct */
4078 kfree(radio);
4079
4080 platform_set_drvdata(pdev, NULL);
4081
4082 return 0;
4083}
4084
4085/*
4086 Platform drivers follow the standard driver model convention, where
4087 discovery/enumeration is handled outside the drivers, and drivers
4088 provide probe() and remove() methods. They support power management
4089 and shutdown notifications using the standard conventions.
4090*/
4091static struct platform_driver tavarua_driver = {
4092 .driver = {
4093 .owner = THIS_MODULE,
4094 .name = "marimba_fm",
4095 },
4096 .remove = __devexit_p(tavarua_remove),
4097 .suspend = tavarua_suspend,
4098 .resume = tavarua_resume,
4099}; /* platform device we're adding */
4100
4101
4102/*************************************************************************
4103 * Module Interface
4104 ************************************************************************/
4105
4106/*==============================================================
4107FUNCTION: radio_module_init
4108==============================================================*/
4109/**
4110 Module entry - add a platform-level device.
4111
4112 @return Returns zero if the driver registered and bound to a device, else
4113 returns a negative error code when the driver not registered.
4114*/
4115static int __init radio_module_init(void)
4116{
4117 printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n");
4118 return platform_driver_probe(&tavarua_driver, tavarua_probe);
4119}
4120
4121/*==============================================================
4122FUNCTION: radio_module_exit
4123==============================================================*/
4124/**
4125 Module exit - removes a platform-level device.
4126
4127 NOTE:
4128 Note that this function will also release all memory- and port-based
4129 resources owned by the device (dev->resource).
4130
4131 @return none.
4132*/
4133static void __exit radio_module_exit(void)
4134{
4135 platform_driver_unregister(&tavarua_driver);
4136}
4137
4138MODULE_LICENSE("GPL v2");
4139MODULE_AUTHOR(DRIVER_AUTHOR);
4140MODULE_DESCRIPTION(DRIVER_DESC);
4141MODULE_VERSION(DRIVER_VERSION);
4142
4143module_init(radio_module_init);
4144module_exit(radio_module_exit);
4145