// 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(…) …;