Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / media / platform / vivid / vivid-radio-common.c
1 /*
2  * vivid-radio-common.c - common radio rx/tx support functions.
3  *
4  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5  *
6  * This program is free software; you may redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
11  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
14  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
15  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17  * SOFTWARE.
18  */
19
20 #include <linux/errno.h>
21 #include <linux/kernel.h>
22 #include <linux/delay.h>
23 #include <linux/videodev2.h>
24
25 #include "vivid-core.h"
26 #include "vivid-ctrls.h"
27 #include "vivid-radio-common.h"
28 #include "vivid-rds-gen.h"
29
30 /*
31  * These functions are shared between the vivid receiver and transmitter
32  * since both use the same frequency bands.
33  */
34
35 const struct v4l2_frequency_band vivid_radio_bands[TOT_BANDS] = {
36         /* Band FM */
37         {
38                 .type = V4L2_TUNER_RADIO,
39                 .index = 0,
40                 .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
41                               V4L2_TUNER_CAP_FREQ_BANDS,
42                 .rangelow   = FM_FREQ_RANGE_LOW,
43                 .rangehigh  = FM_FREQ_RANGE_HIGH,
44                 .modulation = V4L2_BAND_MODULATION_FM,
45         },
46         /* Band AM */
47         {
48                 .type = V4L2_TUNER_RADIO,
49                 .index = 1,
50                 .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
51                 .rangelow   = AM_FREQ_RANGE_LOW,
52                 .rangehigh  = AM_FREQ_RANGE_HIGH,
53                 .modulation = V4L2_BAND_MODULATION_AM,
54         },
55         /* Band SW */
56         {
57                 .type = V4L2_TUNER_RADIO,
58                 .index = 2,
59                 .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
60                 .rangelow   = SW_FREQ_RANGE_LOW,
61                 .rangehigh  = SW_FREQ_RANGE_HIGH,
62                 .modulation = V4L2_BAND_MODULATION_AM,
63         },
64 };
65
66 /*
67  * Initialize the RDS generator. If we can loop, then the RDS generator
68  * is set up with the values from the RDS TX controls, otherwise it
69  * will fill in standard values using one of two alternates.
70  */
71 void vivid_radio_rds_init(struct vivid_dev *dev)
72 {
73         struct vivid_rds_gen *rds = &dev->rds_gen;
74         bool alt = dev->radio_rx_rds_use_alternates;
75
76         /* Do nothing, blocks will be filled by the transmitter */
77         if (dev->radio_rds_loop && !dev->radio_tx_rds_controls)
78                 return;
79
80         if (dev->radio_rds_loop) {
81                 v4l2_ctrl_lock(dev->radio_tx_rds_pi);
82                 rds->picode = dev->radio_tx_rds_pi->cur.val;
83                 rds->pty = dev->radio_tx_rds_pty->cur.val;
84                 rds->mono_stereo = dev->radio_tx_rds_mono_stereo->cur.val;
85                 rds->art_head = dev->radio_tx_rds_art_head->cur.val;
86                 rds->compressed = dev->radio_tx_rds_compressed->cur.val;
87                 rds->dyn_pty = dev->radio_tx_rds_dyn_pty->cur.val;
88                 rds->ta = dev->radio_tx_rds_ta->cur.val;
89                 rds->tp = dev->radio_tx_rds_tp->cur.val;
90                 rds->ms = dev->radio_tx_rds_ms->cur.val;
91                 strlcpy(rds->psname,
92                         dev->radio_tx_rds_psname->p_cur.p_char,
93                         sizeof(rds->psname));
94                 strlcpy(rds->radiotext,
95                         dev->radio_tx_rds_radiotext->p_cur.p_char + alt * 64,
96                         sizeof(rds->radiotext));
97                 v4l2_ctrl_unlock(dev->radio_tx_rds_pi);
98         } else {
99                 vivid_rds_gen_fill(rds, dev->radio_rx_freq, alt);
100         }
101         if (dev->radio_rx_rds_controls) {
102                 v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, rds->pty);
103                 v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, rds->ta);
104                 v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, rds->tp);
105                 v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, rds->ms);
106                 v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, rds->psname);
107                 v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, rds->radiotext);
108                 if (!dev->radio_rds_loop)
109                         dev->radio_rx_rds_use_alternates = !dev->radio_rx_rds_use_alternates;
110         }
111         vivid_rds_generate(rds);
112 }
113
114 /*
115  * Calculate the emulated signal quality taking into account the frequency
116  * the transmitter is using.
117  */
118 static void vivid_radio_calc_sig_qual(struct vivid_dev *dev)
119 {
120         int mod = 16000;
121         int delta = 800;
122         int sig_qual, sig_qual_tx = mod;
123
124         /*
125          * For SW and FM there is a channel every 1000 kHz, for AM there is one
126          * every 100 kHz.
127          */
128         if (dev->radio_rx_freq <= AM_FREQ_RANGE_HIGH) {
129                 mod /= 10;
130                 delta /= 10;
131         }
132         sig_qual = (dev->radio_rx_freq + delta) % mod - delta;
133         if (dev->has_radio_tx)
134                 sig_qual_tx = dev->radio_rx_freq - dev->radio_tx_freq;
135         if (abs(sig_qual_tx) <= abs(sig_qual)) {
136                 sig_qual = sig_qual_tx;
137                 /*
138                  * Zero the internal rds buffer if we are going to loop
139                  * rds blocks.
140                  */
141                 if (!dev->radio_rds_loop && !dev->radio_tx_rds_controls)
142                         memset(dev->rds_gen.data, 0,
143                                sizeof(dev->rds_gen.data));
144                 dev->radio_rds_loop = dev->radio_rx_freq >= FM_FREQ_RANGE_LOW;
145         } else {
146                 dev->radio_rds_loop = false;
147         }
148         if (dev->radio_rx_freq <= AM_FREQ_RANGE_HIGH)
149                 sig_qual *= 10;
150         dev->radio_rx_sig_qual = sig_qual;
151 }
152
153 int vivid_radio_g_frequency(struct file *file, const unsigned *pfreq, struct v4l2_frequency *vf)
154 {
155         if (vf->tuner != 0)
156                 return -EINVAL;
157         vf->frequency = *pfreq;
158         return 0;
159 }
160
161 int vivid_radio_s_frequency(struct file *file, unsigned *pfreq, const struct v4l2_frequency *vf)
162 {
163         struct vivid_dev *dev = video_drvdata(file);
164         unsigned freq;
165         unsigned band;
166
167         if (vf->tuner != 0)
168                 return -EINVAL;
169
170         if (vf->frequency >= (FM_FREQ_RANGE_LOW + SW_FREQ_RANGE_HIGH) / 2)
171                 band = BAND_FM;
172         else if (vf->frequency <= (AM_FREQ_RANGE_HIGH + SW_FREQ_RANGE_LOW) / 2)
173                 band = BAND_AM;
174         else
175                 band = BAND_SW;
176
177         freq = clamp_t(u32, vf->frequency, vivid_radio_bands[band].rangelow,
178                                            vivid_radio_bands[band].rangehigh);
179         *pfreq = freq;
180
181         /*
182          * For both receiver and transmitter recalculate the signal quality
183          * (since that depends on both frequencies) and re-init the rds
184          * generator.
185          */
186         vivid_radio_calc_sig_qual(dev);
187         vivid_radio_rds_init(dev);
188         return 0;
189 }