// SPDX-License-Identifier: GPL-2.0-or-later /* * drivers/media/radio/si470x/radio-si470x-common.c * * Driver for radios with Silicon Labs Si470x FM Radio Receivers * * Copyright (c) 2009 Tobias Lorenz <[email protected]> * Copyright (c) 2012 Hans de Goede <[email protected]> */ /* * History: * 2008-01-12 Tobias Lorenz <[email protected]> * Version 1.0.0 * - First working version * 2008-01-13 Tobias Lorenz <[email protected]> * Version 1.0.1 * - Improved error handling, every function now returns errno * - Improved multi user access (start/mute/stop) * - Channel doesn't get lost anymore after start/mute/stop * - RDS support added (polling mode via interrupt EP 1) * - marked default module parameters with *value* * - switched from bit structs to bit masks * - header file cleaned and integrated * 2008-01-14 Tobias Lorenz <[email protected]> * Version 1.0.2 * - hex values are now lower case * - commented USB ID for ADS/Tech moved on todo list * - blacklisted si470x in hid-quirks.c * - rds buffer handling functions integrated into *_work, *_read * - rds_command in si470x_poll exchanged against simple retval * - check for firmware version 15 * - code order and prototypes still remain the same * - spacing and bottom of band codes remain the same * 2008-01-16 Tobias Lorenz <[email protected]> * Version 1.0.3 * - code reordered to avoid function prototypes * - switch/case defaults are now more user-friendly * - unified comment style * - applied all checkpatch.pl v1.12 suggestions * except the warning about the too long lines with bit comments * - renamed FMRADIO to RADIO to cut line length (checkpatch.pl) * 2008-01-22 Tobias Lorenz <[email protected]> * Version 1.0.4 * - avoid poss. locking when doing copy_to_user which may sleep * - RDS is automatically activated on read now * - code cleaned of unnecessary rds_commands * - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified * (thanks to Guillaume RAMOUSSE) * 2008-01-27 Tobias Lorenz <[email protected]> * Version 1.0.5 * - number of seek_retries changed to tune_timeout * - fixed problem with incomplete tune operations by own buffers * - optimization of variables and printf types * - improved error logging * 2008-01-31 Tobias Lorenz <[email protected]> * Oliver Neukum <[email protected]> * Version 1.0.6 * - fixed coverity checker warnings in *_usb_driver_disconnect * - probe()/open() race by correct ordering in probe() * - DMA coherency rules by separate allocation of all buffers * - use of endianness macros * - abuse of spinlock, replaced by mutex * - racy handling of timer in disconnect, * replaced by delayed_work * - racy interruptible_sleep_on(), * replaced with wait_event_interruptible() * - handle signals in read() * 2008-02-08 Tobias Lorenz <[email protected]> * Oliver Neukum <[email protected]> * Version 1.0.7 * - usb autosuspend support * - unplugging fixed * 2008-05-07 Tobias Lorenz <[email protected]> * Version 1.0.8 * - hardware frequency seek support * - afc indication * - more safety checks, let si470x_get_freq return errno * - vidioc behavior corrected according to v4l2 spec * 2008-10-20 Alexey Klimov <[email protected]> * - add support for KWorld USB FM Radio FM700 * - blacklisted KWorld radio in hid-core.c and hid-ids.h * 2008-12-03 Mark Lord <[email protected]> * - add support for DealExtreme USB Radio * 2009-01-31 Bob Ross <[email protected]> * - correction of stereo detection/setting * - correction of signal strength indicator scaling * 2009-01-31 Rick Bronson <[email protected]> * Tobias Lorenz <[email protected]> * - add LED status output * - get HW/SW version from scratchpad * 2009-06-16 Edouard Lafargue <[email protected]> * Version 1.0.10 * - add support for interrupt mode for RDS endpoint, * instead of polling. * Improves RDS reception significantly */ /* kernel includes */ #include "radio-si470x.h" /************************************************************************** * Module Parameters **************************************************************************/ /* Spacing (kHz) */ /* 0: 200 kHz (USA, Australia) */ /* 1: 100 kHz (Europe, Japan) */ /* 2: 50 kHz */ static unsigned short space = …; module_param(space, ushort, 0444); MODULE_PARM_DESC(…) …; /* De-emphasis */ /* 0: 75 us (USA) */ /* 1: 50 us (Europe, Australia, Japan) */ static unsigned short de = …; module_param(de, ushort, 0444); MODULE_PARM_DESC(…) …; /* Tune timeout */ static unsigned int tune_timeout = …; module_param(tune_timeout, uint, 0644); MODULE_PARM_DESC(…) …; /* Seek timeout */ static unsigned int seek_timeout = …; module_param(seek_timeout, uint, 0644); MODULE_PARM_DESC(…) …; static const struct v4l2_frequency_band bands[] = …; /************************************************************************** * Generic Functions **************************************************************************/ /* * si470x_set_band - set the band */ static int si470x_set_band(struct si470x_device *radio, int band) { … } /* * si470x_set_chan - set the channel */ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) { … } /* * si470x_get_step - get channel spacing */ static unsigned int si470x_get_step(struct si470x_device *radio) { … } /* * si470x_get_freq - get the frequency */ static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq) { … } /* * si470x_set_freq - set the frequency */ int si470x_set_freq(struct si470x_device *radio, unsigned int freq) { … } EXPORT_SYMBOL_GPL(…); /* * si470x_set_seek - set seek */ static int si470x_set_seek(struct si470x_device *radio, const struct v4l2_hw_freq_seek *seek) { … } /* * si470x_start - switch on radio */ int si470x_start(struct si470x_device *radio) { … } EXPORT_SYMBOL_GPL(…); /* * si470x_stop - switch off radio */ int si470x_stop(struct si470x_device *radio) { … } EXPORT_SYMBOL_GPL(…); /* * si470x_rds_on - switch on rds reception */ static int si470x_rds_on(struct si470x_device *radio) { … } /************************************************************************** * File Operations Interface **************************************************************************/ /* * si470x_fops_read - read RDS data */ static ssize_t si470x_fops_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { … } /* * si470x_fops_poll - poll RDS data */ static __poll_t si470x_fops_poll(struct file *file, struct poll_table_struct *pts) { … } static int si470x_fops_open(struct file *file) { … } /* * si470x_fops_release - file release */ static int si470x_fops_release(struct file *file) { … } /* * si470x_fops - file operations interface */ static const struct v4l2_file_operations si470x_fops = …; /************************************************************************** * Video4Linux Interface **************************************************************************/ static int si470x_s_ctrl(struct v4l2_ctrl *ctrl) { … } /* * si470x_vidioc_g_tuner - get tuner attributes */ static int si470x_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *tuner) { … } /* * si470x_vidioc_s_tuner - set tuner attributes */ static int si470x_vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *tuner) { … } /* * si470x_vidioc_g_frequency - get tuner or modulator radio frequency */ static int si470x_vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *freq) { … } /* * si470x_vidioc_s_frequency - set tuner or modulator radio frequency */ static int si470x_vidioc_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *freq) { … } /* * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek */ static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv, const struct v4l2_hw_freq_seek *seek) { … } /* * si470x_vidioc_enum_freq_bands - enumerate supported bands */ static int si470x_vidioc_enum_freq_bands(struct file *file, void *priv, struct v4l2_frequency_band *band) { … } const struct v4l2_ctrl_ops si470x_ctrl_ops = …; EXPORT_SYMBOL_GPL(…); static int si470x_vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *capability) { struct si470x_device *radio = video_drvdata(file); return radio->vidioc_querycap(file, priv, capability); }; /* * si470x_ioctl_ops - video device ioctl operations */ static const struct v4l2_ioctl_ops si470x_ioctl_ops = …; /* * si470x_viddev_template - video device interface */ const struct video_device si470x_viddev_template = …; EXPORT_SYMBOL_GPL(…); MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;