brintos

brintos / linux-shallow public Read only

0
0
Text · 5.1 KiB · 138c7bc Raw
178 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 transmitter20 * since both use the same frequency bands.21 */22 23const 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 generator56 * is set up with the values from the RDS TX controls, otherwise it57 * will fill in standard values using one of two alternates.58 */59void 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 frequency104 * the transmitter is using.105 */106static 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 one114	 * 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 loop127		 * 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 141int 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 149int 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	else163		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 quality171	 * (since that depends on both frequencies) and re-init the rds172	 * generator.173	 */174	vivid_radio_calc_sig_qual(dev);175	vivid_radio_rds_init(dev);176	return 0;177}178