Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelv...
[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         /* wait till tune operation has completed */
178         timeout = jiffies + msecs_to_jiffies(tune_timeout);
179         do {
180                 retval = si470x_get_register(radio, STATUSRSSI);
181                 if (retval < 0)
182                         goto stop;
183                 timed_out = time_after(jiffies, timeout);
184         } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
185                 (!timed_out));
186         if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
187                 dev_warn(&radio->videodev->dev, "tune does not complete\n");
188         if (timed_out)
189                 dev_warn(&radio->videodev->dev,
190                         "tune timed out after %u ms\n", tune_timeout);
191
192 stop:
193         /* stop tuning */
194         radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
195         retval = si470x_set_register(radio, CHANNEL);
196
197 done:
198         return retval;
199 }
200
201
202 /*
203  * si470x_get_freq - get the frequency
204  */
205 static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq)
206 {
207         unsigned int spacing, band_bottom;
208         unsigned short chan;
209         int retval;
210
211         /* Spacing (kHz) */
212         switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
213         /* 0: 200 kHz (USA, Australia) */
214         case 0:
215                 spacing = 0.200 * FREQ_MUL; break;
216         /* 1: 100 kHz (Europe, Japan) */
217         case 1:
218                 spacing = 0.100 * FREQ_MUL; break;
219         /* 2:  50 kHz */
220         default:
221                 spacing = 0.050 * FREQ_MUL; break;
222         };
223
224         /* Bottom of Band (MHz) */
225         switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
226         /* 0: 87.5 - 108 MHz (USA, Europe) */
227         case 0:
228                 band_bottom = 87.5 * FREQ_MUL; break;
229         /* 1: 76   - 108 MHz (Japan wide band) */
230         default:
231                 band_bottom = 76   * FREQ_MUL; break;
232         /* 2: 76   -  90 MHz (Japan) */
233         case 2:
234                 band_bottom = 76   * FREQ_MUL; break;
235         };
236
237         /* read channel */
238         retval = si470x_get_register(radio, READCHAN);
239         chan = radio->registers[READCHAN] & READCHAN_READCHAN;
240
241         /* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */
242         *freq = chan * spacing + band_bottom;
243
244         return retval;
245 }
246
247
248 /*
249  * si470x_set_freq - set the frequency
250  */
251 int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
252 {
253         unsigned int spacing, band_bottom;
254         unsigned short chan;
255
256         /* Spacing (kHz) */
257         switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
258         /* 0: 200 kHz (USA, Australia) */
259         case 0:
260                 spacing = 0.200 * FREQ_MUL; break;
261         /* 1: 100 kHz (Europe, Japan) */
262         case 1:
263                 spacing = 0.100 * FREQ_MUL; break;
264         /* 2:  50 kHz */
265         default:
266                 spacing = 0.050 * FREQ_MUL; break;
267         };
268
269         /* Bottom of Band (MHz) */
270         switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
271         /* 0: 87.5 - 108 MHz (USA, Europe) */
272         case 0:
273                 band_bottom = 87.5 * FREQ_MUL; break;
274         /* 1: 76   - 108 MHz (Japan wide band) */
275         default:
276                 band_bottom = 76   * FREQ_MUL; break;
277         /* 2: 76   -  90 MHz (Japan) */
278         case 2:
279                 band_bottom = 76   * FREQ_MUL; break;
280         };
281
282         /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
283         chan = (freq - band_bottom) / spacing;
284
285         return si470x_set_chan(radio, chan);
286 }
287
288
289 /*
290  * si470x_set_seek - set seek
291  */
292 static int si470x_set_seek(struct si470x_device *radio,
293                 unsigned int wrap_around, unsigned int seek_upward)
294 {
295         int retval = 0;
296         unsigned long timeout;
297         bool timed_out = 0;
298
299         /* start seeking */
300         radio->registers[POWERCFG] |= POWERCFG_SEEK;
301         if (wrap_around == 1)
302                 radio->registers[POWERCFG] &= ~POWERCFG_SKMODE;
303         else
304                 radio->registers[POWERCFG] |= POWERCFG_SKMODE;
305         if (seek_upward == 1)
306                 radio->registers[POWERCFG] |= POWERCFG_SEEKUP;
307         else
308                 radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP;
309         retval = si470x_set_register(radio, POWERCFG);
310         if (retval < 0)
311                 goto done;
312
313         /* wait till seek operation has completed */
314         timeout = jiffies + msecs_to_jiffies(seek_timeout);
315         do {
316                 retval = si470x_get_register(radio, STATUSRSSI);
317                 if (retval < 0)
318                         goto stop;
319                 timed_out = time_after(jiffies, timeout);
320         } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
321                 (!timed_out));
322         if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
323                 dev_warn(&radio->videodev->dev, "seek does not complete\n");
324         if (radio->registers[STATUSRSSI] & STATUSRSSI_SF)
325                 dev_warn(&radio->videodev->dev,
326                         "seek failed / band limit reached\n");
327         if (timed_out)
328                 dev_warn(&radio->videodev->dev,
329                         "seek timed out after %u ms\n", seek_timeout);
330
331 stop:
332         /* stop seeking */
333         radio->registers[POWERCFG] &= ~POWERCFG_SEEK;
334         retval = si470x_set_register(radio, POWERCFG);
335
336 done:
337         /* try again, if timed out */
338         if ((retval == 0) && timed_out)
339                 retval = -EAGAIN;
340
341         return retval;
342 }
343
344
345 /*
346  * si470x_start - switch on radio
347  */
348 int si470x_start(struct si470x_device *radio)
349 {
350         int retval;
351
352         /* powercfg */
353         radio->registers[POWERCFG] =
354                 POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
355         retval = si470x_set_register(radio, POWERCFG);
356         if (retval < 0)
357                 goto done;
358
359         /* sysconfig 1 */
360         radio->registers[SYSCONFIG1] = SYSCONFIG1_DE;
361         retval = si470x_set_register(radio, SYSCONFIG1);
362         if (retval < 0)
363                 goto done;
364
365         /* sysconfig 2 */
366         radio->registers[SYSCONFIG2] =
367                 (0x3f  << 8) |                          /* SEEKTH */
368                 ((band  << 6) & SYSCONFIG2_BAND)  |     /* BAND */
369                 ((space << 4) & SYSCONFIG2_SPACE) |     /* SPACE */
370                 15;                                     /* VOLUME (max) */
371         retval = si470x_set_register(radio, SYSCONFIG2);
372         if (retval < 0)
373                 goto done;
374
375         /* reset last channel */
376         retval = si470x_set_chan(radio,
377                 radio->registers[CHANNEL] & CHANNEL_CHAN);
378
379 done:
380         return retval;
381 }
382
383
384 /*
385  * si470x_stop - switch off radio
386  */
387 int si470x_stop(struct si470x_device *radio)
388 {
389         int retval;
390
391         /* sysconfig 1 */
392         radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
393         retval = si470x_set_register(radio, SYSCONFIG1);
394         if (retval < 0)
395                 goto done;
396
397         /* powercfg */
398         radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
399         /* POWERCFG_ENABLE has to automatically go low */
400         radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE;
401         retval = si470x_set_register(radio, POWERCFG);
402
403 done:
404         return retval;
405 }
406
407
408 /*
409  * si470x_rds_on - switch on rds reception
410  */
411 static int si470x_rds_on(struct si470x_device *radio)
412 {
413         int retval;
414
415         /* sysconfig 1 */
416         radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
417         retval = si470x_set_register(radio, SYSCONFIG1);
418         if (retval < 0)
419                 radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
420
421         return retval;
422 }
423
424
425
426 /**************************************************************************
427  * File Operations Interface
428  **************************************************************************/
429
430 /*
431  * si470x_fops_read - read RDS data
432  */
433 static ssize_t si470x_fops_read(struct file *file, char __user *buf,
434                 size_t count, loff_t *ppos)
435 {
436         struct si470x_device *radio = video_drvdata(file);
437         int retval = 0;
438         unsigned int block_count = 0;
439
440         /* switch on rds reception */
441         mutex_lock(&radio->lock);
442         if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
443                 si470x_rds_on(radio);
444
445         /* block if no new data available */
446         while (radio->wr_index == radio->rd_index) {
447                 if (file->f_flags & O_NONBLOCK) {
448                         retval = -EWOULDBLOCK;
449                         goto done;
450                 }
451                 if (wait_event_interruptible(radio->read_queue,
452                         radio->wr_index != radio->rd_index) < 0) {
453                         retval = -EINTR;
454                         goto done;
455                 }
456         }
457
458         /* calculate block count from byte count */
459         count /= 3;
460
461         /* copy RDS block out of internal buffer and to user buffer */
462         mutex_lock(&radio->lock);
463         while (block_count < count) {
464                 if (radio->rd_index == radio->wr_index)
465                         break;
466
467                 /* always transfer rds complete blocks */
468                 if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3))
469                         /* retval = -EFAULT; */
470                         break;
471
472                 /* increment and wrap read pointer */
473                 radio->rd_index += 3;
474                 if (radio->rd_index >= radio->buf_size)
475                         radio->rd_index = 0;
476
477                 /* increment counters */
478                 block_count++;
479                 buf += 3;
480                 retval += 3;
481         }
482
483 done:
484         mutex_unlock(&radio->lock);
485         return retval;
486 }
487
488
489 /*
490  * si470x_fops_poll - poll RDS data
491  */
492 static unsigned int si470x_fops_poll(struct file *file,
493                 struct poll_table_struct *pts)
494 {
495         struct si470x_device *radio = video_drvdata(file);
496         int retval = 0;
497
498         /* switch on rds reception */
499
500         mutex_lock(&radio->lock);
501         if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
502                 si470x_rds_on(radio);
503         mutex_unlock(&radio->lock);
504
505         poll_wait(file, &radio->read_queue, pts);
506
507         if (radio->rd_index != radio->wr_index)
508                 retval = POLLIN | POLLRDNORM;
509
510         return retval;
511 }
512
513
514 /*
515  * si470x_fops - file operations interface
516  */
517 static const struct v4l2_file_operations si470x_fops = {
518         .owner                  = THIS_MODULE,
519         .read                   = si470x_fops_read,
520         .poll                   = si470x_fops_poll,
521         .unlocked_ioctl         = video_ioctl2,
522         .open                   = si470x_fops_open,
523         .release                = si470x_fops_release,
524 };
525
526
527
528 /**************************************************************************
529  * Video4Linux Interface
530  **************************************************************************/
531
532 /*
533  * si470x_vidioc_queryctrl - enumerate control items
534  */
535 static int si470x_vidioc_queryctrl(struct file *file, void *priv,
536                 struct v4l2_queryctrl *qc)
537 {
538         struct si470x_device *radio = video_drvdata(file);
539         int retval = -EINVAL;
540
541         /* abort if qc->id is below V4L2_CID_BASE */
542         if (qc->id < V4L2_CID_BASE)
543                 goto done;
544
545         /* search video control */
546         switch (qc->id) {
547         case V4L2_CID_AUDIO_VOLUME:
548                 return v4l2_ctrl_query_fill(qc, 0, 15, 1, 15);
549         case V4L2_CID_AUDIO_MUTE:
550                 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
551         }
552
553         /* disable unsupported base controls */
554         /* to satisfy kradio and such apps */
555         if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) {
556                 qc->flags = V4L2_CTRL_FLAG_DISABLED;
557                 retval = 0;
558         }
559
560 done:
561         if (retval < 0)
562                 dev_warn(&radio->videodev->dev,
563                         "query controls failed with %d\n", retval);
564         return retval;
565 }
566
567
568 /*
569  * si470x_vidioc_g_ctrl - get the value of a control
570  */
571 static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
572                 struct v4l2_control *ctrl)
573 {
574         struct si470x_device *radio = video_drvdata(file);
575         int retval = 0;
576
577         mutex_lock(&radio->lock);
578         /* safety checks */
579         retval = si470x_disconnect_check(radio);
580         if (retval)
581                 goto done;
582
583         switch (ctrl->id) {
584         case V4L2_CID_AUDIO_VOLUME:
585                 ctrl->value = radio->registers[SYSCONFIG2] &
586                                 SYSCONFIG2_VOLUME;
587                 break;
588         case V4L2_CID_AUDIO_MUTE:
589                 ctrl->value = ((radio->registers[POWERCFG] &
590                                 POWERCFG_DMUTE) == 0) ? 1 : 0;
591                 break;
592         default:
593                 retval = -EINVAL;
594         }
595
596 done:
597         if (retval < 0)
598                 dev_warn(&radio->videodev->dev,
599                         "get control failed with %d\n", retval);
600
601         mutex_unlock(&radio->lock);
602         return retval;
603 }
604
605
606 /*
607  * si470x_vidioc_s_ctrl - set the value of a control
608  */
609 static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
610                 struct v4l2_control *ctrl)
611 {
612         struct si470x_device *radio = video_drvdata(file);
613         int retval = 0;
614
615         mutex_lock(&radio->lock);
616         /* safety checks */
617         retval = si470x_disconnect_check(radio);
618         if (retval)
619                 goto done;
620
621         switch (ctrl->id) {
622         case V4L2_CID_AUDIO_VOLUME:
623                 radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
624                 radio->registers[SYSCONFIG2] |= ctrl->value;
625                 retval = si470x_set_register(radio, SYSCONFIG2);
626                 break;
627         case V4L2_CID_AUDIO_MUTE:
628                 if (ctrl->value == 1)
629                         radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
630                 else
631                         radio->registers[POWERCFG] |= POWERCFG_DMUTE;
632                 retval = si470x_set_register(radio, POWERCFG);
633                 break;
634         default:
635                 retval = -EINVAL;
636         }
637
638 done:
639         if (retval < 0)
640                 dev_warn(&radio->videodev->dev,
641                         "set control failed with %d\n", retval);
642         mutex_unlock(&radio->lock);
643         return retval;
644 }
645
646
647 /*
648  * si470x_vidioc_g_audio - get audio attributes
649  */
650 static int si470x_vidioc_g_audio(struct file *file, void *priv,
651                 struct v4l2_audio *audio)
652 {
653         /* driver constants */
654         audio->index = 0;
655         strcpy(audio->name, "Radio");
656         audio->capability = V4L2_AUDCAP_STEREO;
657         audio->mode = 0;
658
659         return 0;
660 }
661
662
663 /*
664  * si470x_vidioc_g_tuner - get tuner attributes
665  */
666 static int si470x_vidioc_g_tuner(struct file *file, void *priv,
667                 struct v4l2_tuner *tuner)
668 {
669         struct si470x_device *radio = video_drvdata(file);
670         int retval = 0;
671
672         mutex_lock(&radio->lock);
673         /* safety checks */
674         retval = si470x_disconnect_check(radio);
675         if (retval)
676                 goto done;
677
678         if (tuner->index != 0) {
679                 retval = -EINVAL;
680                 goto done;
681         }
682
683         retval = si470x_get_register(radio, STATUSRSSI);
684         if (retval < 0)
685                 goto done;
686
687         /* driver constants */
688         strcpy(tuner->name, "FM");
689         tuner->type = V4L2_TUNER_RADIO;
690 #if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
691         tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
692                             V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO;
693 #else
694         tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
695 #endif
696
697         /* range limits */
698         switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
699         /* 0: 87.5 - 108 MHz (USA, Europe, default) */
700         default:
701                 tuner->rangelow  =  87.5 * FREQ_MUL;
702                 tuner->rangehigh = 108   * FREQ_MUL;
703                 break;
704         /* 1: 76   - 108 MHz (Japan wide band) */
705         case 1:
706                 tuner->rangelow  =  76   * FREQ_MUL;
707                 tuner->rangehigh = 108   * FREQ_MUL;
708                 break;
709         /* 2: 76   -  90 MHz (Japan) */
710         case 2:
711                 tuner->rangelow  =  76   * FREQ_MUL;
712                 tuner->rangehigh =  90   * FREQ_MUL;
713                 break;
714         };
715
716         /* stereo indicator == stereo (instead of mono) */
717         if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0)
718                 tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
719         else
720                 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
721 #if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
722         /* If there is a reliable method of detecting an RDS channel,
723            then this code should check for that before setting this
724            RDS subchannel. */
725         tuner->rxsubchans |= V4L2_TUNER_SUB_RDS;
726 #endif
727
728         /* mono/stereo selector */
729         if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0)
730                 tuner->audmode = V4L2_TUNER_MODE_STEREO;
731         else
732                 tuner->audmode = V4L2_TUNER_MODE_MONO;
733
734         /* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
735         /* measured in units of dbµV in 1 db increments (max at ~75 dbµV) */
736         tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI);
737         /* the ideal factor is 0xffff/75 = 873,8 */
738         tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10);
739
740         /* automatic frequency control: -1: freq to low, 1 freq to high */
741         /* AFCRL does only indicate that freq. differs, not if too low/high */
742         tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0;
743
744 done:
745         if (retval < 0)
746                 dev_warn(&radio->videodev->dev,
747                         "get tuner failed with %d\n", retval);
748         mutex_unlock(&radio->lock);
749         return retval;
750 }
751
752
753 /*
754  * si470x_vidioc_s_tuner - set tuner attributes
755  */
756 static int si470x_vidioc_s_tuner(struct file *file, void *priv,
757                 struct v4l2_tuner *tuner)
758 {
759         struct si470x_device *radio = video_drvdata(file);
760         int retval = 0;
761
762         mutex_lock(&radio->lock);
763         /* safety checks */
764         retval = si470x_disconnect_check(radio);
765         if (retval)
766                 goto done;
767
768         if (tuner->index != 0)
769                 goto done;
770
771         /* mono/stereo selector */
772         switch (tuner->audmode) {
773         case V4L2_TUNER_MODE_MONO:
774                 radio->registers[POWERCFG] |= POWERCFG_MONO;  /* force mono */
775                 break;
776         case V4L2_TUNER_MODE_STEREO:
777                 radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
778                 break;
779         default:
780                 goto done;
781         }
782
783         retval = si470x_set_register(radio, POWERCFG);
784
785 done:
786         if (retval < 0)
787                 dev_warn(&radio->videodev->dev,
788                         "set tuner failed with %d\n", retval);
789         mutex_unlock(&radio->lock);
790         return retval;
791 }
792
793
794 /*
795  * si470x_vidioc_g_frequency - get tuner or modulator radio frequency
796  */
797 static int si470x_vidioc_g_frequency(struct file *file, void *priv,
798                 struct v4l2_frequency *freq)
799 {
800         struct si470x_device *radio = video_drvdata(file);
801         int retval = 0;
802
803         /* safety checks */
804         mutex_lock(&radio->lock);
805         retval = si470x_disconnect_check(radio);
806         if (retval)
807                 goto done;
808
809         if (freq->tuner != 0) {
810                 retval = -EINVAL;
811                 goto done;
812         }
813
814         freq->type = V4L2_TUNER_RADIO;
815         retval = si470x_get_freq(radio, &freq->frequency);
816
817 done:
818         if (retval < 0)
819                 dev_warn(&radio->videodev->dev,
820                         "get frequency failed with %d\n", retval);
821         mutex_unlock(&radio->lock);
822         return retval;
823 }
824
825
826 /*
827  * si470x_vidioc_s_frequency - set tuner or modulator radio frequency
828  */
829 static int si470x_vidioc_s_frequency(struct file *file, void *priv,
830                 struct v4l2_frequency *freq)
831 {
832         struct si470x_device *radio = video_drvdata(file);
833         int retval = 0;
834
835         mutex_lock(&radio->lock);
836         /* safety checks */
837         retval = si470x_disconnect_check(radio);
838         if (retval)
839                 goto done;
840
841         if (freq->tuner != 0) {
842                 retval = -EINVAL;
843                 goto done;
844         }
845
846         retval = si470x_set_freq(radio, freq->frequency);
847
848 done:
849         if (retval < 0)
850                 dev_warn(&radio->videodev->dev,
851                         "set frequency failed with %d\n", retval);
852         mutex_unlock(&radio->lock);
853         return retval;
854 }
855
856
857 /*
858  * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek
859  */
860 static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
861                 struct v4l2_hw_freq_seek *seek)
862 {
863         struct si470x_device *radio = video_drvdata(file);
864         int retval = 0;
865
866         mutex_lock(&radio->lock);
867         /* safety checks */
868         retval = si470x_disconnect_check(radio);
869         if (retval)
870                 goto done;
871
872         if (seek->tuner != 0) {
873                 retval = -EINVAL;
874                 goto done;
875         }
876
877         retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward);
878
879 done:
880         if (retval < 0)
881                 dev_warn(&radio->videodev->dev,
882                         "set hardware frequency seek failed with %d\n", retval);
883         mutex_unlock(&radio->lock);
884         return retval;
885 }
886
887
888 /*
889  * si470x_ioctl_ops - video device ioctl operations
890  */
891 static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
892         .vidioc_querycap        = si470x_vidioc_querycap,
893         .vidioc_queryctrl       = si470x_vidioc_queryctrl,
894         .vidioc_g_ctrl          = si470x_vidioc_g_ctrl,
895         .vidioc_s_ctrl          = si470x_vidioc_s_ctrl,
896         .vidioc_g_audio         = si470x_vidioc_g_audio,
897         .vidioc_g_tuner         = si470x_vidioc_g_tuner,
898         .vidioc_s_tuner         = si470x_vidioc_s_tuner,
899         .vidioc_g_frequency     = si470x_vidioc_g_frequency,
900         .vidioc_s_frequency     = si470x_vidioc_s_frequency,
901         .vidioc_s_hw_freq_seek  = si470x_vidioc_s_hw_freq_seek,
902 };
903
904
905 /*
906  * si470x_viddev_template - video device interface
907  */
908 struct video_device si470x_viddev_template = {
909         .fops                   = &si470x_fops,
910         .name                   = DRIVER_NAME,
911         .release                = video_device_release,
912         .ioctl_ops              = &si470x_ioctl_ops,
913 };