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