Merge branch 'sh-latest' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal...
[pandora-kernel.git] / drivers / media / radio / si470x / radio-si470x-common.c
1 /*
2  *  drivers/media/radio/si470x/radio-si470x-common.c
3  *
4  *  Driver for radios with Silicon Labs Si470x FM Radio Receivers
5  *
6  *  Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.net>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  */
22
23
24 /*
25  * History:
26  * 2008-01-12   Tobias Lorenz <tobias.lorenz@gmx.net>
27  *              Version 1.0.0
28  *              - First working version
29  * 2008-01-13   Tobias Lorenz <tobias.lorenz@gmx.net>
30  *              Version 1.0.1
31  *              - Improved error handling, every function now returns errno
32  *              - Improved multi user access (start/mute/stop)
33  *              - Channel doesn't get lost anymore after start/mute/stop
34  *              - RDS support added (polling mode via interrupt EP 1)
35  *              - marked default module parameters with *value*
36  *              - switched from bit structs to bit masks
37  *              - header file cleaned and integrated
38  * 2008-01-14   Tobias Lorenz <tobias.lorenz@gmx.net>
39  *              Version 1.0.2
40  *              - hex values are now lower case
41  *              - commented USB ID for ADS/Tech moved on todo list
42  *              - blacklisted si470x in hid-quirks.c
43  *              - rds buffer handling functions integrated into *_work, *_read
44  *              - rds_command in si470x_poll exchanged against simple retval
45  *              - check for firmware version 15
46  *              - code order and prototypes still remain the same
47  *              - spacing and bottom of band codes remain the same
48  * 2008-01-16   Tobias Lorenz <tobias.lorenz@gmx.net>
49  *              Version 1.0.3
50  *              - code reordered to avoid function prototypes
51  *              - switch/case defaults are now more user-friendly
52  *              - unified comment style
53  *              - applied all checkpatch.pl v1.12 suggestions
54  *                except the warning about the too long lines with bit comments
55  *              - renamed FMRADIO to RADIO to cut line length (checkpatch.pl)
56  * 2008-01-22   Tobias Lorenz <tobias.lorenz@gmx.net>
57  *              Version 1.0.4
58  *              - avoid poss. locking when doing copy_to_user which may sleep
59  *              - RDS is automatically activated on read now
60  *              - code cleaned of unnecessary rds_commands
61  *              - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified
62  *                (thanks to Guillaume RAMOUSSE)
63  * 2008-01-27   Tobias Lorenz <tobias.lorenz@gmx.net>
64  *              Version 1.0.5
65  *              - number of seek_retries changed to tune_timeout
66  *              - fixed problem with incomplete tune operations by own buffers
67  *              - optimization of variables and printf types
68  *              - improved error logging
69  * 2008-01-31   Tobias Lorenz <tobias.lorenz@gmx.net>
70  *              Oliver Neukum <oliver@neukum.org>
71  *              Version 1.0.6
72  *              - fixed coverity checker warnings in *_usb_driver_disconnect
73  *              - probe()/open() race by correct ordering in probe()
74  *              - DMA coherency rules by separate allocation of all buffers
75  *              - use of endianness macros
76  *              - abuse of spinlock, replaced by mutex
77  *              - racy handling of timer in disconnect,
78  *                replaced by delayed_work
79  *              - racy interruptible_sleep_on(),
80  *                replaced with wait_event_interruptible()
81  *              - handle signals in read()
82  * 2008-02-08   Tobias Lorenz <tobias.lorenz@gmx.net>
83  *              Oliver Neukum <oliver@neukum.org>
84  *              Version 1.0.7
85  *              - usb autosuspend support
86  *              - unplugging fixed
87  * 2008-05-07   Tobias Lorenz <tobias.lorenz@gmx.net>
88  *              Version 1.0.8
89  *              - hardware frequency seek support
90  *              - afc indication
91  *              - more safety checks, let si470x_get_freq return errno
92  *              - vidioc behavior corrected according to v4l2 spec
93  * 2008-10-20   Alexey Klimov <klimov.linux@gmail.com>
94  *              - add support for KWorld USB FM Radio FM700
95  *              - blacklisted KWorld radio in hid-core.c and hid-ids.h
96  * 2008-12-03   Mark Lord <mlord@pobox.com>
97  *              - add support for DealExtreme USB Radio
98  * 2009-01-31   Bob Ross <pigiron@gmx.com>
99  *              - correction of stereo detection/setting
100  *              - correction of signal strength indicator scaling
101  * 2009-01-31   Rick Bronson <rick@efn.org>
102  *              Tobias Lorenz <tobias.lorenz@gmx.net>
103  *              - add LED status output
104  *              - get HW/SW version from scratchpad
105  * 2009-06-16   Edouard Lafargue <edouard@lafargue.name>
106  *              Version 1.0.10
107  *              - add support for interrupt mode for RDS endpoint,
108  *                instead of polling.
109  *                Improves RDS reception significantly
110  */
111
112
113 /* kernel includes */
114 #include "radio-si470x.h"
115
116
117
118 /**************************************************************************
119  * Module Parameters
120  **************************************************************************/
121
122 /* Spacing (kHz) */
123 /* 0: 200 kHz (USA, Australia) */
124 /* 1: 100 kHz (Europe, Japan) */
125 /* 2:  50 kHz */
126 static unsigned short space = 2;
127 module_param(space, ushort, 0444);
128 MODULE_PARM_DESC(space, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
129
130 /* Bottom of Band (MHz) */
131 /* 0: 87.5 - 108 MHz (USA, Europe)*/
132 /* 1: 76   - 108 MHz (Japan wide band) */
133 /* 2: 76   -  90 MHz (Japan) */
134 static unsigned short band = 1;
135 module_param(band, ushort, 0444);
136 MODULE_PARM_DESC(band, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
137
138 /* De-emphasis */
139 /* 0: 75 us (USA) */
140 /* 1: 50 us (Europe, Australia, Japan) */
141 static unsigned short de = 1;
142 module_param(de, ushort, 0444);
143 MODULE_PARM_DESC(de, "De-emphasis: 0=75us *1=50us*");
144
145 /* Tune timeout */
146 static unsigned int tune_timeout = 3000;
147 module_param(tune_timeout, uint, 0644);
148 MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*");
149
150 /* Seek timeout */
151 static unsigned int seek_timeout = 5000;
152 module_param(seek_timeout, uint, 0644);
153 MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*");
154
155
156
157 /**************************************************************************
158  * Generic Functions
159  **************************************************************************/
160
161 /*
162  * si470x_set_chan - set the channel
163  */
164 static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
165 {
166         int retval;
167         unsigned long timeout;
168         bool timed_out = 0;
169
170         /* start tuning */
171         radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
172         radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
173         retval = si470x_set_register(radio, CHANNEL);
174         if (retval < 0)
175                 goto done;
176
177         /* currently I2C driver only uses interrupt way to tune */
178         if (radio->stci_enabled) {
179                 INIT_COMPLETION(radio->completion);
180
181                 /* wait till tune operation has completed */
182                 retval = wait_for_completion_timeout(&radio->completion,
183                                 msecs_to_jiffies(tune_timeout));
184                 if (!retval)
185                         timed_out = true;
186         } else {
187                 /* wait till tune operation has completed */
188                 timeout = jiffies + msecs_to_jiffies(tune_timeout);
189                 do {
190                         retval = si470x_get_register(radio, STATUSRSSI);
191                         if (retval < 0)
192                                 goto stop;
193                         timed_out = time_after(jiffies, timeout);
194                 } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
195                                 && (!timed_out));
196         }
197
198         if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
199                 dev_warn(&radio->videodev->dev, "tune does not complete\n");
200         if (timed_out)
201                 dev_warn(&radio->videodev->dev,
202                         "tune timed out after %u ms\n", tune_timeout);
203
204 stop:
205         /* stop tuning */
206         radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
207         retval = si470x_set_register(radio, CHANNEL);
208
209 done:
210         return retval;
211 }
212
213
214 /*
215  * si470x_get_freq - get the frequency
216  */
217 static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq)
218 {
219         unsigned int spacing, band_bottom;
220         unsigned short chan;
221         int retval;
222
223         /* Spacing (kHz) */
224         switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
225         /* 0: 200 kHz (USA, Australia) */
226         case 0:
227                 spacing = 0.200 * FREQ_MUL; break;
228         /* 1: 100 kHz (Europe, Japan) */
229         case 1:
230                 spacing = 0.100 * FREQ_MUL; break;
231         /* 2:  50 kHz */
232         default:
233                 spacing = 0.050 * FREQ_MUL; break;
234         };
235
236         /* Bottom of Band (MHz) */
237         switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
238         /* 0: 87.5 - 108 MHz (USA, Europe) */
239         case 0:
240                 band_bottom = 87.5 * FREQ_MUL; break;
241         /* 1: 76   - 108 MHz (Japan wide band) */
242         default:
243                 band_bottom = 76   * FREQ_MUL; break;
244         /* 2: 76   -  90 MHz (Japan) */
245         case 2:
246                 band_bottom = 76   * FREQ_MUL; break;
247         };
248
249         /* read channel */
250         retval = si470x_get_register(radio, READCHAN);
251         chan = radio->registers[READCHAN] & READCHAN_READCHAN;
252
253         /* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */
254         *freq = chan * spacing + band_bottom;
255
256         return retval;
257 }
258
259
260 /*
261  * si470x_set_freq - set the frequency
262  */
263 int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
264 {
265         unsigned int spacing, band_bottom;
266         unsigned short chan;
267
268         /* Spacing (kHz) */
269         switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
270         /* 0: 200 kHz (USA, Australia) */
271         case 0:
272                 spacing = 0.200 * FREQ_MUL; break;
273         /* 1: 100 kHz (Europe, Japan) */
274         case 1:
275                 spacing = 0.100 * FREQ_MUL; break;
276         /* 2:  50 kHz */
277         default:
278                 spacing = 0.050 * FREQ_MUL; break;
279         };
280
281         /* Bottom of Band (MHz) */
282         switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
283         /* 0: 87.5 - 108 MHz (USA, Europe) */
284         case 0:
285                 band_bottom = 87.5 * FREQ_MUL; break;
286         /* 1: 76   - 108 MHz (Japan wide band) */
287         default:
288                 band_bottom = 76   * FREQ_MUL; break;
289         /* 2: 76   -  90 MHz (Japan) */
290         case 2:
291                 band_bottom = 76   * FREQ_MUL; break;
292         };
293
294         /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
295         chan = (freq - band_bottom) / spacing;
296
297         return si470x_set_chan(radio, chan);
298 }
299
300
301 /*
302  * si470x_set_seek - set seek
303  */
304 static int si470x_set_seek(struct si470x_device *radio,
305                 unsigned int wrap_around, unsigned int seek_upward)
306 {
307         int retval = 0;
308         unsigned long timeout;
309         bool timed_out = 0;
310
311         /* start seeking */
312         radio->registers[POWERCFG] |= POWERCFG_SEEK;
313         if (wrap_around == 1)
314                 radio->registers[POWERCFG] &= ~POWERCFG_SKMODE;
315         else
316                 radio->registers[POWERCFG] |= POWERCFG_SKMODE;
317         if (seek_upward == 1)
318                 radio->registers[POWERCFG] |= POWERCFG_SEEKUP;
319         else
320                 radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP;
321         retval = si470x_set_register(radio, POWERCFG);
322         if (retval < 0)
323                 goto done;
324
325         /* currently I2C driver only uses interrupt way to seek */
326         if (radio->stci_enabled) {
327                 INIT_COMPLETION(radio->completion);
328
329                 /* wait till seek operation has completed */
330                 retval = wait_for_completion_timeout(&radio->completion,
331                                 msecs_to_jiffies(seek_timeout));
332                 if (!retval)
333                         timed_out = true;
334         } else {
335                 /* wait till seek operation has completed */
336                 timeout = jiffies + msecs_to_jiffies(seek_timeout);
337                 do {
338                         retval = si470x_get_register(radio, STATUSRSSI);
339                         if (retval < 0)
340                                 goto stop;
341                         timed_out = time_after(jiffies, timeout);
342                 } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
343                                 && (!timed_out));
344         }
345
346         if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
347                 dev_warn(&radio->videodev->dev, "seek does not complete\n");
348         if (radio->registers[STATUSRSSI] & STATUSRSSI_SF)
349                 dev_warn(&radio->videodev->dev,
350                         "seek failed / band limit reached\n");
351         if (timed_out)
352                 dev_warn(&radio->videodev->dev,
353                         "seek timed out after %u ms\n", seek_timeout);
354
355 stop:
356         /* stop seeking */
357         radio->registers[POWERCFG] &= ~POWERCFG_SEEK;
358         retval = si470x_set_register(radio, POWERCFG);
359
360 done:
361         /* try again, if timed out */
362         if ((retval == 0) && timed_out)
363                 retval = -EAGAIN;
364
365         return retval;
366 }
367
368
369 /*
370  * si470x_start - switch on radio
371  */
372 int si470x_start(struct si470x_device *radio)
373 {
374         int retval;
375
376         /* powercfg */
377         radio->registers[POWERCFG] =
378                 POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
379         retval = si470x_set_register(radio, POWERCFG);
380         if (retval < 0)
381                 goto done;
382
383         /* sysconfig 1 */
384         radio->registers[SYSCONFIG1] =
385                 (de << 11) & SYSCONFIG1_DE;             /* DE*/
386         retval = si470x_set_register(radio, SYSCONFIG1);
387         if (retval < 0)
388                 goto done;
389
390         /* sysconfig 2 */
391         radio->registers[SYSCONFIG2] =
392                 (0x3f  << 8) |                          /* SEEKTH */
393                 ((band  << 6) & SYSCONFIG2_BAND)  |     /* BAND */
394                 ((space << 4) & SYSCONFIG2_SPACE) |     /* SPACE */
395                 15;                                     /* VOLUME (max) */
396         retval = si470x_set_register(radio, SYSCONFIG2);
397         if (retval < 0)
398                 goto done;
399
400         /* reset last channel */
401         retval = si470x_set_chan(radio,
402                 radio->registers[CHANNEL] & CHANNEL_CHAN);
403
404 done:
405         return retval;
406 }
407
408
409 /*
410  * si470x_stop - switch off radio
411  */
412 int si470x_stop(struct si470x_device *radio)
413 {
414         int retval;
415
416         /* sysconfig 1 */
417         radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
418         retval = si470x_set_register(radio, SYSCONFIG1);
419         if (retval < 0)
420                 goto done;
421
422         /* powercfg */
423         radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
424         /* POWERCFG_ENABLE has to automatically go low */
425         radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE;
426         retval = si470x_set_register(radio, POWERCFG);
427
428 done:
429         return retval;
430 }
431
432
433 /*
434  * si470x_rds_on - switch on rds reception
435  */
436 static int si470x_rds_on(struct si470x_device *radio)
437 {
438         int retval;
439
440         /* sysconfig 1 */
441         radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
442         retval = si470x_set_register(radio, SYSCONFIG1);
443         if (retval < 0)
444                 radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
445
446         return retval;
447 }
448
449
450
451 /**************************************************************************
452  * File Operations Interface
453  **************************************************************************/
454
455 /*
456  * si470x_fops_read - read RDS data
457  */
458 static ssize_t si470x_fops_read(struct file *file, char __user *buf,
459                 size_t count, loff_t *ppos)
460 {
461         struct si470x_device *radio = video_drvdata(file);
462         int retval = 0;
463         unsigned int block_count = 0;
464
465         /* switch on rds reception */
466         mutex_lock(&radio->lock);
467         if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
468                 si470x_rds_on(radio);
469
470         /* block if no new data available */
471         while (radio->wr_index == radio->rd_index) {
472                 if (file->f_flags & O_NONBLOCK) {
473                         retval = -EWOULDBLOCK;
474                         goto done;
475                 }
476                 if (wait_event_interruptible(radio->read_queue,
477                         radio->wr_index != radio->rd_index) < 0) {
478                         retval = -EINTR;
479                         goto done;
480                 }
481         }
482
483         /* calculate block count from byte count */
484         count /= 3;
485
486         /* copy RDS block out of internal buffer and to user buffer */
487         while (block_count < count) {
488                 if (radio->rd_index == radio->wr_index)
489                         break;
490
491                 /* always transfer rds complete blocks */
492                 if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3))
493                         /* retval = -EFAULT; */
494                         break;
495
496                 /* increment and wrap read pointer */
497                 radio->rd_index += 3;
498                 if (radio->rd_index >= radio->buf_size)
499                         radio->rd_index = 0;
500
501                 /* increment counters */
502                 block_count++;
503                 buf += 3;
504                 retval += 3;
505         }
506
507 done:
508         mutex_unlock(&radio->lock);
509         return retval;
510 }
511
512
513 /*
514  * si470x_fops_poll - poll RDS data
515  */
516 static unsigned int si470x_fops_poll(struct file *file,
517                 struct poll_table_struct *pts)
518 {
519         struct si470x_device *radio = video_drvdata(file);
520         int retval = 0;
521
522         /* switch on rds reception */
523
524         mutex_lock(&radio->lock);
525         if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
526                 si470x_rds_on(radio);
527         mutex_unlock(&radio->lock);
528
529         poll_wait(file, &radio->read_queue, pts);
530
531         if (radio->rd_index != radio->wr_index)
532                 retval = POLLIN | POLLRDNORM;
533
534         return retval;
535 }
536
537
538 /*
539  * si470x_fops - file operations interface
540  */
541 static const struct v4l2_file_operations si470x_fops = {
542         .owner                  = THIS_MODULE,
543         .read                   = si470x_fops_read,
544         .poll                   = si470x_fops_poll,
545         .unlocked_ioctl         = video_ioctl2,
546         .open                   = si470x_fops_open,
547         .release                = si470x_fops_release,
548 };
549
550
551
552 /**************************************************************************
553  * Video4Linux Interface
554  **************************************************************************/
555
556 /*
557  * si470x_vidioc_queryctrl - enumerate control items
558  */
559 static int si470x_vidioc_queryctrl(struct file *file, void *priv,
560                 struct v4l2_queryctrl *qc)
561 {
562         struct si470x_device *radio = video_drvdata(file);
563         int retval = -EINVAL;
564
565         /* abort if qc->id is below V4L2_CID_BASE */
566         if (qc->id < V4L2_CID_BASE)
567                 goto done;
568
569         /* search video control */
570         switch (qc->id) {
571         case V4L2_CID_AUDIO_VOLUME:
572                 return v4l2_ctrl_query_fill(qc, 0, 15, 1, 15);
573         case V4L2_CID_AUDIO_MUTE:
574                 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
575         }
576
577         /* disable unsupported base controls */
578         /* to satisfy kradio and such apps */
579         if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) {
580                 qc->flags = V4L2_CTRL_FLAG_DISABLED;
581                 retval = 0;
582         }
583
584 done:
585         if (retval < 0)
586                 dev_warn(&radio->videodev->dev,
587                         "query controls failed with %d\n", retval);
588         return retval;
589 }
590
591
592 /*
593  * si470x_vidioc_g_ctrl - get the value of a control
594  */
595 static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
596                 struct v4l2_control *ctrl)
597 {
598         struct si470x_device *radio = video_drvdata(file);
599         int retval = 0;
600
601         mutex_lock(&radio->lock);
602         /* safety checks */
603         retval = si470x_disconnect_check(radio);
604         if (retval)
605                 goto done;
606
607         switch (ctrl->id) {
608         case V4L2_CID_AUDIO_VOLUME:
609                 ctrl->value = radio->registers[SYSCONFIG2] &
610                                 SYSCONFIG2_VOLUME;
611                 break;
612         case V4L2_CID_AUDIO_MUTE:
613                 ctrl->value = ((radio->registers[POWERCFG] &
614                                 POWERCFG_DMUTE) == 0) ? 1 : 0;
615                 break;
616         default:
617                 retval = -EINVAL;
618         }
619
620 done:
621         if (retval < 0)
622                 dev_warn(&radio->videodev->dev,
623                         "get control failed with %d\n", retval);
624
625         mutex_unlock(&radio->lock);
626         return retval;
627 }
628
629
630 /*
631  * si470x_vidioc_s_ctrl - set the value of a control
632  */
633 static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
634                 struct v4l2_control *ctrl)
635 {
636         struct si470x_device *radio = video_drvdata(file);
637         int retval = 0;
638
639         mutex_lock(&radio->lock);
640         /* safety checks */
641         retval = si470x_disconnect_check(radio);
642         if (retval)
643                 goto done;
644
645         switch (ctrl->id) {
646         case V4L2_CID_AUDIO_VOLUME:
647                 radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
648                 radio->registers[SYSCONFIG2] |= ctrl->value;
649                 retval = si470x_set_register(radio, SYSCONFIG2);
650                 break;
651         case V4L2_CID_AUDIO_MUTE:
652                 if (ctrl->value == 1)
653                         radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
654                 else
655                         radio->registers[POWERCFG] |= POWERCFG_DMUTE;
656                 retval = si470x_set_register(radio, POWERCFG);
657                 break;
658         default:
659                 retval = -EINVAL;
660         }
661
662 done:
663         if (retval < 0)
664                 dev_warn(&radio->videodev->dev,
665                         "set control failed with %d\n", retval);
666         mutex_unlock(&radio->lock);
667         return retval;
668 }
669
670
671 /*
672  * si470x_vidioc_g_audio - get audio attributes
673  */
674 static int si470x_vidioc_g_audio(struct file *file, void *priv,
675                 struct v4l2_audio *audio)
676 {
677         /* driver constants */
678         audio->index = 0;
679         strcpy(audio->name, "Radio");
680         audio->capability = V4L2_AUDCAP_STEREO;
681         audio->mode = 0;
682
683         return 0;
684 }
685
686
687 /*
688  * si470x_vidioc_g_tuner - get tuner attributes
689  */
690 static int si470x_vidioc_g_tuner(struct file *file, void *priv,
691                 struct v4l2_tuner *tuner)
692 {
693         struct si470x_device *radio = video_drvdata(file);
694         int retval = 0;
695
696         mutex_lock(&radio->lock);
697         /* safety checks */
698         retval = si470x_disconnect_check(radio);
699         if (retval)
700                 goto done;
701
702         if (tuner->index != 0) {
703                 retval = -EINVAL;
704                 goto done;
705         }
706
707         retval = si470x_get_register(radio, STATUSRSSI);
708         if (retval < 0)
709                 goto done;
710
711         /* driver constants */
712         strcpy(tuner->name, "FM");
713         tuner->type = V4L2_TUNER_RADIO;
714         tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
715                             V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO;
716
717         /* range limits */
718         switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
719         /* 0: 87.5 - 108 MHz (USA, Europe, default) */
720         default:
721                 tuner->rangelow  =  87.5 * FREQ_MUL;
722                 tuner->rangehigh = 108   * FREQ_MUL;
723                 break;
724         /* 1: 76   - 108 MHz (Japan wide band) */
725         case 1:
726                 tuner->rangelow  =  76   * FREQ_MUL;
727                 tuner->rangehigh = 108   * FREQ_MUL;
728                 break;
729         /* 2: 76   -  90 MHz (Japan) */
730         case 2:
731                 tuner->rangelow  =  76   * FREQ_MUL;
732                 tuner->rangehigh =  90   * FREQ_MUL;
733                 break;
734         };
735
736         /* stereo indicator == stereo (instead of mono) */
737         if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0)
738                 tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
739         else
740                 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
741         /* If there is a reliable method of detecting an RDS channel,
742            then this code should check for that before setting this
743            RDS subchannel. */
744         tuner->rxsubchans |= V4L2_TUNER_SUB_RDS;
745
746         /* mono/stereo selector */
747         if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0)
748                 tuner->audmode = V4L2_TUNER_MODE_STEREO;
749         else
750                 tuner->audmode = V4L2_TUNER_MODE_MONO;
751
752         /* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
753         /* measured in units of dbµV in 1 db increments (max at ~75 dbµV) */
754         tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI);
755         /* the ideal factor is 0xffff/75 = 873,8 */
756         tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10);
757
758         /* automatic frequency control: -1: freq to low, 1 freq to high */
759         /* AFCRL does only indicate that freq. differs, not if too low/high */
760         tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0;
761
762 done:
763         if (retval < 0)
764                 dev_warn(&radio->videodev->dev,
765                         "get tuner failed with %d\n", retval);
766         mutex_unlock(&radio->lock);
767         return retval;
768 }
769
770
771 /*
772  * si470x_vidioc_s_tuner - set tuner attributes
773  */
774 static int si470x_vidioc_s_tuner(struct file *file, void *priv,
775                 struct v4l2_tuner *tuner)
776 {
777         struct si470x_device *radio = video_drvdata(file);
778         int retval = 0;
779
780         mutex_lock(&radio->lock);
781         /* safety checks */
782         retval = si470x_disconnect_check(radio);
783         if (retval)
784                 goto done;
785
786         if (tuner->index != 0)
787                 goto done;
788
789         /* mono/stereo selector */
790         switch (tuner->audmode) {
791         case V4L2_TUNER_MODE_MONO:
792                 radio->registers[POWERCFG] |= POWERCFG_MONO;  /* force mono */
793                 break;
794         case V4L2_TUNER_MODE_STEREO:
795                 radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
796                 break;
797         default:
798                 goto done;
799         }
800
801         retval = si470x_set_register(radio, POWERCFG);
802
803 done:
804         if (retval < 0)
805                 dev_warn(&radio->videodev->dev,
806                         "set tuner failed with %d\n", retval);
807         mutex_unlock(&radio->lock);
808         return retval;
809 }
810
811
812 /*
813  * si470x_vidioc_g_frequency - get tuner or modulator radio frequency
814  */
815 static int si470x_vidioc_g_frequency(struct file *file, void *priv,
816                 struct v4l2_frequency *freq)
817 {
818         struct si470x_device *radio = video_drvdata(file);
819         int retval = 0;
820
821         /* safety checks */
822         mutex_lock(&radio->lock);
823         retval = si470x_disconnect_check(radio);
824         if (retval)
825                 goto done;
826
827         if (freq->tuner != 0) {
828                 retval = -EINVAL;
829                 goto done;
830         }
831
832         freq->type = V4L2_TUNER_RADIO;
833         retval = si470x_get_freq(radio, &freq->frequency);
834
835 done:
836         if (retval < 0)
837                 dev_warn(&radio->videodev->dev,
838                         "get frequency failed with %d\n", retval);
839         mutex_unlock(&radio->lock);
840         return retval;
841 }
842
843
844 /*
845  * si470x_vidioc_s_frequency - set tuner or modulator radio frequency
846  */
847 static int si470x_vidioc_s_frequency(struct file *file, void *priv,
848                 struct v4l2_frequency *freq)
849 {
850         struct si470x_device *radio = video_drvdata(file);
851         int retval = 0;
852
853         mutex_lock(&radio->lock);
854         /* safety checks */
855         retval = si470x_disconnect_check(radio);
856         if (retval)
857                 goto done;
858
859         if (freq->tuner != 0) {
860                 retval = -EINVAL;
861                 goto done;
862         }
863
864         retval = si470x_set_freq(radio, freq->frequency);
865
866 done:
867         if (retval < 0)
868                 dev_warn(&radio->videodev->dev,
869                         "set frequency failed with %d\n", retval);
870         mutex_unlock(&radio->lock);
871         return retval;
872 }
873
874
875 /*
876  * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek
877  */
878 static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
879                 struct v4l2_hw_freq_seek *seek)
880 {
881         struct si470x_device *radio = video_drvdata(file);
882         int retval = 0;
883
884         mutex_lock(&radio->lock);
885         /* safety checks */
886         retval = si470x_disconnect_check(radio);
887         if (retval)
888                 goto done;
889
890         if (seek->tuner != 0) {
891                 retval = -EINVAL;
892                 goto done;
893         }
894
895         retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward);
896
897 done:
898         if (retval < 0)
899                 dev_warn(&radio->videodev->dev,
900                         "set hardware frequency seek failed with %d\n", retval);
901         mutex_unlock(&radio->lock);
902         return retval;
903 }
904
905
906 /*
907  * si470x_ioctl_ops - video device ioctl operations
908  */
909 static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
910         .vidioc_querycap        = si470x_vidioc_querycap,
911         .vidioc_queryctrl       = si470x_vidioc_queryctrl,
912         .vidioc_g_ctrl          = si470x_vidioc_g_ctrl,
913         .vidioc_s_ctrl          = si470x_vidioc_s_ctrl,
914         .vidioc_g_audio         = si470x_vidioc_g_audio,
915         .vidioc_g_tuner         = si470x_vidioc_g_tuner,
916         .vidioc_s_tuner         = si470x_vidioc_s_tuner,
917         .vidioc_g_frequency     = si470x_vidioc_g_frequency,
918         .vidioc_s_frequency     = si470x_vidioc_s_frequency,
919         .vidioc_s_hw_freq_seek  = si470x_vidioc_s_hw_freq_seek,
920 };
921
922
923 /*
924  * si470x_viddev_template - video device interface
925  */
926 struct video_device si470x_viddev_template = {
927         .fops                   = &si470x_fops,
928         .name                   = DRIVER_NAME,
929         .release                = video_device_release,
930         .ioctl_ops              = &si470x_ioctl_ops,
931 };