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