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