Lines Matching +full:switch +full:- +full:freq

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * drivers/media/radio/si470x/radio-si470x-common.c
14 * 2008-01-12 Tobias Lorenz <tobias.lorenz@gmx.net>
16 * - First working version
17 * 2008-01-13 Tobias Lorenz <tobias.lorenz@gmx.net>
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>
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>
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
43 * - renamed FMRADIO to RADIO to cut line length (checkpatch.pl)
44 * 2008-01-22 Tobias Lorenz <tobias.lorenz@gmx.net>
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
51 * 2008-01-27 Tobias Lorenz <tobias.lorenz@gmx.net>
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>
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,
67 * - racy interruptible_sleep_on(),
69 * - handle signals in read()
70 * 2008-02-08 Tobias Lorenz <tobias.lorenz@gmx.net>
73 * - usb autosuspend support
74 * - unplugging fixed
75 * 2008-05-07 Tobias Lorenz <tobias.lorenz@gmx.net>
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>
91 * - add LED status output
92 * - get HW/SW version from scratchpad
93 * 2009-06-16 Edouard Lafargue <edouard@lafargue.name>
95 * - add support for interrupt mode for RDS endpoint,
102 #include "radio-si470x.h"
116 /* De-emphasis */
121 MODULE_PARM_DESC(de, "De-emphasis: 0=75us *1=50us*");
177 * si470x_set_band - set the band
181 if (radio->band == band) in si470x_set_band()
184 radio->band = band; in si470x_set_band()
185 radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_BAND; in si470x_set_band()
186 radio->registers[SYSCONFIG2] |= radio->band << 6; in si470x_set_band()
187 return radio->set_register(radio, SYSCONFIG2); in si470x_set_band()
191 * si470x_set_chan - set the channel
199 retval = radio->get_register(radio, POWERCFG); in si470x_set_chan()
203 if ((radio->registers[POWERCFG] & (POWERCFG_ENABLE|POWERCFG_DMUTE)) in si470x_set_chan()
209 radio->registers[CHANNEL] &= ~CHANNEL_CHAN; in si470x_set_chan()
210 radio->registers[CHANNEL] |= CHANNEL_TUNE | chan; in si470x_set_chan()
211 retval = radio->set_register(radio, CHANNEL); in si470x_set_chan()
216 reinit_completion(&radio->completion); in si470x_set_chan()
217 time_left = wait_for_completion_timeout(&radio->completion, in si470x_set_chan()
222 if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) in si470x_set_chan()
223 dev_warn(&radio->videodev.dev, "tune does not complete\n"); in si470x_set_chan()
225 dev_warn(&radio->videodev.dev, in si470x_set_chan()
229 radio->registers[CHANNEL] &= ~CHANNEL_TUNE; in si470x_set_chan()
230 retval = radio->set_register(radio, CHANNEL); in si470x_set_chan()
237 * si470x_get_step - get channel spacing
242 switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) { in si470x_get_step()
257 * si470x_get_freq - get the frequency
259 static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq) in si470x_get_freq() argument
264 retval = radio->get_register(radio, READCHAN); in si470x_get_freq()
265 chan = radio->registers[READCHAN] & READCHAN_READCHAN; in si470x_get_freq()
268 *freq = chan * si470x_get_step(radio) + bands[radio->band].rangelow; in si470x_get_freq()
275 * si470x_set_freq - set the frequency
277 int si470x_set_freq(struct si470x_device *radio, unsigned int freq) in si470x_set_freq() argument
281 freq = clamp(freq, bands[radio->band].rangelow, in si470x_set_freq()
282 bands[radio->band].rangehigh); in si470x_set_freq()
283 /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */ in si470x_set_freq()
284 chan = (freq - bands[radio->band].rangelow) / si470x_get_step(radio); in si470x_set_freq()
292 * si470x_set_seek - set seek
298 unsigned int freq; in si470x_set_seek() local
303 if (seek->rangelow || seek->rangehigh) { in si470x_set_seek()
305 if (bands[band].rangelow == seek->rangelow && in si470x_set_seek()
306 bands[band].rangehigh == seek->rangehigh) in si470x_set_seek()
310 return -EINVAL; /* No matching band found */ in si470x_set_seek()
312 band = 1; /* If nothing is specified seek 76 - 108 Mhz */ in si470x_set_seek()
314 if (radio->band != band) { in si470x_set_seek()
315 retval = si470x_get_freq(radio, &freq); in si470x_set_seek()
321 retval = si470x_set_freq(radio, freq); in si470x_set_seek()
327 radio->registers[POWERCFG] |= POWERCFG_SEEK; in si470x_set_seek()
328 if (seek->wrap_around) in si470x_set_seek()
329 radio->registers[POWERCFG] &= ~POWERCFG_SKMODE; in si470x_set_seek()
331 radio->registers[POWERCFG] |= POWERCFG_SKMODE; in si470x_set_seek()
332 if (seek->seek_upward) in si470x_set_seek()
333 radio->registers[POWERCFG] |= POWERCFG_SEEKUP; in si470x_set_seek()
335 radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP; in si470x_set_seek()
336 retval = radio->set_register(radio, POWERCFG); in si470x_set_seek()
341 reinit_completion(&radio->completion); in si470x_set_seek()
342 time_left = wait_for_completion_timeout(&radio->completion, in si470x_set_seek()
347 if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) in si470x_set_seek()
348 dev_warn(&radio->videodev.dev, "seek does not complete\n"); in si470x_set_seek()
349 if (radio->registers[STATUSRSSI] & STATUSRSSI_SF) in si470x_set_seek()
350 dev_warn(&radio->videodev.dev, in si470x_set_seek()
354 radio->registers[POWERCFG] &= ~POWERCFG_SEEK; in si470x_set_seek()
355 retval = radio->set_register(radio, POWERCFG); in si470x_set_seek()
359 return -ENODATA; in si470x_set_seek()
365 * si470x_start - switch on radio
372 radio->registers[POWERCFG] = in si470x_start()
374 retval = radio->set_register(radio, POWERCFG); in si470x_start()
379 radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDSIEN | SYSCONFIG1_STCIEN | in si470x_start()
381 radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_GPIO2; in si470x_start()
382 radio->registers[SYSCONFIG1] |= SYSCONFIG1_GPIO2_INT; in si470x_start()
384 radio->registers[SYSCONFIG1] |= SYSCONFIG1_DE; in si470x_start()
385 retval = radio->set_register(radio, SYSCONFIG1); in si470x_start()
390 radio->registers[SYSCONFIG2] = in si470x_start()
392 ((radio->band << 6) & SYSCONFIG2_BAND) |/* BAND */ in si470x_start()
395 retval = radio->set_register(radio, SYSCONFIG2); in si470x_start()
401 radio->registers[CHANNEL] & CHANNEL_CHAN); in si470x_start()
410 * si470x_stop - switch off radio
417 radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; in si470x_stop()
418 retval = radio->set_register(radio, SYSCONFIG1); in si470x_stop()
423 radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; in si470x_stop()
425 radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE; in si470x_stop()
426 retval = radio->set_register(radio, POWERCFG); in si470x_stop()
435 * si470x_rds_on - switch on rds reception
442 radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS; in si470x_rds_on()
443 retval = radio->set_register(radio, SYSCONFIG1); in si470x_rds_on()
445 radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; in si470x_rds_on()
457 * si470x_fops_read - read RDS data
466 /* switch on rds reception */ in si470x_fops_read()
467 if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) in si470x_fops_read()
471 while (radio->wr_index == radio->rd_index) { in si470x_fops_read()
472 if (file->f_flags & O_NONBLOCK) { in si470x_fops_read()
473 retval = -EWOULDBLOCK; in si470x_fops_read()
476 if (wait_event_interruptible(radio->read_queue, in si470x_fops_read()
477 radio->wr_index != radio->rd_index) < 0) { in si470x_fops_read()
478 retval = -EINTR; in si470x_fops_read()
488 if (radio->rd_index == radio->wr_index) in si470x_fops_read()
492 if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3)) in si470x_fops_read()
493 /* retval = -EFAULT; */ in si470x_fops_read()
497 radio->rd_index += 3; in si470x_fops_read()
498 if (radio->rd_index >= radio->buf_size) in si470x_fops_read()
499 radio->rd_index = 0; in si470x_fops_read()
513 * si470x_fops_poll - poll RDS data
523 /* switch on rds reception */ in si470x_fops_poll()
524 if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) in si470x_fops_poll()
527 poll_wait(file, &radio->read_queue, pts); in si470x_fops_poll()
529 if (radio->rd_index != radio->wr_index) in si470x_fops_poll()
541 return radio->fops_open(file); in si470x_fops_open()
546 * si470x_fops_release - file release
552 return radio->fops_release(file); in si470x_fops_release()
557 * si470x_fops - file operations interface
578 container_of(ctrl->handler, struct si470x_device, hdl); in si470x_s_ctrl()
580 switch (ctrl->id) { in si470x_s_ctrl()
582 radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME; in si470x_s_ctrl()
583 radio->registers[SYSCONFIG2] |= ctrl->val; in si470x_s_ctrl()
584 return radio->set_register(radio, SYSCONFIG2); in si470x_s_ctrl()
586 if (ctrl->val) in si470x_s_ctrl()
587 radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; in si470x_s_ctrl()
589 radio->registers[POWERCFG] |= POWERCFG_DMUTE; in si470x_s_ctrl()
590 return radio->set_register(radio, POWERCFG); in si470x_s_ctrl()
592 return -EINVAL; in si470x_s_ctrl()
598 * si470x_vidioc_g_tuner - get tuner attributes
606 if (tuner->index != 0) in si470x_vidioc_g_tuner()
607 return -EINVAL; in si470x_vidioc_g_tuner()
609 if (!radio->status_rssi_auto_update) { in si470x_vidioc_g_tuner()
610 retval = radio->get_register(radio, STATUSRSSI); in si470x_vidioc_g_tuner()
616 strscpy(tuner->name, "FM", sizeof(tuner->name)); in si470x_vidioc_g_tuner()
617 tuner->type = V4L2_TUNER_RADIO; in si470x_vidioc_g_tuner()
618 tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | in si470x_vidioc_g_tuner()
622 tuner->rangelow = 76 * FREQ_MUL; in si470x_vidioc_g_tuner()
623 tuner->rangehigh = 108 * FREQ_MUL; in si470x_vidioc_g_tuner()
626 if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0) in si470x_vidioc_g_tuner()
627 tuner->rxsubchans = V4L2_TUNER_SUB_MONO; in si470x_vidioc_g_tuner()
629 tuner->rxsubchans = V4L2_TUNER_SUB_STEREO; in si470x_vidioc_g_tuner()
633 tuner->rxsubchans |= V4L2_TUNER_SUB_RDS; in si470x_vidioc_g_tuner()
636 if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0) in si470x_vidioc_g_tuner()
637 tuner->audmode = V4L2_TUNER_MODE_STEREO; in si470x_vidioc_g_tuner()
639 tuner->audmode = V4L2_TUNER_MODE_MONO; in si470x_vidioc_g_tuner()
643 tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI); in si470x_vidioc_g_tuner()
645 tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10); in si470x_vidioc_g_tuner()
646 if (tuner->signal > 0xffff) in si470x_vidioc_g_tuner()
647 tuner->signal = 0xffff; in si470x_vidioc_g_tuner()
649 /* automatic frequency control: -1: freq to low, 1 freq to high */ in si470x_vidioc_g_tuner()
650 /* AFCRL does only indicate that freq. differs, not if too low/high */ in si470x_vidioc_g_tuner()
651 tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0; in si470x_vidioc_g_tuner()
658 * si470x_vidioc_s_tuner - set tuner attributes
665 if (tuner->index != 0) in si470x_vidioc_s_tuner()
666 return -EINVAL; in si470x_vidioc_s_tuner()
669 switch (tuner->audmode) { in si470x_vidioc_s_tuner()
671 radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */ in si470x_vidioc_s_tuner()
675 radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */ in si470x_vidioc_s_tuner()
679 return radio->set_register(radio, POWERCFG); in si470x_vidioc_s_tuner()
684 * si470x_vidioc_g_frequency - get tuner or modulator radio frequency
687 struct v4l2_frequency *freq) in si470x_vidioc_g_frequency() argument
691 if (freq->tuner != 0) in si470x_vidioc_g_frequency()
692 return -EINVAL; in si470x_vidioc_g_frequency()
694 freq->type = V4L2_TUNER_RADIO; in si470x_vidioc_g_frequency()
695 return si470x_get_freq(radio, &freq->frequency); in si470x_vidioc_g_frequency()
700 * si470x_vidioc_s_frequency - set tuner or modulator radio frequency
703 const struct v4l2_frequency *freq) in si470x_vidioc_s_frequency() argument
708 if (freq->tuner != 0) in si470x_vidioc_s_frequency()
709 return -EINVAL; in si470x_vidioc_s_frequency()
711 if (freq->frequency < bands[radio->band].rangelow || in si470x_vidioc_s_frequency()
712 freq->frequency > bands[radio->band].rangehigh) { in si470x_vidioc_s_frequency()
713 /* Switch to band 1 which covers everything we support */ in si470x_vidioc_s_frequency()
718 return si470x_set_freq(radio, freq->frequency); in si470x_vidioc_s_frequency()
723 * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek
730 if (seek->tuner != 0) in si470x_vidioc_s_hw_freq_seek()
731 return -EINVAL; in si470x_vidioc_s_hw_freq_seek()
733 if (file->f_flags & O_NONBLOCK) in si470x_vidioc_s_hw_freq_seek()
734 return -EWOULDBLOCK; in si470x_vidioc_s_hw_freq_seek()
740 * si470x_vidioc_enum_freq_bands - enumerate supported bands
745 if (band->tuner != 0) in si470x_vidioc_enum_freq_bands()
746 return -EINVAL; in si470x_vidioc_enum_freq_bands()
747 if (band->index >= ARRAY_SIZE(bands)) in si470x_vidioc_enum_freq_bands()
748 return -EINVAL; in si470x_vidioc_enum_freq_bands()
749 *band = bands[band->index]; in si470x_vidioc_enum_freq_bands()
763 return radio->vidioc_querycap(file, priv, capability); in si470x_vidioc_querycap()
767 * si470x_ioctl_ops - video device ioctl operations
783 * si470x_viddev_template - video device interface