linux/drivers/media/v4l2-core/tuner-core.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * i2c tv tuner chip device driver
 * core core, i.e. kernel interfaces, registering and so on
 *
 * Copyright(c) by Ralph Metzler, Gerd Knorr, Gunther Mayer
 *
 * Copyright(c) 2005-2011 by Mauro Carvalho Chehab
 *	- Added support for a separate Radio tuner
 *	- Major rework and cleanups at the code
 *
 * This driver supports many devices and the idea is to let the driver
 * detect which device is present. So rather than listing all supported
 * devices here, we pretend to support a single, fake device type that will
 * handle both radio and analog TV tuning.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/i2c.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/videodev2.h>
#include <media/tuner.h>
#include <media/tuner-types.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include "mt20xx.h"
#include "tda8290.h"
#include "tea5761.h"
#include "tea5767.h"
#include "xc2028.h"
#include "tuner-simple.h"
#include "tda9887.h"
#include "xc5000.h"
#include "tda18271.h"
#include "xc4000.h"

#define UNSET

/*
 * Driver modprobe parameters
 */

/* insmod options used at init time => read/only */
static unsigned int addr;
static unsigned int no_autodetect;
static unsigned int show_i2c;

module_param(addr, int, 0444);
module_param(no_autodetect, int, 0444);
module_param(show_i2c, int, 0444);

/* insmod options used at runtime => read/write */
static int tuner_debug;
static unsigned int tv_range[2] =;
static unsigned int radio_range[2] =;
static char pal[] =;
static char secam[] =;
static char ntsc[] =;

module_param_named(debug, tuner_debug, int, 0644);
module_param_array();
module_param_array();
module_param_string();
module_param_string();
module_param_string();

/*
 * Static vars
 */

static LIST_HEAD(tuner_list);
static const struct v4l2_subdev_ops tuner_ops;

/*
 * Debug macros
 */

#undef pr_fmt

#define pr_fmt(fmt)


#define dprintk(fmt, arg...)

/*
 * Internal enums/struct used inside the driver
 */

/**
 * enum tuner_pad_index - tuner pad index for MEDIA_ENT_F_TUNER
 *
 * @TUNER_PAD_RF_INPUT:
 *	Radiofrequency (RF) sink pad, usually linked to a RF connector entity.
 * @TUNER_PAD_OUTPUT:
 *	tuner video output source pad. Contains the video chrominance
 *	and luminance or the hole bandwidth of the signal converted to
 *	an Intermediate Frequency (IF) or to baseband (on zero-IF tuners).
 * @TUNER_PAD_AUD_OUT:
 *	Tuner audio output source pad. Tuners used to decode analog TV
 *	signals have an extra pad for audio output. Old tuners use an
 *	analog stage with a saw filter for the audio IF frequency. The
 *	output of the pad is, in this case, the audio IF, with should be
 *	decoded either by the bridge chipset (that's the case of cx2388x
 *	chipsets) or may require an external IF sound processor, like
 *	msp34xx. On modern silicon tuners, the audio IF decoder is usually
 *	incorporated at the tuner. On such case, the output of this pad
 *	is an audio sampled data.
 * @TUNER_NUM_PADS:
 *	Number of pads of the tuner.
 */
enum tuner_pad_index {};

/**
 * enum if_vid_dec_pad_index - video IF-PLL pad index
 *	for MEDIA_ENT_F_IF_VID_DECODER
 *
 * @IF_VID_DEC_PAD_IF_INPUT:
 *	video Intermediate Frequency (IF) sink pad
 * @IF_VID_DEC_PAD_OUT:
 *	IF-PLL video output source pad. Contains the video chrominance
 *	and luminance IF signals.
 * @IF_VID_DEC_PAD_NUM_PADS:
 *	Number of pads of the video IF-PLL.
 */
enum if_vid_dec_pad_index {};

struct tuner {};

/*
 * Function prototypes
 */

static void set_tv_freq(struct i2c_client *c, unsigned int freq);
static void set_radio_freq(struct i2c_client *c, unsigned int freq);

/*
 * tuner attach/detach logic
 */

/* This macro allows us to probe dynamically, avoiding static links */
#ifdef CONFIG_MEDIA_ATTACH
#define tuner_symbol_probe(FUNCTION, ARGS...)

static void tuner_detach(struct dvb_frontend *fe)
{}
#else
#define tuner_symbol_probe

static void tuner_detach(struct dvb_frontend *fe)
{
	if (fe->ops.tuner_ops.release)
		fe->ops.tuner_ops.release(fe);
	if (fe->ops.analog_ops.release)
		fe->ops.analog_ops.release(fe);
}
#endif


static inline struct tuner *to_tuner(struct v4l2_subdev *sd)
{}

/*
 * struct analog_demod_ops callbacks
 */

static void fe_set_params(struct dvb_frontend *fe,
			  struct analog_parameters *params)
{}

static void fe_standby(struct dvb_frontend *fe)
{}

static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg)
{}

static void tuner_status(struct dvb_frontend *fe);

static const struct analog_demod_ops tuner_analog_ops =;

/*
 * Functions to select between radio and TV and tuner probe/remove functions
 */

/**
 * set_type - Sets the tuner type for a given device
 *
 * @c:			i2c_client descriptor
 * @type:		type of the tuner (e. g. tuner number)
 * @new_mode_mask:	Indicates if tuner supports TV and/or Radio
 * @new_config:		an optional parameter used by a few tuners to adjust
 *			internal parameters, like LNA mode
 * @tuner_callback:	an optional function to be called when switching
 *			to analog mode
 *
 * This function applies the tuner config to tuner specified
 * by tun_setup structure. It contains several per-tuner initialization "magic"
 */
static void set_type(struct i2c_client *c, unsigned int type,
		     unsigned int new_mode_mask, void *new_config,
		     int (*tuner_callback) (void *dev, int component, int cmd, int arg))
{}

/**
 * tuner_s_type_addr - Sets the tuner type for a device
 *
 * @sd:		subdev descriptor
 * @tun_setup:	type to be associated to a given tuner i2c address
 *
 * This function applies the tuner config to tuner specified
 * by tun_setup structure.
 * If tuner I2C address is UNSET, then it will only set the device
 * if the tuner supports the mode specified in the call.
 * If the address is specified, the change will be applied only if
 * tuner I2C address matches.
 * The call can change the tuner number and the tuner mode.
 */
static int tuner_s_type_addr(struct v4l2_subdev *sd,
			     struct tuner_setup *tun_setup)
{}

/**
 * tuner_s_config - Sets tuner configuration
 *
 * @sd:		subdev descriptor
 * @cfg:	tuner configuration
 *
 * Calls tuner set_config() private function to set some tuner-internal
 * parameters
 */
static int tuner_s_config(struct v4l2_subdev *sd,
			  const struct v4l2_priv_tun_config *cfg)
{}

/**
 * tuner_lookup - Seek for tuner adapters
 *
 * @adap:	i2c_adapter struct
 * @radio:	pointer to be filled if the adapter is radio
 * @tv:		pointer to be filled if the adapter is TV
 *
 * Search for existing radio and/or TV tuners on the given I2C adapter,
 * discarding demod-only adapters (tda9887).
 *
 * Note that when this function is called from tuner_probe you can be
 * certain no other devices will be added/deleted at the same time, I2C
 * core protects against that.
 */
static void tuner_lookup(struct i2c_adapter *adap,
		struct tuner **radio, struct tuner **tv)
{}

/**
 *tuner_probe - Probes the existing tuners on an I2C bus
 *
 * @client:	i2c_client descriptor
 *
 * This routine probes for tuners at the expected I2C addresses. On most
 * cases, if a device answers to a given I2C address, it assumes that the
 * device is a tuner. On a few cases, however, an additional logic is needed
 * to double check if the device is really a tuner, or to identify the tuner
 * type, like on tea5767/5761 devices.
 *
 * During client attach, set_type is called by adapter's attach_inform callback.
 * set_type must then be completed by tuner_probe.
 */
static int tuner_probe(struct i2c_client *client)
{}

/**
 * tuner_remove - detaches a tuner
 *
 * @client:	i2c_client descriptor
 */

static void tuner_remove(struct i2c_client *client)
{}

/*
 * Functions to switch between Radio and TV
 *
 * A few cards have a separate I2C tuner for radio. Those routines
 * take care of switching between TV/Radio mode, filtering only the
 * commands that apply to the Radio or TV tuner.
 */

/**
 * check_mode - Verify if tuner supports the requested mode
 * @t: a pointer to the module's internal struct_tuner
 * @mode: mode of the tuner, as defined by &enum v4l2_tuner_type.
 *
 * This function checks if the tuner is capable of tuning analog TV,
 * digital TV or radio, depending on what the caller wants. If the
 * tuner can't support that mode, it returns -EINVAL. Otherwise, it
 * returns 0.
 * This function is needed for boards that have a separate tuner for
 * radio (like devices with tea5767).
 *
 * NOTE: mt20xx uses V4L2_TUNER_DIGITAL_TV and calls set_tv_freq to
 *       select a TV frequency. So, t_mode = T_ANALOG_TV could actually
 *	 be used to represent a Digital TV too.
 */
static inline int check_mode(struct tuner *t, enum v4l2_tuner_type mode)
{}

/**
 * set_mode - Switch tuner to other mode.
 * @t:		a pointer to the module's internal struct_tuner
 * @mode:	enum v4l2_type (radio or TV)
 *
 * If tuner doesn't support the needed mode (radio or TV), prints a
 * debug message and returns -EINVAL, changing its state to standby.
 * Otherwise, changes the mode and returns 0.
 */
static int set_mode(struct tuner *t, enum v4l2_tuner_type mode)
{}

/**
 * set_freq - Set the tuner to the desired frequency.
 * @t:		a pointer to the module's internal struct_tuner
 * @freq:	frequency to set (0 means to use the current frequency)
 */
static void set_freq(struct tuner *t, unsigned int freq)
{}

/*
 * Functions that are specific for TV mode
 */

/**
 * set_tv_freq - Set tuner frequency,  freq in Units of 62.5 kHz = 1/16MHz
 *
 * @c:	i2c_client descriptor
 * @freq: frequency
 */
static void set_tv_freq(struct i2c_client *c, unsigned int freq)
{}

/**
 * tuner_fixup_std - force a given video standard variant
 *
 * @t: tuner internal struct
 * @std:	TV standard
 *
 * A few devices or drivers have problem to detect some standard variations.
 * On other operational systems, the drivers generally have a per-country
 * code, and some logic to apply per-country hacks. V4L2 API doesn't provide
 * such hacks. Instead, it relies on a proper video standard selection from
 * the userspace application. However, as some apps are buggy, not allowing
 * to distinguish all video standard variations, a modprobe parameter can
 * be used to force a video standard match.
 */
static v4l2_std_id tuner_fixup_std(struct tuner *t, v4l2_std_id std)
{}

/*
 * Functions that are specific for Radio mode
 */

/**
 * set_radio_freq - Set tuner frequency,  freq in Units of 62.5 Hz  = 1/16kHz
 *
 * @c:	i2c_client descriptor
 * @freq: frequency
 */
static void set_radio_freq(struct i2c_client *c, unsigned int freq)
{}

/*
 * Debug function for reporting tuner status to userspace
 */

/**
 * tuner_status - Dumps the current tuner status at dmesg
 * @fe: pointer to struct dvb_frontend
 *
 * This callback is used only for driver debug purposes, answering to
 * VIDIOC_LOG_STATUS. No changes should happen on this call.
 */
static void tuner_status(struct dvb_frontend *fe)
{}

/*
 * Function to splicitly change mode to radio. Probably not needed anymore
 */

static int tuner_s_radio(struct v4l2_subdev *sd)
{}

/*
 * Tuner callbacks to handle userspace ioctl's
 */

/**
 * tuner_standby - places the tuner in standby mode
 * @sd: pointer to struct v4l2_subdev
 */
static int tuner_standby(struct v4l2_subdev *sd)
{}

static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
{}

static int tuner_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *f)
{}

/**
 * tuner_g_frequency - Get the tuned frequency for the tuner
 * @sd: pointer to struct v4l2_subdev
 * @f: pointer to struct v4l2_frequency
 *
 * At return, the structure f will be filled with tuner frequency
 * if the tuner matches the f->type.
 * Note: f->type should be initialized before calling it.
 * This is done by either video_ioctl2 or by the bridge driver.
 */
static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
{}

/**
 * tuner_g_tuner - Fill in tuner information
 * @sd: pointer to struct v4l2_subdev
 * @vt: pointer to struct v4l2_tuner
 *
 * At return, the structure vt will be filled with tuner information
 * if the tuner matches vt->type.
 * Note: vt->type should be initialized before calling it.
 * This is done by either video_ioctl2 or by the bridge driver.
 */
static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
{}

/**
 * tuner_s_tuner - Set the tuner's audio mode
 * @sd: pointer to struct v4l2_subdev
 * @vt: pointer to struct v4l2_tuner
 *
 * Sets the audio mode if the tuner matches vt->type.
 * Note: vt->type should be initialized before calling it.
 * This is done by either video_ioctl2 or by the bridge driver.
 */
static int tuner_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
{}

static int tuner_log_status(struct v4l2_subdev *sd)
{}

#ifdef CONFIG_PM_SLEEP
static int tuner_suspend(struct device *dev)
{}

static int tuner_resume(struct device *dev)
{}
#endif

static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg)
{}

/*
 * Callback structs
 */

static const struct v4l2_subdev_core_ops tuner_core_ops =;

static const struct v4l2_subdev_tuner_ops tuner_tuner_ops =;

static const struct v4l2_subdev_video_ops tuner_video_ops =;

static const struct v4l2_subdev_ops tuner_ops =;

/*
 * I2C structs and module init functions
 */

static const struct dev_pm_ops tuner_pm_ops =;

static const struct i2c_device_id tuner_id[] =;
MODULE_DEVICE_TABLE(i2c, tuner_id);

static struct i2c_driver tuner_driver =;

module_i2c_driver();

MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_LICENSE();