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