Commit 82cd0b278fddc1c0bc7e187ff82fd0e273520233

Authored by Mauro Carvalho Chehab
1 parent 098af4bde0

Revert "[media] v4l2: Add a V4L2 driver for SI476X MFD"

As requested by Andrey Smirnov <andrew.smirnov@gmail.com>, revert
this patch.

This reverts commit 30bac9110455402fa8888740c6819dd3daa2666f.

Conflicts:
	drivers/media/radio/Kconfig
	drivers/media/radio/radio-si476x.c

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

Showing 5 changed files with 0 additions and 2230 deletions Side-by-side Diff

Documentation/video4linux/si476x.txt
1   -SI476x Driver Readme
2   -------------------------------------------------
3   - Copyright (C) 2013 Andrey Smirnov <andrew.smirnov@gmail.com>
4   -
5   -TODO for the driver
6   -------------------------------
7   -
8   -- According to the SiLabs' datasheet it is possible to update the
9   - firmware of the radio chip in the run-time, thus bringing it to the
10   - most recent version. Unfortunately I couldn't find any mentioning of
11   - the said firmware update for the old chips that I tested the driver
12   - against, so for chips like that the driver only exposes the old
13   - functionality.
14   -
15   -
16   -Parameters exposed over debugfs
17   --------------------------------
18   -SI476x allow user to get multiple characteristics that can be very
19   -useful for EoL testing/RF performance estimation, parameters that have
20   -very little to do with V4L2 subsystem. Such parameters are exposed via
21   -debugfs and can be accessed via regular file I/O operations.
22   -
23   -The drivers exposes following files:
24   -
25   -* /sys/kernel/debug/<device-name>/acf
26   - This file contains ACF(Automatically Controlled Features) status
27   - information. The contents of the file is binary data of the
28   - following layout:
29   -
30   - Offset | Name | Description
31   - ====================================================================
32   - 0x00 | blend_int | Flag, set when stereo separation has
33   - | | crossed below the blend threshold
34   - --------------------------------------------------------------------
35   - 0x01 | hblend_int | Flag, set when HiBlend cutoff
36   - | | frequency is lower than threshold
37   - --------------------------------------------------------------------
38   - 0x02 | hicut_int | Flag, set when HiCut cutoff
39   - | | frequency is lower than threshold
40   - --------------------------------------------------------------------
41   - 0x03 | chbw_int | Flag, set when channel filter
42   - | | bandwidth is less than threshold
43   - --------------------------------------------------------------------
44   - 0x04 | softmute_int | Flag indicating that softmute
45   - | | attenuation has increased above
46   - | | softmute threshold
47   - --------------------------------------------------------------------
48   - 0x05 | smute | 0 - Audio is not soft muted
49   - | | 1 - Audio is soft muted
50   - --------------------------------------------------------------------
51   - 0x06 | smattn | Soft mute attenuation level in dB
52   - --------------------------------------------------------------------
53   - 0x07 | chbw | Channel filter bandwidth in kHz
54   - --------------------------------------------------------------------
55   - 0x08 | hicut | HiCut cutoff frequency in units of
56   - | | 100Hz
57   - --------------------------------------------------------------------
58   - 0x09 | hiblend | HiBlend cutoff frequency in units
59   - | | of 100 Hz
60   - --------------------------------------------------------------------
61   - 0x10 | pilot | 0 - Stereo pilot is not present
62   - | | 1 - Stereo pilot is present
63   - --------------------------------------------------------------------
64   - 0x11 | stblend | Stereo blend in %
65   - --------------------------------------------------------------------
66   -
67   -
68   -* /sys/kernel/debug/<device-name>/rds_blckcnt
69   - This file contains statistics about RDS receptions. It's binary data
70   - has the following layout:
71   -
72   - Offset | Name | Description
73   - ====================================================================
74   - 0x00 | expected | Number of expected RDS blocks
75   - --------------------------------------------------------------------
76   - 0x02 | received | Number of received RDS blocks
77   - --------------------------------------------------------------------
78   - 0x04 | uncorrectable | Number of uncorrectable RDS blocks
79   - --------------------------------------------------------------------
80   -
81   -* /sys/kernel/debug/<device-name>/agc
82   - This file contains information about parameters pertaining to
83   - AGC(Automatic Gain Control)
84   -
85   - The layout is:
86   - Offset | Name | Description
87   - ====================================================================
88   - 0x00 | mxhi | 0 - FM Mixer PD high threshold is
89   - | | not tripped
90   - | | 1 - FM Mixer PD high threshold is
91   - | | tripped
92   - --------------------------------------------------------------------
93   - 0x01 | mxlo | ditto for FM Mixer PD low
94   - --------------------------------------------------------------------
95   - 0x02 | lnahi | ditto for FM LNA PD high
96   - --------------------------------------------------------------------
97   - 0x03 | lnalo | ditto for FM LNA PD low
98   - --------------------------------------------------------------------
99   - 0x04 | fmagc1 | FMAGC1 attenuator resistance
100   - | | (see datasheet for more detail)
101   - --------------------------------------------------------------------
102   - 0x05 | fmagc2 | ditto for FMAGC2
103   - --------------------------------------------------------------------
104   - 0x06 | pgagain | PGA gain in dB
105   - --------------------------------------------------------------------
106   - 0x07 | fmwblang | FM/WB LNA Gain in dB
107   - --------------------------------------------------------------------
108   -
109   -* /sys/kernel/debug/<device-name>/rsq
110   - This file contains information about parameters pertaining to
111   - RSQ(Received Signal Quality)
112   -
113   - The layout is:
114   - Offset | Name | Description
115   - ====================================================================
116   - 0x00 | multhint | 0 - multipath value has not crossed
117   - | | the Multipath high threshold
118   - | | 1 - multipath value has crossed
119   - | | the Multipath high threshold
120   - --------------------------------------------------------------------
121   - 0x01 | multlint | ditto for Multipath low threshold
122   - --------------------------------------------------------------------
123   - 0x02 | snrhint | 0 - received signal's SNR has not
124   - | | crossed high threshold
125   - | | 1 - received signal's SNR has
126   - | | crossed high threshold
127   - --------------------------------------------------------------------
128   - 0x03 | snrlint | ditto for low threshold
129   - --------------------------------------------------------------------
130   - 0x04 | rssihint | ditto for RSSI high threshold
131   - --------------------------------------------------------------------
132   - 0x05 | rssilint | ditto for RSSI low threshold
133   - --------------------------------------------------------------------
134   - 0x06 | bltf | Flag indicating if seek command
135   - | | reached/wrapped seek band limit
136   - --------------------------------------------------------------------
137   - 0x07 | snr_ready | Indicates that SNR metrics is ready
138   - --------------------------------------------------------------------
139   - 0x08 | rssiready | ditto for RSSI metrics
140   - --------------------------------------------------------------------
141   - 0x09 | injside | 0 - Low-side injection is being used
142   - | | 1 - High-side injection is used
143   - --------------------------------------------------------------------
144   - 0x10 | afcrl | Flag indicating if AFC rails
145   - --------------------------------------------------------------------
146   - 0x11 | valid | Flag indicating if channel is valid
147   - --------------------------------------------------------------------
148   - 0x12 | readfreq | Current tuned frequency
149   - --------------------------------------------------------------------
150   - 0x14 | freqoff | Singed frequency offset in units of
151   - | | 2ppm
152   - --------------------------------------------------------------------
153   - 0x15 | rssi | Signed value of RSSI in dBuV
154   - --------------------------------------------------------------------
155   - 0x16 | snr | Signed RF SNR in dB
156   - --------------------------------------------------------------------
157   - 0x17 | issi | Signed Image Strength Signal
158   - | | indicator
159   - --------------------------------------------------------------------
160   - 0x18 | lassi | Signed Low side adjacent Channel
161   - | | Strength indicator
162   - --------------------------------------------------------------------
163   - 0x19 | hassi | ditto fpr High side
164   - --------------------------------------------------------------------
165   - 0x20 | mult | Multipath indicator
166   - --------------------------------------------------------------------
167   - 0x21 | dev | Frequency deviation
168   - --------------------------------------------------------------------
169   - 0x24 | assi | Adjascent channel SSI
170   - --------------------------------------------------------------------
171   - 0x25 | usn | Ultrasonic noise indicator
172   - --------------------------------------------------------------------
173   - 0x26 | pilotdev | Pilot deviation in units of 100 Hz
174   - --------------------------------------------------------------------
175   - 0x27 | rdsdev | ditto for RDS
176   - --------------------------------------------------------------------
177   - 0x28 | assidev | ditto for ASSI
178   - --------------------------------------------------------------------
179   - 0x29 | strongdev | Frequency deviation
180   - --------------------------------------------------------------------
181   - 0x30 | rdspi | RDS PI code
182   - --------------------------------------------------------------------
183   -
184   -* /sys/kernel/debug/<device-name>/rsq_primary
185   - This file contains information about parameters pertaining to
186   - RSQ(Received Signal Quality) for primary tuner only. Layout is as
187   - the one above.
drivers/media/radio/Kconfig
... ... @@ -18,23 +18,6 @@
18 18  
19 19 source "drivers/media/radio/si470x/Kconfig"
20 20  
21   -config RADIO_SI476X
22   - tristate "Silicon Laboratories Si476x I2C FM Radio"
23   - depends on I2C && VIDEO_V4L2 && SND && SND_SOC
24   - select MFD_CORE
25   - select MFD_SI476X_CORE
26   - select SND_SOC_SI476X
27   - ---help---
28   - Choose Y here if you have this FM radio chip.
29   -
30   - In order to control your radio card, you will need to use programs
31   - that are compatible with the Video For Linux 2 API. Information on
32   - this API and pointers to "v4l2" programs may be found at
33   - <file:Documentation/video4linux/API.html>.
34   -
35   - To compile this driver as a module, choose M here: the
36   - module will be called radio-si476x.
37   -
38 21 config USB_MR800
39 22 tristate "AverMedia MR 800 USB FM radio support"
40 23 depends on USB && VIDEO_V4L2
drivers/media/radio/Makefile
... ... @@ -19,7 +19,6 @@
19 19 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
20 20 obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o
21 21 obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o
22   -obj-$(CONFIG_RADIO_SI476X) += radio-si476x.o
23 22 obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o
24 23 obj-$(CONFIG_USB_DSBR) += dsbr100.o
25 24 obj-$(CONFIG_RADIO_SI470X) += si470x/
drivers/media/radio/radio-si476x.c
Changes suppressed. Click to show
1   -/*
2   - * drivers/media/radio/radio-si476x.c -- V4L2 driver for SI476X chips
3   - *
4   - * Copyright (C) 2012 Innovative Converged Devices(ICD)
5   - * Copyright (C) 2013 Andrey Smirnov
6   - *
7   - * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
8   - *
9   - * This program is free software; you can redistribute it and/or modify
10   - * it under the terms of the GNU General Public License as published by
11   - * the Free Software Foundation; version 2 of the License.
12   - *
13   - * This program is distributed in the hope that it will be useful, but
14   - * WITHOUT ANY WARRANTY; without even the implied warranty of
15   - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   - * General Public License for more details.
17   - *
18   - */
19   -
20   -#include <linux/module.h>
21   -#include <linux/delay.h>
22   -#include <linux/interrupt.h>
23   -#include <linux/slab.h>
24   -#include <linux/atomic.h>
25   -#include <linux/videodev2.h>
26   -#include <linux/mutex.h>
27   -#include <linux/debugfs.h>
28   -#include <media/v4l2-common.h>
29   -#include <media/v4l2-ioctl.h>
30   -#include <media/v4l2-ctrls.h>
31   -#include <media/v4l2-event.h>
32   -#include <media/v4l2-device.h>
33   -
34   -#include <media/si476x.h>
35   -#include <linux/mfd/si476x-core.h>
36   -
37   -#define FM_FREQ_RANGE_LOW 64000000
38   -#define FM_FREQ_RANGE_HIGH 108000000
39   -
40   -#define AM_FREQ_RANGE_LOW 520000
41   -#define AM_FREQ_RANGE_HIGH 30000000
42   -
43   -#define PWRLINEFLTR (1 << 8)
44   -
45   -#define FREQ_MUL (10000000 / 625)
46   -
47   -#define SI476X_PHDIV_STATUS_LINK_LOCKED(status) (0b10000000 & (status))
48   -
49   -#define DRIVER_NAME "si476x-radio"
50   -#define DRIVER_CARD "SI476x AM/FM Receiver"
51   -
52   -enum si476x_freq_bands {
53   - SI476X_BAND_FM,
54   - SI476X_BAND_AM,
55   -};
56   -
57   -static const struct v4l2_frequency_band si476x_bands[] = {
58   - [SI476X_BAND_FM] = {
59   - .type = V4L2_TUNER_RADIO,
60   - .index = SI476X_BAND_FM,
61   - .capability = V4L2_TUNER_CAP_LOW
62   - | V4L2_TUNER_CAP_STEREO
63   - | V4L2_TUNER_CAP_RDS
64   - | V4L2_TUNER_CAP_RDS_BLOCK_IO
65   - | V4L2_TUNER_CAP_FREQ_BANDS,
66   - .rangelow = 64 * FREQ_MUL,
67   - .rangehigh = 108 * FREQ_MUL,
68   - .modulation = V4L2_BAND_MODULATION_FM,
69   - },
70   - [SI476X_BAND_AM] = {
71   - .type = V4L2_TUNER_RADIO,
72   - .index = SI476X_BAND_AM,
73   - .capability = V4L2_TUNER_CAP_LOW
74   - | V4L2_TUNER_CAP_FREQ_BANDS,
75   - .rangelow = 0.52 * FREQ_MUL,
76   - .rangehigh = 30 * FREQ_MUL,
77   - .modulation = V4L2_BAND_MODULATION_AM,
78   - },
79   -};
80   -
81   -static inline bool si476x_radio_freq_is_inside_of_the_band(u32 freq, int band)
82   -{
83   - return freq >= si476x_bands[band].rangelow &&
84   - freq <= si476x_bands[band].rangehigh;
85   -}
86   -
87   -static inline bool si476x_radio_range_is_inside_of_the_band(u32 low, u32 high,
88   - int band)
89   -{
90   - return low >= si476x_bands[band].rangelow &&
91   - high <= si476x_bands[band].rangehigh;
92   -}
93   -
94   -static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl);
95   -static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl);
96   -
97   -enum phase_diversity_modes_idx {
98   - SI476X_IDX_PHDIV_DISABLED,
99   - SI476X_IDX_PHDIV_PRIMARY_COMBINING,
100   - SI476X_IDX_PHDIV_PRIMARY_ANTENNA,
101   - SI476X_IDX_PHDIV_SECONDARY_ANTENNA,
102   - SI476X_IDX_PHDIV_SECONDARY_COMBINING,
103   -};
104   -
105   -static const char * const phase_diversity_modes[] = {
106   - [SI476X_IDX_PHDIV_DISABLED] = "Disabled",
107   - [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = "Primary with Secondary",
108   - [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = "Primary Antenna",
109   - [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = "Secondary Antenna",
110   - [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = "Secondary with Primary",
111   -};
112   -
113   -static inline enum phase_diversity_modes_idx
114   -si476x_phase_diversity_mode_to_idx(enum si476x_phase_diversity_mode mode)
115   -{
116   - switch (mode) {
117   - default: /* FALLTHROUGH */
118   - case SI476X_PHDIV_DISABLED:
119   - return SI476X_IDX_PHDIV_DISABLED;
120   - case SI476X_PHDIV_PRIMARY_COMBINING:
121   - return SI476X_IDX_PHDIV_PRIMARY_COMBINING;
122   - case SI476X_PHDIV_PRIMARY_ANTENNA:
123   - return SI476X_IDX_PHDIV_PRIMARY_ANTENNA;
124   - case SI476X_PHDIV_SECONDARY_ANTENNA:
125   - return SI476X_IDX_PHDIV_SECONDARY_ANTENNA;
126   - case SI476X_PHDIV_SECONDARY_COMBINING:
127   - return SI476X_IDX_PHDIV_SECONDARY_COMBINING;
128   - }
129   -}
130   -
131   -static inline enum si476x_phase_diversity_mode
132   -si476x_phase_diversity_idx_to_mode(enum phase_diversity_modes_idx idx)
133   -{
134   - static const int idx_to_value[] = {
135   - [SI476X_IDX_PHDIV_DISABLED] = SI476X_PHDIV_DISABLED,
136   - [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = SI476X_PHDIV_PRIMARY_COMBINING,
137   - [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = SI476X_PHDIV_PRIMARY_ANTENNA,
138   - [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = SI476X_PHDIV_SECONDARY_ANTENNA,
139   - [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = SI476X_PHDIV_SECONDARY_COMBINING,
140   - };
141   -
142   - return idx_to_value[idx];
143   -}
144   -
145   -static const struct v4l2_ctrl_ops si476x_ctrl_ops = {
146   - .g_volatile_ctrl = si476x_radio_g_volatile_ctrl,
147   - .s_ctrl = si476x_radio_s_ctrl,
148   -};
149   -
150   -
151   -enum si476x_ctrl_idx {
152   - SI476X_IDX_RSSI_THRESHOLD,
153   - SI476X_IDX_SNR_THRESHOLD,
154   - SI476X_IDX_MAX_TUNE_ERROR,
155   - SI476X_IDX_HARMONICS_COUNT,
156   - SI476X_IDX_DIVERSITY_MODE,
157   - SI476X_IDX_INTERCHIP_LINK,
158   -};
159   -static struct v4l2_ctrl_config si476x_ctrls[] = {
160   -
161   - /**
162   - * SI476X during its station seeking(or tuning) process uses several
163   - * parameters to detrmine if "the station" is valid:
164   - *
165   - * - Signal's SNR(in dBuV) must be lower than
166   - * #V4L2_CID_SI476X_SNR_THRESHOLD
167   - * - Signal's RSSI(in dBuV) must be greater than
168   - * #V4L2_CID_SI476X_RSSI_THRESHOLD
169   - * - Signal's frequency deviation(in units of 2ppm) must not be
170   - * more than #V4L2_CID_SI476X_MAX_TUNE_ERROR
171   - */
172   - [SI476X_IDX_RSSI_THRESHOLD] = {
173   - .ops = &si476x_ctrl_ops,
174   - .id = V4L2_CID_SI476X_RSSI_THRESHOLD,
175   - .name = "Valid RSSI Threshold",
176   - .type = V4L2_CTRL_TYPE_INTEGER,
177   - .min = -128,
178   - .max = 127,
179   - .step = 1,
180   - },
181   - [SI476X_IDX_SNR_THRESHOLD] = {
182   - .ops = &si476x_ctrl_ops,
183   - .id = V4L2_CID_SI476X_SNR_THRESHOLD,
184   - .type = V4L2_CTRL_TYPE_INTEGER,
185   - .name = "Valid SNR Threshold",
186   - .min = -128,
187   - .max = 127,
188   - .step = 1,
189   - },
190   - [SI476X_IDX_MAX_TUNE_ERROR] = {
191   - .ops = &si476x_ctrl_ops,
192   - .id = V4L2_CID_SI476X_MAX_TUNE_ERROR,
193   - .type = V4L2_CTRL_TYPE_INTEGER,
194   - .name = "Max Tune Errors",
195   - .min = 0,
196   - .max = 126 * 2,
197   - .step = 2,
198   - },
199   -
200   - /**
201   - * #V4L2_CID_SI476X_HARMONICS_COUNT -- number of harmonics
202   - * built-in power-line noise supression filter is to reject
203   - * during AM-mode operation.
204   - */
205   - [SI476X_IDX_HARMONICS_COUNT] = {
206   - .ops = &si476x_ctrl_ops,
207   - .id = V4L2_CID_SI476X_HARMONICS_COUNT,
208   - .type = V4L2_CTRL_TYPE_INTEGER,
209   -
210   - .name = "Count of Harmonics to Reject",
211   - .min = 0,
212   - .max = 20,
213   - .step = 1,
214   - },
215   -
216   - /**
217   - * #V4L2_CID_SI476X_DIVERSITY_MODE -- configuration which
218   - * two tuners working in diversity mode are to work in.
219   - *
220   - * - #SI476X_IDX_PHDIV_DISABLED diversity mode disabled
221   - * - #SI476X_IDX_PHDIV_PRIMARY_COMBINING diversity mode is
222   - * on, primary tuner's antenna is the main one.
223   - * - #SI476X_IDX_PHDIV_PRIMARY_ANTENNA diversity mode is
224   - * off, primary tuner's antenna is the main one.
225   - * - #SI476X_IDX_PHDIV_SECONDARY_ANTENNA diversity mode is
226   - * off, secondary tuner's antenna is the main one.
227   - * - #SI476X_IDX_PHDIV_SECONDARY_COMBINING diversity mode is
228   - * on, secondary tuner's antenna is the main one.
229   - */
230   - [SI476X_IDX_DIVERSITY_MODE] = {
231   - .ops = &si476x_ctrl_ops,
232   - .id = V4L2_CID_SI476X_DIVERSITY_MODE,
233   - .type = V4L2_CTRL_TYPE_MENU,
234   - .name = "Phase Diversity Mode",
235   - .qmenu = phase_diversity_modes,
236   - .min = 0,
237   - .max = ARRAY_SIZE(phase_diversity_modes) - 1,
238   - },
239   -
240   - /**
241   - * #V4L2_CID_SI476X_INTERCHIP_LINK -- inter-chip link in
242   - * diversity mode indicator. Allows user to determine if two
243   - * chips working in diversity mode have established a link
244   - * between each other and if the system as a whole uses
245   - * signals from both antennas to receive FM radio.
246   - */
247   - [SI476X_IDX_INTERCHIP_LINK] = {
248   - .ops = &si476x_ctrl_ops,
249   - .id = V4L2_CID_SI476X_INTERCHIP_LINK,
250   - .type = V4L2_CTRL_TYPE_BOOLEAN,
251   - .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE,
252   - .name = "Inter-Chip Link",
253   - .min = 0,
254   - .max = 1,
255   - .step = 1,
256   - },
257   -};
258   -
259   -struct si476x_radio;
260   -
261   -/**
262   - * struct si476x_radio_ops - vtable of tuner functions
263   - *
264   - * This table holds pointers to functions implementing particular
265   - * operations depending on the mode in which the tuner chip was
266   - * configured to start in. If the function is not supported
267   - * corresponding element is set to #NULL.
268   - *
269   - * @tune_freq: Tune chip to a specific frequency
270   - * @seek_start: Star station seeking
271   - * @rsq_status: Get Recieved Signal Quality(RSQ) status
272   - * @rds_blckcnt: Get recived RDS blocks count
273   - * @phase_diversity: Change phase diversity mode of the tuner
274   - * @phase_div_status: Get phase diversity mode status
275   - * @acf_status: Get the status of Automatically Controlled
276   - * Features(ACF)
277   - * @agc_status: Get Automatic Gain Control(AGC) status
278   - */
279   -struct si476x_radio_ops {
280   - int (*tune_freq)(struct si476x_core *, struct si476x_tune_freq_args *);
281   - int (*seek_start)(struct si476x_core *, bool, bool);
282   - int (*rsq_status)(struct si476x_core *, struct si476x_rsq_status_args *,
283   - struct si476x_rsq_status_report *);
284   - int (*rds_blckcnt)(struct si476x_core *, bool,
285   - struct si476x_rds_blockcount_report *);
286   -
287   - int (*phase_diversity)(struct si476x_core *,
288   - enum si476x_phase_diversity_mode);
289   - int (*phase_div_status)(struct si476x_core *);
290   - int (*acf_status)(struct si476x_core *,
291   - struct si476x_acf_status_report *);
292   - int (*agc_status)(struct si476x_core *,
293   - struct si476x_agc_status_report *);
294   -};
295   -
296   -/**
297   - * struct si476x_radio - radio device
298   - *
299   - * @core: Pointer to underlying core device
300   - * @videodev: Pointer to video device created by V4L2 subsystem
301   - * @ops: Vtable of functions. See struct si476x_radio_ops for details
302   - * @kref: Reference counter
303   - * @core_lock: An r/w semaphore to brebvent the deletion of underlying
304   - * core structure is the radio device is being used
305   - */
306   -struct si476x_radio {
307   - struct v4l2_device v4l2dev;
308   - struct video_device videodev;
309   - struct v4l2_ctrl_handler ctrl_handler;
310   -
311   - struct si476x_core *core;
312   - /* This field should not be accesses unless core lock is held */
313   - const struct si476x_radio_ops *ops;
314   -
315   - struct dentry *debugfs;
316   - u32 audmode;
317   -};
318   -
319   -static inline struct si476x_radio *
320   -v4l2_dev_to_radio(struct v4l2_device *d)
321   -{
322   - return container_of(d, struct si476x_radio, v4l2dev);
323   -}
324   -
325   -static inline struct si476x_radio *
326   -v4l2_ctrl_handler_to_radio(struct v4l2_ctrl_handler *d)
327   -{
328   - return container_of(d, struct si476x_radio, ctrl_handler);
329   -}
330   -
331   -/*
332   - * si476x_vidioc_querycap - query device capabilities
333   - */
334   -static int si476x_radio_querycap(struct file *file, void *priv,
335   - struct v4l2_capability *capability)
336   -{
337   - struct si476x_radio *radio = video_drvdata(file);
338   -
339   - strlcpy(capability->driver, radio->v4l2dev.name,
340   - sizeof(capability->driver));
341   - strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
342   - snprintf(capability->bus_info, sizeof(capability->bus_info),
343   - "platform:%s", radio->v4l2dev.name);
344   -
345   - capability->device_caps = V4L2_CAP_TUNER
346   - | V4L2_CAP_RADIO
347   - | V4L2_CAP_HW_FREQ_SEEK;
348   -
349   - si476x_core_lock(radio->core);
350   - if (!si476x_core_is_a_secondary_tuner(radio->core))
351   - capability->device_caps |= V4L2_CAP_RDS_CAPTURE
352   - | V4L2_CAP_READWRITE;
353   - si476x_core_unlock(radio->core);
354   -
355   - capability->capabilities = capability->device_caps
356   - | V4L2_CAP_DEVICE_CAPS;
357   - return 0;
358   -}
359   -
360   -static int si476x_radio_enum_freq_bands(struct file *file, void *priv,
361   - struct v4l2_frequency_band *band)
362   -{
363   - int err;
364   - struct si476x_radio *radio = video_drvdata(file);
365   -
366   - if (band->tuner != 0)
367   - return -EINVAL;
368   -
369   - switch (radio->core->chip_id) {
370   - /* AM/FM tuners -- all bands are supported */
371   - case SI476X_CHIP_SI4761:
372   - case SI476X_CHIP_SI4764:
373   - if (band->index < ARRAY_SIZE(si476x_bands)) {
374   - *band = si476x_bands[band->index];
375   - err = 0;
376   - } else {
377   - err = -EINVAL;
378   - }
379   - break;
380   - /* FM companion tuner chips -- only FM bands are
381   - * supported */
382   - case SI476X_CHIP_SI4768:
383   - if (band->index == SI476X_BAND_FM) {
384   - *band = si476x_bands[band->index];
385   - err = 0;
386   - } else {
387   - err = -EINVAL;
388   - }
389   - break;
390   - default:
391   - err = -EINVAL;
392   - }
393   -
394   - return err;
395   -}
396   -
397   -static int si476x_radio_g_tuner(struct file *file, void *priv,
398   - struct v4l2_tuner *tuner)
399   -{
400   - int err;
401   - struct si476x_rsq_status_report report;
402   - struct si476x_radio *radio = video_drvdata(file);
403   -
404   - struct si476x_rsq_status_args args = {
405   - .primary = false,
406   - .rsqack = false,
407   - .attune = false,
408   - .cancel = false,
409   - .stcack = false,
410   - };
411   -
412   - if (tuner->index != 0)
413   - return -EINVAL;
414   -
415   - tuner->type = V4L2_TUNER_RADIO;
416   - tuner->capability = V4L2_TUNER_CAP_LOW /* Measure frequencies
417   - * in multiples of
418   - * 62.5 Hz */
419   - | V4L2_TUNER_CAP_STEREO
420   - | V4L2_TUNER_CAP_HWSEEK_BOUNDED
421   - | V4L2_TUNER_CAP_HWSEEK_WRAP
422   - | V4L2_TUNER_CAP_HWSEEK_PROG_LIM;
423   -
424   - si476x_core_lock(radio->core);
425   -
426   - if (si476x_core_is_a_secondary_tuner(radio->core)) {
427   - strlcpy(tuner->name, "FM (secondary)", sizeof(tuner->name));
428   - tuner->rxsubchans = 0;
429   - tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow;
430   - } else if (si476x_core_has_am(radio->core)) {
431   - if (si476x_core_is_a_primary_tuner(radio->core))
432   - strlcpy(tuner->name, "AM/FM (primary)",
433   - sizeof(tuner->name));
434   - else
435   - strlcpy(tuner->name, "AM/FM", sizeof(tuner->name));
436   -
437   - tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO
438   - | V4L2_TUNER_SUB_RDS;
439   - tuner->capability |= V4L2_TUNER_CAP_RDS
440   - | V4L2_TUNER_CAP_RDS_BLOCK_IO
441   - | V4L2_TUNER_CAP_FREQ_BANDS;
442   -
443   - tuner->rangelow = si476x_bands[SI476X_BAND_AM].rangelow;
444   - } else {
445   - strlcpy(tuner->name, "FM", sizeof(tuner->name));
446   - tuner->rxsubchans = V4L2_TUNER_SUB_RDS;
447   - tuner->capability |= V4L2_TUNER_CAP_RDS
448   - | V4L2_TUNER_CAP_RDS_BLOCK_IO
449   - | V4L2_TUNER_CAP_FREQ_BANDS;
450   - tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow;
451   - }
452   -
453   - tuner->audmode = radio->audmode;
454   -
455   - tuner->afc = 1;
456   - tuner->rangehigh = si476x_bands[SI476X_BAND_FM].rangehigh;
457   -
458   - err = radio->ops->rsq_status(radio->core,
459   - &args, &report);
460   - if (err < 0) {
461   - tuner->signal = 0;
462   - } else {
463   - /*
464   - * tuner->signal value range: 0x0000 .. 0xFFFF,
465   - * report.rssi: -128 .. 127
466   - */
467   - tuner->signal = (report.rssi + 128) * 257;
468   - }
469   - si476x_core_unlock(radio->core);
470   -
471   - return err;
472   -}
473   -
474   -static int si476x_radio_s_tuner(struct file *file, void *priv,
475   - const struct v4l2_tuner *tuner)
476   -{
477   - struct si476x_radio *radio = video_drvdata(file);
478   -
479   - if (tuner->index != 0)
480   - return -EINVAL;
481   -
482   - if (tuner->audmode == V4L2_TUNER_MODE_MONO ||
483   - tuner->audmode == V4L2_TUNER_MODE_STEREO)
484   - radio->audmode = tuner->audmode;
485   - else
486   - radio->audmode = V4L2_TUNER_MODE_STEREO;
487   -
488   - return 0;
489   -}
490   -
491   -static int si476x_radio_init_vtable(struct si476x_radio *radio,
492   - enum si476x_func func)
493   -{
494   - static const struct si476x_radio_ops fm_ops = {
495   - .tune_freq = si476x_core_cmd_fm_tune_freq,
496   - .seek_start = si476x_core_cmd_fm_seek_start,
497   - .rsq_status = si476x_core_cmd_fm_rsq_status,
498   - .rds_blckcnt = si476x_core_cmd_fm_rds_blockcount,
499   - .phase_diversity = si476x_core_cmd_fm_phase_diversity,
500   - .phase_div_status = si476x_core_cmd_fm_phase_div_status,
501   - .acf_status = si476x_core_cmd_fm_acf_status,
502   - .agc_status = si476x_core_cmd_agc_status,
503   - };
504   -
505   - static const struct si476x_radio_ops am_ops = {
506   - .tune_freq = si476x_core_cmd_am_tune_freq,
507   - .seek_start = si476x_core_cmd_am_seek_start,
508   - .rsq_status = si476x_core_cmd_am_rsq_status,
509   - .rds_blckcnt = NULL,
510   - .phase_diversity = NULL,
511   - .phase_div_status = NULL,
512   - .acf_status = si476x_core_cmd_am_acf_status,
513   - .agc_status = NULL,
514   - };
515   -
516   - switch (func) {
517   - case SI476X_FUNC_FM_RECEIVER:
518   - radio->ops = &fm_ops;
519   - return 0;
520   -
521   - case SI476X_FUNC_AM_RECEIVER:
522   - radio->ops = &am_ops;
523   - return 0;
524   - default:
525   - WARN(1, "Unexpected tuner function value\n");
526   - return -EINVAL;
527   - }
528   -}
529   -
530   -static int si476x_radio_pretune(struct si476x_radio *radio,
531   - enum si476x_func func)
532   -{
533   - int retval;
534   -
535   - struct si476x_tune_freq_args args = {
536   - .zifsr = false,
537   - .hd = false,
538   - .injside = SI476X_INJSIDE_AUTO,
539   - .tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE,
540   - .smoothmetrics = SI476X_SM_INITIALIZE_AUDIO,
541   - .antcap = 0,
542   - };
543   -
544   - switch (func) {
545   - case SI476X_FUNC_FM_RECEIVER:
546   - args.freq = v4l2_to_si476x(radio->core,
547   - 92 * FREQ_MUL);
548   - retval = radio->ops->tune_freq(radio->core, &args);
549   - break;
550   - case SI476X_FUNC_AM_RECEIVER:
551   - args.freq = v4l2_to_si476x(radio->core,
552   - 0.6 * FREQ_MUL);
553   - retval = radio->ops->tune_freq(radio->core, &args);
554   - break;
555   - default:
556   - WARN(1, "Unexpected tuner function value\n");
557   - retval = -EINVAL;
558   - }
559   -
560   - return retval;
561   -}
562   -static int si476x_radio_do_post_powerup_init(struct si476x_radio *radio,
563   - enum si476x_func func)
564   -{
565   - int err;
566   -
567   - /* regcache_mark_dirty(radio->core->regmap); */
568   - err = regcache_sync_region(radio->core->regmap,
569   - SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE,
570   - SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT);
571   - if (err < 0)
572   - return err;
573   -
574   - err = regcache_sync_region(radio->core->regmap,
575   - SI476X_PROP_AUDIO_DEEMPHASIS,
576   - SI476X_PROP_AUDIO_PWR_LINE_FILTER);
577   - if (err < 0)
578   - return err;
579   -
580   - err = regcache_sync_region(radio->core->regmap,
581   - SI476X_PROP_INT_CTL_ENABLE,
582   - SI476X_PROP_INT_CTL_ENABLE);
583   - if (err < 0)
584   - return err;
585   -
586   - /*
587   - * Is there any point in restoring SNR and the like
588   - * when switching between AM/FM?
589   - */
590   - err = regcache_sync_region(radio->core->regmap,
591   - SI476X_PROP_VALID_MAX_TUNE_ERROR,
592   - SI476X_PROP_VALID_MAX_TUNE_ERROR);
593   - if (err < 0)
594   - return err;
595   -
596   - err = regcache_sync_region(radio->core->regmap,
597   - SI476X_PROP_VALID_SNR_THRESHOLD,
598   - SI476X_PROP_VALID_RSSI_THRESHOLD);
599   - if (err < 0)
600   - return err;
601   -
602   - if (func == SI476X_FUNC_FM_RECEIVER) {
603   - if (si476x_core_has_diversity(radio->core)) {
604   - err = si476x_core_cmd_fm_phase_diversity(radio->core,
605   - radio->core->diversity_mode);
606   - if (err < 0)
607   - return err;
608   - }
609   -
610   - err = regcache_sync_region(radio->core->regmap,
611   - SI476X_PROP_FM_RDS_INTERRUPT_SOURCE,
612   - SI476X_PROP_FM_RDS_CONFIG);
613   - if (err < 0)
614   - return err;
615   - }
616   -
617   - return si476x_radio_init_vtable(radio, func);
618   -
619   -}
620   -
621   -static int si476x_radio_change_func(struct si476x_radio *radio,
622   - enum si476x_func func)
623   -{
624   - int err;
625   - bool soft;
626   - /*
627   - * Since power/up down is a very time consuming operation,
628   - * try to avoid doing it if the requested mode matches the one
629   - * the tuner is in
630   - */
631   - if (func == radio->core->power_up_parameters.func)
632   - return 0;
633   -
634   - soft = true;
635   - err = si476x_core_stop(radio->core, soft);
636   - if (err < 0) {
637   - /*
638   - * OK, if the chip does not want to play nice let's
639   - * try to reset it in more brutal way
640   - */
641   - soft = false;
642   - err = si476x_core_stop(radio->core, soft);
643   - if (err < 0)
644   - return err;
645   - }
646   - /*
647   - Set the desired radio tuner function
648   - */
649   - radio->core->power_up_parameters.func = func;
650   -
651   - err = si476x_core_start(radio->core, soft);
652   - if (err < 0)
653   - return err;
654   -
655   - /*
656   - * No need to do the rest of manipulations for the bootlader
657   - * mode
658   - */
659   - if (func != SI476X_FUNC_FM_RECEIVER &&
660   - func != SI476X_FUNC_AM_RECEIVER)
661   - return err;
662   -
663   - return si476x_radio_do_post_powerup_init(radio, func);
664   -}
665   -
666   -static int si476x_radio_g_frequency(struct file *file, void *priv,
667   - struct v4l2_frequency *f)
668   -{
669   - int err;
670   - struct si476x_radio *radio = video_drvdata(file);
671   -
672   - if (f->tuner != 0 ||
673   - f->type != V4L2_TUNER_RADIO)
674   - return -EINVAL;
675   -
676   - si476x_core_lock(radio->core);
677   -
678   - if (radio->ops->rsq_status) {
679   - struct si476x_rsq_status_report report;
680   - struct si476x_rsq_status_args args = {
681   - .primary = false,
682   - .rsqack = false,
683   - .attune = true,
684   - .cancel = false,
685   - .stcack = false,
686   - };
687   -
688   - err = radio->ops->rsq_status(radio->core, &args, &report);
689   - if (!err)
690   - f->frequency = si476x_to_v4l2(radio->core,
691   - report.readfreq);
692   - } else {
693   - err = -EINVAL;
694   - }
695   -
696   - si476x_core_unlock(radio->core);
697   -
698   - return err;
699   -}
700   -
701   -static int si476x_radio_s_frequency(struct file *file, void *priv,
702   - const struct v4l2_frequency *f)
703   -{
704   - int err;
705   - u32 freq = f->frequency;
706   - struct si476x_tune_freq_args args;
707   - struct si476x_radio *radio = video_drvdata(file);
708   -
709   - const u32 midrange = (si476x_bands[SI476X_BAND_AM].rangehigh +
710   - si476x_bands[SI476X_BAND_FM].rangelow) / 2;
711   - const int band = (freq > midrange) ?
712   - SI476X_BAND_FM : SI476X_BAND_AM;
713   - const enum si476x_func func = (band == SI476X_BAND_AM) ?
714   - SI476X_FUNC_AM_RECEIVER : SI476X_FUNC_FM_RECEIVER;
715   -
716   - if (f->tuner != 0 ||
717   - f->type != V4L2_TUNER_RADIO)
718   - return -EINVAL;
719   -
720   - si476x_core_lock(radio->core);
721   -
722   - freq = clamp(freq,
723   - si476x_bands[band].rangelow,
724   - si476x_bands[band].rangehigh);
725   -
726   - if (si476x_radio_freq_is_inside_of_the_band(freq,
727   - SI476X_BAND_AM) &&
728   - (!si476x_core_has_am(radio->core) ||
729   - si476x_core_is_a_secondary_tuner(radio->core))) {
730   - err = -EINVAL;
731   - goto unlock;
732   - }
733   -
734   - err = si476x_radio_change_func(radio, func);
735   - if (err < 0)
736   - goto unlock;
737   -
738   - args.zifsr = false;
739   - args.hd = false;
740   - args.injside = SI476X_INJSIDE_AUTO;
741   - args.freq = v4l2_to_si476x(radio->core, freq);
742   - args.tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE;
743   - args.smoothmetrics = SI476X_SM_INITIALIZE_AUDIO;
744   - args.antcap = 0;
745   -
746   - err = radio->ops->tune_freq(radio->core, &args);
747   -
748   -unlock:
749   - si476x_core_unlock(radio->core);
750   - return err;
751   -}
752   -
753   -static int si476x_radio_s_hw_freq_seek(struct file *file, void *priv,
754   - const struct v4l2_hw_freq_seek *seek)
755   -{
756   - int err;
757   - enum si476x_func func;
758   - u32 rangelow, rangehigh;
759   - struct si476x_radio *radio = video_drvdata(file);
760   -
761   - if (file->f_flags & O_NONBLOCK)
762   - return -EAGAIN;
763   -
764   - if (seek->tuner != 0 ||
765   - seek->type != V4L2_TUNER_RADIO)
766   - return -EINVAL;
767   -
768   - si476x_core_lock(radio->core);
769   -
770   - if (!seek->rangelow) {
771   - err = regmap_read(radio->core->regmap,
772   - SI476X_PROP_SEEK_BAND_BOTTOM,
773   - &rangelow);
774   - if (!err)
775   - rangelow = si476x_to_v4l2(radio->core, rangelow);
776   - else
777   - goto unlock;
778   - }
779   - if (!seek->rangehigh) {
780   - err = regmap_read(radio->core->regmap,
781   - SI476X_PROP_SEEK_BAND_TOP,
782   - &rangehigh);
783   - if (!err)
784   - rangehigh = si476x_to_v4l2(radio->core, rangehigh);
785   - else
786   - goto unlock;
787   - }
788   -
789   - if (rangelow > rangehigh) {
790   - err = -EINVAL;
791   - goto unlock;
792   - }
793   -
794   - if (si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh,
795   - SI476X_BAND_FM)) {
796   - func = SI476X_FUNC_FM_RECEIVER;
797   -
798   - } else if (si476x_core_has_am(radio->core) &&
799   - si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh,
800   - SI476X_BAND_AM)) {
801   - func = SI476X_FUNC_AM_RECEIVER;
802   - } else {
803   - err = -EINVAL;
804   - goto unlock;
805   - }
806   -
807   - err = si476x_radio_change_func(radio, func);
808   - if (err < 0)
809   - goto unlock;
810   -
811   - if (seek->rangehigh) {
812   - err = regmap_write(radio->core->regmap,
813   - SI476X_PROP_SEEK_BAND_TOP,
814   - v4l2_to_si476x(radio->core,
815   - seek->rangehigh));
816   - if (err)
817   - goto unlock;
818   - }
819   - if (seek->rangelow) {
820   - err = regmap_write(radio->core->regmap,
821   - SI476X_PROP_SEEK_BAND_BOTTOM,
822   - v4l2_to_si476x(radio->core,
823   - seek->rangelow));
824   - if (err)
825   - goto unlock;
826   - }
827   - if (seek->spacing) {
828   - err = regmap_write(radio->core->regmap,
829   - SI476X_PROP_SEEK_FREQUENCY_SPACING,
830   - v4l2_to_si476x(radio->core,
831   - seek->spacing));
832   - if (err)
833   - goto unlock;
834   - }
835   -
836   - err = radio->ops->seek_start(radio->core,
837   - seek->seek_upward,
838   - seek->wrap_around);
839   -unlock:
840   - si476x_core_unlock(radio->core);
841   -
842   -
843   -
844   - return err;
845   -}
846   -
847   -static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
848   -{
849   - int retval;
850   - struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler);
851   -
852   - si476x_core_lock(radio->core);
853   -
854   - switch (ctrl->id) {
855   - case V4L2_CID_SI476X_INTERCHIP_LINK:
856   - if (si476x_core_has_diversity(radio->core)) {
857   - if (radio->ops->phase_diversity) {
858   - retval = radio->ops->phase_div_status(radio->core);
859   - if (retval < 0)
860   - break;
861   -
862   - ctrl->val = !!SI476X_PHDIV_STATUS_LINK_LOCKED(retval);
863   - retval = 0;
864   - break;
865   - } else {
866   - retval = -ENOTTY;
867   - break;
868   - }
869   - }
870   - retval = -EINVAL;
871   - break;
872   - default:
873   - retval = -EINVAL;
874   - break;
875   - }
876   - si476x_core_unlock(radio->core);
877   - return retval;
878   -
879   -}
880   -
881   -static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl)
882   -{
883   - int retval;
884   - enum si476x_phase_diversity_mode mode;
885   - struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler);
886   -
887   - si476x_core_lock(radio->core);
888   -
889   - switch (ctrl->id) {
890   - case V4L2_CID_SI476X_HARMONICS_COUNT:
891   - retval = regmap_update_bits(radio->core->regmap,
892   - SI476X_PROP_AUDIO_PWR_LINE_FILTER,
893   - SI476X_PROP_PWR_HARMONICS_MASK,
894   - ctrl->val);
895   - break;
896   - case V4L2_CID_POWER_LINE_FREQUENCY:
897   - switch (ctrl->val) {
898   - case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
899   - retval = regmap_update_bits(radio->core->regmap,
900   - SI476X_PROP_AUDIO_PWR_LINE_FILTER,
901   - SI476X_PROP_PWR_ENABLE_MASK,
902   - 0);
903   - break;
904   - case V4L2_CID_POWER_LINE_FREQUENCY_50HZ:
905   - retval = regmap_update_bits(radio->core->regmap,
906   - SI476X_PROP_AUDIO_PWR_LINE_FILTER,
907   - SI476X_PROP_PWR_GRID_MASK,
908   - SI476X_PROP_PWR_GRID_50HZ);
909   - break;
910   - case V4L2_CID_POWER_LINE_FREQUENCY_60HZ:
911   - retval = regmap_update_bits(radio->core->regmap,
912   - SI476X_PROP_AUDIO_PWR_LINE_FILTER,
913   - SI476X_PROP_PWR_GRID_MASK,
914   - SI476X_PROP_PWR_GRID_60HZ);
915   - break;
916   - default:
917   - retval = -EINVAL;
918   - break;
919   - }
920   - break;
921   - case V4L2_CID_SI476X_RSSI_THRESHOLD:
922   - retval = regmap_write(radio->core->regmap,
923   - SI476X_PROP_VALID_RSSI_THRESHOLD,
924   - ctrl->val);
925   - break;
926   - case V4L2_CID_SI476X_SNR_THRESHOLD:
927   - retval = regmap_write(radio->core->regmap,
928   - SI476X_PROP_VALID_SNR_THRESHOLD,
929   - ctrl->val);
930   - break;
931   - case V4L2_CID_SI476X_MAX_TUNE_ERROR:
932   - retval = regmap_write(radio->core->regmap,
933   - SI476X_PROP_VALID_MAX_TUNE_ERROR,
934   - ctrl->val);
935   - break;
936   - case V4L2_CID_RDS_RECEPTION:
937   - /*
938   - * It looks like RDS related properties are
939   - * inaccesable when tuner is in AM mode, so cache the
940   - * changes
941   - */
942   - if (si476x_core_is_in_am_receiver_mode(radio->core))
943   - regcache_cache_only(radio->core->regmap, true);
944   -
945   - if (ctrl->val) {
946   - retval = regmap_write(radio->core->regmap,
947   - SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT,
948   - radio->core->rds_fifo_depth);
949   - if (retval < 0)
950   - break;
951   -
952   - if (radio->core->client->irq) {
953   - retval = regmap_write(radio->core->regmap,
954   - SI476X_PROP_FM_RDS_INTERRUPT_SOURCE,
955   - SI476X_RDSRECV);
956   - if (retval < 0)
957   - break;
958   - }
959   -
960   - /* Drain RDS FIFO before enabling RDS processing */
961   - retval = si476x_core_cmd_fm_rds_status(radio->core,
962   - false,
963   - true,
964   - true,
965   - NULL);
966   - if (retval < 0)
967   - break;
968   -
969   - retval = regmap_update_bits(radio->core->regmap,
970   - SI476X_PROP_FM_RDS_CONFIG,
971   - SI476X_PROP_RDSEN_MASK,
972   - SI476X_PROP_RDSEN);
973   - } else {
974   - retval = regmap_update_bits(radio->core->regmap,
975   - SI476X_PROP_FM_RDS_CONFIG,
976   - SI476X_PROP_RDSEN_MASK,
977   - !SI476X_PROP_RDSEN);
978   - }
979   -
980   - if (si476x_core_is_in_am_receiver_mode(radio->core))
981   - regcache_cache_only(radio->core->regmap, false);
982   - break;
983   - case V4L2_CID_TUNE_DEEMPHASIS:
984   - retval = regmap_write(radio->core->regmap,
985   - SI476X_PROP_AUDIO_DEEMPHASIS,
986   - ctrl->val);
987   - break;
988   -
989   - case V4L2_CID_SI476X_DIVERSITY_MODE:
990   - mode = si476x_phase_diversity_idx_to_mode(ctrl->val);
991   -
992   - if (mode == radio->core->diversity_mode) {
993   - retval = 0;
994   - break;
995   - }
996   -
997   - if (si476x_core_is_in_am_receiver_mode(radio->core)) {
998   - /*
999   - * Diversity cannot be configured while tuner
1000   - * is in AM mode so save the changes and carry on.
1001   - */
1002   - radio->core->diversity_mode = mode;
1003   - retval = 0;
1004   - } else {
1005   - retval = radio->ops->phase_diversity(radio->core, mode);
1006   - if (!retval)
1007   - radio->core->diversity_mode = mode;
1008   - }
1009   - break;
1010   -
1011   - default:
1012   - retval = -EINVAL;
1013   - break;
1014   - }
1015   -
1016   - si476x_core_unlock(radio->core);
1017   -
1018   - return retval;
1019   -}
1020   -
1021   -static int si476x_radio_g_chip_ident(struct file *file, void *fh,
1022   - struct v4l2_dbg_chip_ident *chip)
1023   -{
1024   - if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
1025   - v4l2_chip_match_host(&chip->match))
1026   - return 0;
1027   - return -EINVAL;
1028   -}
1029   -
1030   -
1031   -#ifdef CONFIG_VIDEO_ADV_DEBUG
1032   -static int si476x_radio_g_register(struct file *file, void *fh,
1033   - struct v4l2_dbg_register *reg)
1034   -{
1035   - int err;
1036   - unsigned int value;
1037   - struct si476x_radio *radio = video_drvdata(file);
1038   -
1039   - si476x_core_lock(radio->core);
1040   - reg->size = 2;
1041   - err = regmap_read(radio->core->regmap,
1042   - (unsigned int)reg->reg, &value);
1043   - reg->val = value;
1044   - si476x_core_unlock(radio->core);
1045   -
1046   - return err;
1047   -}
1048   -static int si476x_radio_s_register(struct file *file, void *fh,
1049   - const struct v4l2_dbg_register *reg)
1050   -{
1051   -
1052   - int err;
1053   - struct si476x_radio *radio = video_drvdata(file);
1054   -
1055   - si476x_core_lock(radio->core);
1056   - err = regmap_write(radio->core->regmap,
1057   - (unsigned int)reg->reg,
1058   - (unsigned int)reg->val);
1059   - si476x_core_unlock(radio->core);
1060   -
1061   - return err;
1062   -}
1063   -#endif
1064   -
1065   -static int si476x_radio_fops_open(struct file *file)
1066   -{
1067   - struct si476x_radio *radio = video_drvdata(file);
1068   - int err;
1069   -
1070   - err = v4l2_fh_open(file);
1071   - if (err)
1072   - return err;
1073   -
1074   - if (v4l2_fh_is_singular_file(file)) {
1075   - si476x_core_lock(radio->core);
1076   - err = si476x_core_set_power_state(radio->core,
1077   - SI476X_POWER_UP_FULL);
1078   - if (err < 0)
1079   - goto done;
1080   -
1081   - err = si476x_radio_do_post_powerup_init(radio,
1082   - radio->core->power_up_parameters.func);
1083   - if (err < 0)
1084   - goto power_down;
1085   -
1086   - err = si476x_radio_pretune(radio,
1087   - radio->core->power_up_parameters.func);
1088   - if (err < 0)
1089   - goto power_down;
1090   -
1091   - si476x_core_unlock(radio->core);
1092   - /*Must be done after si476x_core_unlock to prevent a deadlock*/
1093   - v4l2_ctrl_handler_setup(&radio->ctrl_handler);
1094   - }
1095   -
1096   - return err;
1097   -
1098   -power_down:
1099   - si476x_core_set_power_state(radio->core,
1100   - SI476X_POWER_DOWN);
1101   -done:
1102   - si476x_core_unlock(radio->core);
1103   - v4l2_fh_release(file);
1104   -
1105   - return err;
1106   -}
1107   -
1108   -static int si476x_radio_fops_release(struct file *file)
1109   -{
1110   - int err;
1111   - struct si476x_radio *radio = video_drvdata(file);
1112   -
1113   - if (v4l2_fh_is_singular_file(file) &&
1114   - atomic_read(&radio->core->is_alive))
1115   - si476x_core_set_power_state(radio->core,
1116   - SI476X_POWER_DOWN);
1117   -
1118   - err = v4l2_fh_release(file);
1119   -
1120   - return err;
1121   -}
1122   -
1123   -static ssize_t si476x_radio_fops_read(struct file *file, char __user *buf,
1124   - size_t count, loff_t *ppos)
1125   -{
1126   - ssize_t rval;
1127   - size_t fifo_len;
1128   - unsigned int copied;
1129   -
1130   - struct si476x_radio *radio = video_drvdata(file);
1131   -
1132   - /* block if no new data available */
1133   - if (kfifo_is_empty(&radio->core->rds_fifo)) {
1134   - if (file->f_flags & O_NONBLOCK)
1135   - return -EWOULDBLOCK;
1136   -
1137   - rval = wait_event_interruptible(radio->core->rds_read_queue,
1138   - (!kfifo_is_empty(&radio->core->rds_fifo) ||
1139   - !atomic_read(&radio->core->is_alive)));
1140   - if (rval < 0)
1141   - return -EINTR;
1142   -
1143   - if (!atomic_read(&radio->core->is_alive))
1144   - return -ENODEV;
1145   - }
1146   -
1147   - fifo_len = kfifo_len(&radio->core->rds_fifo);
1148   -
1149   - if (kfifo_to_user(&radio->core->rds_fifo, buf,
1150   - min(fifo_len, count),
1151   - &copied) != 0) {
1152   - dev_warn(&radio->videodev.dev,
1153   - "Error during FIFO to userspace copy\n");
1154   - rval = -EIO;
1155   - } else {
1156   - rval = (ssize_t)copied;
1157   - }
1158   -
1159   - return rval;
1160   -}
1161   -
1162   -static unsigned int si476x_radio_fops_poll(struct file *file,
1163   - struct poll_table_struct *pts)
1164   -{
1165   - struct si476x_radio *radio = video_drvdata(file);
1166   - unsigned long req_events = poll_requested_events(pts);
1167   - unsigned int err = v4l2_ctrl_poll(file, pts);
1168   -
1169   - if (req_events & (POLLIN | POLLRDNORM)) {
1170   - if (atomic_read(&radio->core->is_alive))
1171   - poll_wait(file, &radio->core->rds_read_queue, pts);
1172   -
1173   - if (!atomic_read(&radio->core->is_alive))
1174   - err = POLLHUP;
1175   -
1176   - if (!kfifo_is_empty(&radio->core->rds_fifo))
1177   - err = POLLIN | POLLRDNORM;
1178   - }
1179   -
1180   - return err;
1181   -}
1182   -
1183   -static const struct v4l2_file_operations si476x_fops = {
1184   - .owner = THIS_MODULE,
1185   - .read = si476x_radio_fops_read,
1186   - .poll = si476x_radio_fops_poll,
1187   - .unlocked_ioctl = video_ioctl2,
1188   - .open = si476x_radio_fops_open,
1189   - .release = si476x_radio_fops_release,
1190   -};
1191   -
1192   -
1193   -static const struct v4l2_ioctl_ops si4761_ioctl_ops = {
1194   - .vidioc_querycap = si476x_radio_querycap,
1195   - .vidioc_g_tuner = si476x_radio_g_tuner,
1196   - .vidioc_s_tuner = si476x_radio_s_tuner,
1197   -
1198   - .vidioc_g_frequency = si476x_radio_g_frequency,
1199   - .vidioc_s_frequency = si476x_radio_s_frequency,
1200   - .vidioc_s_hw_freq_seek = si476x_radio_s_hw_freq_seek,
1201   - .vidioc_enum_freq_bands = si476x_radio_enum_freq_bands,
1202   -
1203   - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
1204   - .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
1205   -
1206   - .vidioc_g_chip_ident = si476x_radio_g_chip_ident,
1207   -#ifdef CONFIG_VIDEO_ADV_DEBUG
1208   - .vidioc_g_register = si476x_radio_g_register,
1209   - .vidioc_s_register = si476x_radio_s_register,
1210   -#endif
1211   -};
1212   -
1213   -
1214   -static const struct video_device si476x_viddev_template = {
1215   - .fops = &si476x_fops,
1216   - .name = DRIVER_NAME,
1217   - .release = video_device_release_empty,
1218   -};
1219   -
1220   -
1221   -
1222   -static ssize_t si476x_radio_read_acf_blob(struct file *file,
1223   - char __user *user_buf,
1224   - size_t count, loff_t *ppos)
1225   -{
1226   - int err;
1227   - struct si476x_radio *radio = file->private_data;
1228   - struct si476x_acf_status_report report;
1229   -
1230   - si476x_core_lock(radio->core);
1231   - if (radio->ops->acf_status)
1232   - err = radio->ops->acf_status(radio->core, &report);
1233   - else
1234   - err = -ENOENT;
1235   - si476x_core_unlock(radio->core);
1236   -
1237   - if (err < 0)
1238   - return err;
1239   -
1240   - return simple_read_from_buffer(user_buf, count, ppos, &report,
1241   - sizeof(report));
1242   -}
1243   -
1244   -static const struct file_operations radio_acf_fops = {
1245   - .open = simple_open,
1246   - .llseek = default_llseek,
1247   - .read = si476x_radio_read_acf_blob,
1248   -};
1249   -
1250   -static ssize_t si476x_radio_read_rds_blckcnt_blob(struct file *file,
1251   - char __user *user_buf,
1252   - size_t count, loff_t *ppos)
1253   -{
1254   - int err;
1255   - struct si476x_radio *radio = file->private_data;
1256   - struct si476x_rds_blockcount_report report;
1257   -
1258   - si476x_core_lock(radio->core);
1259   - if (radio->ops->rds_blckcnt)
1260   - err = radio->ops->rds_blckcnt(radio->core, true,
1261   - &report);
1262   - else
1263   - err = -ENOENT;
1264   - si476x_core_unlock(radio->core);
1265   -
1266   - if (err < 0)
1267   - return err;
1268   -
1269   - return simple_read_from_buffer(user_buf, count, ppos, &report,
1270   - sizeof(report));
1271   -}
1272   -
1273   -static const struct file_operations radio_rds_blckcnt_fops = {
1274   - .open = simple_open,
1275   - .llseek = default_llseek,
1276   - .read = si476x_radio_read_rds_blckcnt_blob,
1277   -};
1278   -
1279   -static ssize_t si476x_radio_read_agc_blob(struct file *file,
1280   - char __user *user_buf,
1281   - size_t count, loff_t *ppos)
1282   -{
1283   - int err;
1284   - struct si476x_radio *radio = file->private_data;
1285   - struct si476x_agc_status_report report;
1286   -
1287   - si476x_core_lock(radio->core);
1288   - if (radio->ops->rds_blckcnt)
1289   - err = radio->ops->agc_status(radio->core, &report);
1290   - else
1291   - err = -ENOENT;
1292   - si476x_core_unlock(radio->core);
1293   -
1294   - if (err < 0)
1295   - return err;
1296   -
1297   - return simple_read_from_buffer(user_buf, count, ppos, &report,
1298   - sizeof(report));
1299   -}
1300   -
1301   -static const struct file_operations radio_agc_fops = {
1302   - .open = simple_open,
1303   - .llseek = default_llseek,
1304   - .read = si476x_radio_read_agc_blob,
1305   -};
1306   -
1307   -static ssize_t si476x_radio_read_rsq_blob(struct file *file,
1308   - char __user *user_buf,
1309   - size_t count, loff_t *ppos)
1310   -{
1311   - int err;
1312   - struct si476x_radio *radio = file->private_data;
1313   - struct si476x_rsq_status_report report;
1314   - struct si476x_rsq_status_args args = {
1315   - .primary = false,
1316   - .rsqack = false,
1317   - .attune = false,
1318   - .cancel = false,
1319   - .stcack = false,
1320   - };
1321   -
1322   - si476x_core_lock(radio->core);
1323   - if (radio->ops->rds_blckcnt)
1324   - err = radio->ops->rsq_status(radio->core, &args, &report);
1325   - else
1326   - err = -ENOENT;
1327   - si476x_core_unlock(radio->core);
1328   -
1329   - if (err < 0)
1330   - return err;
1331   -
1332   - return simple_read_from_buffer(user_buf, count, ppos, &report,
1333   - sizeof(report));
1334   -}
1335   -
1336   -static const struct file_operations radio_rsq_fops = {
1337   - .open = simple_open,
1338   - .llseek = default_llseek,
1339   - .read = si476x_radio_read_rsq_blob,
1340   -};
1341   -
1342   -static ssize_t si476x_radio_read_rsq_primary_blob(struct file *file,
1343   - char __user *user_buf,
1344   - size_t count, loff_t *ppos)
1345   -{
1346   - int err;
1347   - struct si476x_radio *radio = file->private_data;
1348   - struct si476x_rsq_status_report report;
1349   - struct si476x_rsq_status_args args = {
1350   - .primary = true,
1351   - .rsqack = false,
1352   - .attune = false,
1353   - .cancel = false,
1354   - .stcack = false,
1355   - };
1356   -
1357   - si476x_core_lock(radio->core);
1358   - if (radio->ops->rds_blckcnt)
1359   - err = radio->ops->rsq_status(radio->core, &args, &report);
1360   - else
1361   - err = -ENOENT;
1362   - si476x_core_unlock(radio->core);
1363   -
1364   - if (err < 0)
1365   - return err;
1366   -
1367   - return simple_read_from_buffer(user_buf, count, ppos, &report,
1368   - sizeof(report));
1369   -}
1370   -
1371   -static const struct file_operations radio_rsq_primary_fops = {
1372   - .open = simple_open,
1373   - .llseek = default_llseek,
1374   - .read = si476x_radio_read_rsq_primary_blob,
1375   -};
1376   -
1377   -
1378   -static int si476x_radio_init_debugfs(struct si476x_radio *radio)
1379   -{
1380   - struct dentry *dentry;
1381   - int ret;
1382   -
1383   - dentry = debugfs_create_dir(dev_name(radio->v4l2dev.dev), NULL);
1384   - if (IS_ERR(dentry)) {
1385   - ret = PTR_ERR(dentry);
1386   - goto exit;
1387   - }
1388   - radio->debugfs = dentry;
1389   -
1390   - dentry = debugfs_create_file("acf", S_IRUGO,
1391   - radio->debugfs, radio, &radio_acf_fops);
1392   - if (IS_ERR(dentry)) {
1393   - ret = PTR_ERR(dentry);
1394   - goto cleanup;
1395   - }
1396   -
1397   - dentry = debugfs_create_file("rds_blckcnt", S_IRUGO,
1398   - radio->debugfs, radio,
1399   - &radio_rds_blckcnt_fops);
1400   - if (IS_ERR(dentry)) {
1401   - ret = PTR_ERR(dentry);
1402   - goto cleanup;
1403   - }
1404   -
1405   - dentry = debugfs_create_file("agc", S_IRUGO,
1406   - radio->debugfs, radio, &radio_agc_fops);
1407   - if (IS_ERR(dentry)) {
1408   - ret = PTR_ERR(dentry);
1409   - goto cleanup;
1410   - }
1411   -
1412   - dentry = debugfs_create_file("rsq", S_IRUGO,
1413   - radio->debugfs, radio, &radio_rsq_fops);
1414   - if (IS_ERR(dentry)) {
1415   - ret = PTR_ERR(dentry);
1416   - goto cleanup;
1417   - }
1418   -
1419   - dentry = debugfs_create_file("rsq_primary", S_IRUGO,
1420   - radio->debugfs, radio,
1421   - &radio_rsq_primary_fops);
1422   - if (IS_ERR(dentry)) {
1423   - ret = PTR_ERR(dentry);
1424   - goto cleanup;
1425   - }
1426   -
1427   - return 0;
1428   -cleanup:
1429   - debugfs_remove_recursive(radio->debugfs);
1430   -exit:
1431   - return ret;
1432   -}
1433   -
1434   -
1435   -static int si476x_radio_add_new_custom(struct si476x_radio *radio,
1436   - enum si476x_ctrl_idx idx)
1437   -{
1438   - int rval;
1439   - struct v4l2_ctrl *ctrl;
1440   -
1441   - ctrl = v4l2_ctrl_new_custom(&radio->ctrl_handler,
1442   - &si476x_ctrls[idx],
1443   - NULL);
1444   - rval = radio->ctrl_handler.error;
1445   - if (ctrl == NULL && rval)
1446   - dev_err(radio->v4l2dev.dev,
1447   - "Could not initialize '%s' control %d\n",
1448   - si476x_ctrls[idx].name, rval);
1449   -
1450   - return rval;
1451   -}
1452   -
1453   -static int si476x_radio_probe(struct platform_device *pdev)
1454   -{
1455   - int rval;
1456   - struct si476x_radio *radio;
1457   - struct v4l2_ctrl *ctrl;
1458   -
1459   - static atomic_t instance = ATOMIC_INIT(0);
1460   -
1461   - radio = devm_kzalloc(&pdev->dev, sizeof(*radio), GFP_KERNEL);
1462   - if (!radio)
1463   - return -ENOMEM;
1464   -
1465   - radio->core = i2c_mfd_cell_to_core(&pdev->dev);
1466   -
1467   - v4l2_device_set_name(&radio->v4l2dev, DRIVER_NAME, &instance);
1468   -
1469   - rval = v4l2_device_register(&pdev->dev, &radio->v4l2dev);
1470   - if (rval) {
1471   - dev_err(&pdev->dev, "Cannot register v4l2_device.\n");
1472   - return rval;
1473   - }
1474   -
1475   - memcpy(&radio->videodev, &si476x_viddev_template,
1476   - sizeof(struct video_device));
1477   -
1478   - radio->videodev.v4l2_dev = &radio->v4l2dev;
1479   - radio->videodev.ioctl_ops = &si4761_ioctl_ops;
1480   -
1481   - video_set_drvdata(&radio->videodev, radio);
1482   - platform_set_drvdata(pdev, radio);
1483   -
1484   - set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags);
1485   -
1486   - radio->v4l2dev.ctrl_handler = &radio->ctrl_handler;
1487   - v4l2_ctrl_handler_init(&radio->ctrl_handler,
1488   - 1 + ARRAY_SIZE(si476x_ctrls));
1489   -
1490   - if (si476x_core_has_am(radio->core)) {
1491   - ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler,
1492   - &si476x_ctrl_ops,
1493   - V4L2_CID_POWER_LINE_FREQUENCY,
1494   - V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
1495   - 0, 0);
1496   - rval = radio->ctrl_handler.error;
1497   - if (ctrl == NULL && rval) {
1498   - dev_err(&pdev->dev, "Could not initialize V4L2_CID_POWER_LINE_FREQUENCY control %d\n",
1499   - rval);
1500   - goto exit;
1501   - }
1502   -
1503   - rval = si476x_radio_add_new_custom(radio,
1504   - SI476X_IDX_HARMONICS_COUNT);
1505   - if (rval < 0)
1506   - goto exit;
1507   - }
1508   -
1509   - rval = si476x_radio_add_new_custom(radio, SI476X_IDX_RSSI_THRESHOLD);
1510   - if (rval < 0)
1511   - goto exit;
1512   -
1513   - rval = si476x_radio_add_new_custom(radio, SI476X_IDX_SNR_THRESHOLD);
1514   - if (rval < 0)
1515   - goto exit;
1516   -
1517   - rval = si476x_radio_add_new_custom(radio, SI476X_IDX_MAX_TUNE_ERROR);
1518   - if (rval < 0)
1519   - goto exit;
1520   -
1521   - ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler,
1522   - &si476x_ctrl_ops,
1523   - V4L2_CID_TUNE_DEEMPHASIS,
1524   - V4L2_DEEMPHASIS_75_uS, 0, 0);
1525   - rval = radio->ctrl_handler.error;
1526   - if (ctrl == NULL && rval) {
1527   - dev_err(&pdev->dev, "Could not initialize V4L2_CID_TUNE_DEEMPHASIS control %d\n",
1528   - rval);
1529   - goto exit;
1530   - }
1531   -
1532   - ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &si476x_ctrl_ops,
1533   - V4L2_CID_RDS_RECEPTION,
1534   - 0, 1, 1, 1);
1535   - rval = radio->ctrl_handler.error;
1536   - if (ctrl == NULL && rval) {
1537   - dev_err(&pdev->dev, "Could not initialize V4L2_CID_RDS_RECEPTION control %d\n",
1538   - rval);
1539   - goto exit;
1540   - }
1541   -
1542   - if (si476x_core_has_diversity(radio->core)) {
1543   - si476x_ctrls[SI476X_IDX_DIVERSITY_MODE].def =
1544   - si476x_phase_diversity_mode_to_idx(radio->core->diversity_mode);
1545   - si476x_radio_add_new_custom(radio, SI476X_IDX_DIVERSITY_MODE);
1546   - if (rval < 0)
1547   - goto exit;
1548   -
1549   - si476x_radio_add_new_custom(radio, SI476X_IDX_INTERCHIP_LINK);
1550   - if (rval < 0)
1551   - goto exit;
1552   - }
1553   -
1554   - /* register video device */
1555   - rval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, -1);
1556   - if (rval < 0) {
1557   - dev_err(&pdev->dev, "Could not register video device\n");
1558   - goto exit;
1559   - }
1560   -
1561   - rval = si476x_radio_init_debugfs(radio);
1562   - if (rval < 0) {
1563   - dev_err(&pdev->dev, "Could not creat debugfs interface\n");
1564   - goto exit;
1565   - }
1566   -
1567   - return 0;
1568   -exit:
1569   - v4l2_ctrl_handler_free(radio->videodev.ctrl_handler);
1570   - return rval;
1571   -}
1572   -
1573   -static int si476x_radio_remove(struct platform_device *pdev)
1574   -{
1575   - struct si476x_radio *radio = platform_get_drvdata(pdev);
1576   -
1577   - v4l2_ctrl_handler_free(radio->videodev.ctrl_handler);
1578   - video_unregister_device(&radio->videodev);
1579   - v4l2_device_unregister(&radio->v4l2dev);
1580   - debugfs_remove_recursive(radio->debugfs);
1581   -
1582   - return 0;
1583   -}
1584   -
1585   -MODULE_ALIAS("platform:si476x-radio");
1586   -
1587   -static struct platform_driver si476x_radio_driver = {
1588   - .driver = {
1589   - .name = DRIVER_NAME,
1590   - .owner = THIS_MODULE,
1591   - },
1592   - .probe = si476x_radio_probe,
1593   - .remove = si476x_radio_remove,
1594   -};
1595   -module_platform_driver(si476x_radio_driver);
1596   -
1597   -MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
1598   -MODULE_DESCRIPTION("Driver for Si4761/64/68 AM/FM Radio MFD Cell");
1599   -MODULE_LICENSE("GPL");
include/media/si476x.h
1   -/*
2   - * include/media/si476x.h -- Common definitions for si476x driver
3   - *
4   - * Copyright (C) 2012 Innovative Converged Devices(ICD)
5   - * Copyright (C) 2013 Andrey Smirnov
6   - *
7   - * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
8   - *
9   - * This program is free software; you can redistribute it and/or modify
10   - * it under the terms of the GNU General Public License as published by
11   - * the Free Software Foundation; version 2 of the License.
12   - *
13   - * This program is distributed in the hope that it will be useful, but
14   - * WITHOUT ANY WARRANTY; without even the implied warranty of
15   - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   - * General Public License for more details.
17   - *
18   - */
19   -
20   -#ifndef SI476X_H
21   -#define SI476X_H
22   -
23   -#include <linux/types.h>
24   -#include <linux/videodev2.h>
25   -
26   -struct si476x_device;
27   -
28   -/* It is possible to select one of the four adresses using pins A0
29   - * and A1 on SI476x */
30   -#define SI476X_I2C_ADDR_1 0x60
31   -#define SI476X_I2C_ADDR_2 0x61
32   -#define SI476X_I2C_ADDR_3 0x62
33   -#define SI476X_I2C_ADDR_4 0x63
34   -
35   -enum si476x_iqclk_config {
36   - SI476X_IQCLK_NOOP = 0,
37   - SI476X_IQCLK_TRISTATE = 1,
38   - SI476X_IQCLK_IQ = 21,
39   -};
40   -enum si476x_iqfs_config {
41   - SI476X_IQFS_NOOP = 0,
42   - SI476X_IQFS_TRISTATE = 1,
43   - SI476X_IQFS_IQ = 21,
44   -};
45   -enum si476x_iout_config {
46   - SI476X_IOUT_NOOP = 0,
47   - SI476X_IOUT_TRISTATE = 1,
48   - SI476X_IOUT_OUTPUT = 22,
49   -};
50   -enum si476x_qout_config {
51   - SI476X_QOUT_NOOP = 0,
52   - SI476X_QOUT_TRISTATE = 1,
53   - SI476X_QOUT_OUTPUT = 22,
54   -};
55   -
56   -enum si476x_dclk_config {
57   - SI476X_DCLK_NOOP = 0,
58   - SI476X_DCLK_TRISTATE = 1,
59   - SI476X_DCLK_DAUDIO = 10,
60   -};
61   -
62   -enum si476x_dfs_config {
63   - SI476X_DFS_NOOP = 0,
64   - SI476X_DFS_TRISTATE = 1,
65   - SI476X_DFS_DAUDIO = 10,
66   -};
67   -
68   -enum si476x_dout_config {
69   - SI476X_DOUT_NOOP = 0,
70   - SI476X_DOUT_TRISTATE = 1,
71   - SI476X_DOUT_I2S_OUTPUT = 12,
72   - SI476X_DOUT_I2S_INPUT = 13,
73   -};
74   -
75   -enum si476x_xout_config {
76   - SI476X_XOUT_NOOP = 0,
77   - SI476X_XOUT_TRISTATE = 1,
78   - SI476X_XOUT_I2S_INPUT = 13,
79   - SI476X_XOUT_MODE_SELECT = 23,
80   -};
81   -
82   -
83   -enum si476x_icin_config {
84   - SI476X_ICIN_NOOP = 0,
85   - SI476X_ICIN_TRISTATE = 1,
86   - SI476X_ICIN_GPO1_HIGH = 2,
87   - SI476X_ICIN_GPO1_LOW = 3,
88   - SI476X_ICIN_IC_LINK = 30,
89   -};
90   -
91   -enum si476x_icip_config {
92   - SI476X_ICIP_NOOP = 0,
93   - SI476X_ICIP_TRISTATE = 1,
94   - SI476X_ICIP_GPO2_HIGH = 2,
95   - SI476X_ICIP_GPO2_LOW = 3,
96   - SI476X_ICIP_IC_LINK = 30,
97   -};
98   -
99   -enum si476x_icon_config {
100   - SI476X_ICON_NOOP = 0,
101   - SI476X_ICON_TRISTATE = 1,
102   - SI476X_ICON_I2S = 10,
103   - SI476X_ICON_IC_LINK = 30,
104   -};
105   -
106   -enum si476x_icop_config {
107   - SI476X_ICOP_NOOP = 0,
108   - SI476X_ICOP_TRISTATE = 1,
109   - SI476X_ICOP_I2S = 10,
110   - SI476X_ICOP_IC_LINK = 30,
111   -};
112   -
113   -
114   -enum si476x_lrout_config {
115   - SI476X_LROUT_NOOP = 0,
116   - SI476X_LROUT_TRISTATE = 1,
117   - SI476X_LROUT_AUDIO = 2,
118   - SI476X_LROUT_MPX = 3,
119   -};
120   -
121   -
122   -enum si476x_intb_config {
123   - SI476X_INTB_NOOP = 0,
124   - SI476X_INTB_TRISTATE = 1,
125   - SI476X_INTB_DAUDIO = 10,
126   - SI476X_INTB_IRQ = 40,
127   -};
128   -
129   -enum si476x_a1_config {
130   - SI476X_A1_NOOP = 0,
131   - SI476X_A1_TRISTATE = 1,
132   - SI476X_A1_IRQ = 40,
133   -};
134   -
135   -enum si476x_part_revisions {
136   - SI476X_REVISION_A10 = 0,
137   - SI476X_REVISION_A20 = 1,
138   - SI476X_REVISION_A30 = 2,
139   -};
140   -
141   -struct si476x_pinmux {
142   - enum si476x_dclk_config dclk;
143   - enum si476x_dfs_config dfs;
144   - enum si476x_dout_config dout;
145   - enum si476x_xout_config xout;
146   -
147   - enum si476x_iqclk_config iqclk;
148   - enum si476x_iqfs_config iqfs;
149   - enum si476x_iout_config iout;
150   - enum si476x_qout_config qout;
151   -
152   - enum si476x_icin_config icin;
153   - enum si476x_icip_config icip;
154   - enum si476x_icon_config icon;
155   - enum si476x_icop_config icop;
156   -
157   - enum si476x_lrout_config lrout;
158   -
159   - enum si476x_intb_config intb;
160   - enum si476x_a1_config a1;
161   -};
162   -
163   -/**
164   - * enum si476x_phase_diversity_mode - possbile phase diversity modes
165   - * for SI4764/5/6/7 chips.
166   - *
167   - * @SI476X_PHDIV_DISABLED: Phase diversity feature is
168   - * disabled.
169   - * @SI476X_PHDIV_PRIMARY_COMBINING: Tuner works as a primary tuner
170   - * in combination with a
171   - * secondary one.
172   - * @SI476X_PHDIV_PRIMARY_ANTENNA: Tuner works as a primary tuner
173   - * using only its own antenna.
174   - * @SI476X_PHDIV_SECONDARY_ANTENNA: Tuner works as a primary tuner
175   - * usning seconary tuner's antenna.
176   - * @SI476X_PHDIV_SECONDARY_COMBINING: Tuner works as a secondary
177   - * tuner in combination with the
178   - * primary one.
179   - */
180   -enum si476x_phase_diversity_mode {
181   - SI476X_PHDIV_DISABLED = 0,
182   - SI476X_PHDIV_PRIMARY_COMBINING = 1,
183   - SI476X_PHDIV_PRIMARY_ANTENNA = 2,
184   - SI476X_PHDIV_SECONDARY_ANTENNA = 3,
185   - SI476X_PHDIV_SECONDARY_COMBINING = 5,
186   -};
187   -
188   -enum si476x_ibias6x {
189   - SI476X_IBIAS6X_OTHER = 0,
190   - SI476X_IBIAS6X_RCVR1_NON_4MHZ_CLK = 1,
191   -};
192   -
193   -enum si476x_xstart {
194   - SI476X_XSTART_MULTIPLE_TUNER = 0x11,
195   - SI476X_XSTART_NORMAL = 0x77,
196   -};
197   -
198   -enum si476x_freq {
199   - SI476X_FREQ_4_MHZ = 0,
200   - SI476X_FREQ_37P209375_MHZ = 1,
201   - SI476X_FREQ_36P4_MHZ = 2,
202   - SI476X_FREQ_37P8_MHZ = 3,
203   -};
204   -
205   -enum si476x_xmode {
206   - SI476X_XMODE_CRYSTAL_RCVR1 = 1,
207   - SI476X_XMODE_EXT_CLOCK = 2,
208   - SI476X_XMODE_CRYSTAL_RCVR2_3 = 3,
209   -};
210   -
211   -enum si476x_xbiashc {
212   - SI476X_XBIASHC_SINGLE_RECEIVER = 0,
213   - SI476X_XBIASHC_MULTIPLE_RECEIVER = 1,
214   -};
215   -
216   -enum si476x_xbias {
217   - SI476X_XBIAS_RCVR2_3 = 0,
218   - SI476X_XBIAS_4MHZ_RCVR1 = 3,
219   - SI476X_XBIAS_RCVR1 = 7,
220   -};
221   -
222   -enum si476x_func {
223   - SI476X_FUNC_BOOTLOADER = 0,
224   - SI476X_FUNC_FM_RECEIVER = 1,
225   - SI476X_FUNC_AM_RECEIVER = 2,
226   - SI476X_FUNC_WB_RECEIVER = 3,
227   -};
228   -
229   -
230   -/**
231   - * @xcload: Selects the amount of additional on-chip capacitance to
232   - * be connected between XTAL1 and gnd and between XTAL2 and
233   - * GND. One half of the capacitance value shown here is the
234   - * additional load capacitance presented to the xtal. The
235   - * minimum step size is 0.277 pF. Recommended value is 0x28
236   - * but it will be layout dependent. Range is 0โ€“0x3F i.e.
237   - * (0โ€“16.33 pF)
238   - * @ctsien: enable CTSINT(interrupt request when CTS condition
239   - * arises) when set
240   - * @intsel: when set A1 pin becomes the interrupt pin; otherwise,
241   - * INTB is the interrupt pin
242   - * @func: selects the boot function of the device. I.e.
243   - * SI476X_BOOTLOADER - Boot loader
244   - * SI476X_FM_RECEIVER - FM receiver
245   - * SI476X_AM_RECEIVER - AM receiver
246   - * SI476X_WB_RECEIVER - Weatherband receiver
247   - * @freq: oscillator's crystal frequency:
248   - * SI476X_XTAL_37P209375_MHZ - 37.209375 Mhz
249   - * SI476X_XTAL_36P4_MHZ - 36.4 Mhz
250   - * SI476X_XTAL_37P8_MHZ - 37.8 Mhz
251   - */
252   -struct si476x_power_up_args {
253   - enum si476x_ibias6x ibias6x;
254   - enum si476x_xstart xstart;
255   - u8 xcload;
256   - bool fastboot;
257   - enum si476x_xbiashc xbiashc;
258   - enum si476x_xbias xbias;
259   - enum si476x_func func;
260   - enum si476x_freq freq;
261   - enum si476x_xmode xmode;
262   -};
263   -
264   -
265   -enum si476x_ctrl_id {
266   - V4L2_CID_SI476X_RSSI_THRESHOLD = (V4L2_CID_USER_SI476X_BASE + 1),
267   - V4L2_CID_SI476X_SNR_THRESHOLD = (V4L2_CID_USER_SI476X_BASE + 2),
268   - V4L2_CID_SI476X_MAX_TUNE_ERROR = (V4L2_CID_USER_SI476X_BASE + 3),
269   - V4L2_CID_SI476X_HARMONICS_COUNT = (V4L2_CID_USER_SI476X_BASE + 4),
270   - V4L2_CID_SI476X_DIVERSITY_MODE = (V4L2_CID_USER_SI476X_BASE + 5),
271   - V4L2_CID_SI476X_INTERCHIP_LINK = (V4L2_CID_USER_SI476X_BASE + 6),
272   -};
273   -
274   -/*
275   - * Platform dependent definition
276   - */
277   -struct si476x_platform_data {
278   - int gpio_reset; /* < 0 if not used */
279   -
280   - struct si476x_power_up_args power_up_parameters;
281   - enum si476x_phase_diversity_mode diversity_mode;
282   -
283   - struct si476x_pinmux pinmux;
284   -};
285   -
286   -/**
287   - * struct si476x_rsq_status - structure containing received signal
288   - * quality
289   - * @multhint: Multipath Detect High.
290   - * true - Indicatedes that the value is below
291   - * FM_RSQ_MULTIPATH_HIGH_THRESHOLD
292   - * false - Indicatedes that the value is above
293   - * FM_RSQ_MULTIPATH_HIGH_THRESHOLD
294   - * @multlint: Multipath Detect Low.
295   - * true - Indicatedes that the value is below
296   - * FM_RSQ_MULTIPATH_LOW_THRESHOLD
297   - * false - Indicatedes that the value is above
298   - * FM_RSQ_MULTIPATH_LOW_THRESHOLD
299   - * @snrhint: SNR Detect High.
300   - * true - Indicatedes that the value is below
301   - * FM_RSQ_SNR_HIGH_THRESHOLD
302   - * false - Indicatedes that the value is above
303   - * FM_RSQ_SNR_HIGH_THRESHOLD
304   - * @snrlint: SNR Detect Low.
305   - * true - Indicatedes that the value is below
306   - * FM_RSQ_SNR_LOW_THRESHOLD
307   - * false - Indicatedes that the value is above
308   - * FM_RSQ_SNR_LOW_THRESHOLD
309   - * @rssihint: RSSI Detect High.
310   - * true - Indicatedes that the value is below
311   - * FM_RSQ_RSSI_HIGH_THRESHOLD
312   - * false - Indicatedes that the value is above
313   - * FM_RSQ_RSSI_HIGH_THRESHOLD
314   - * @rssilint: RSSI Detect Low.
315   - * true - Indicatedes that the value is below
316   - * FM_RSQ_RSSI_LOW_THRESHOLD
317   - * false - Indicatedes that the value is above
318   - * FM_RSQ_RSSI_LOW_THRESHOLD
319   - * @bltf: Band Limit.
320   - * Set if seek command hits the band limit or wrapped to
321   - * the original frequency.
322   - * @snr_ready: SNR measurement in progress.
323   - * @rssiready: RSSI measurement in progress.
324   - * @afcrl: Set if FREQOFF >= MAX_TUNE_ERROR
325   - * @valid: Set if the channel is valid
326   - * rssi < FM_VALID_RSSI_THRESHOLD
327   - * snr < FM_VALID_SNR_THRESHOLD
328   - * tune_error < FM_VALID_MAX_TUNE_ERROR
329   - * @readfreq: Current tuned frequency.
330   - * @freqoff: Signed frequency offset.
331   - * @rssi: Received Signal Strength Indicator(dBuV).
332   - * @snr: RF SNR Indicator(dB).
333   - * @lassi:
334   - * @hassi: Low/High side Adjacent(100 kHz) Channel Strength Indicator
335   - * @mult: Multipath indicator
336   - * @dev: Who knows? But values may vary.
337   - * @readantcap: Antenna tuning capacity value.
338   - * @assi: Adjacent Channel(+/- 200kHz) Strength Indicator
339   - * @usn: Ultrasonic Noise Inticator in -DBFS
340   - */
341   -struct si476x_rsq_status_report {
342   - __u8 multhint, multlint;
343   - __u8 snrhint, snrlint;
344   - __u8 rssihint, rssilint;
345   - __u8 bltf;
346   - __u8 snr_ready;
347   - __u8 rssiready;
348   - __u8 injside;
349   - __u8 afcrl;
350   - __u8 valid;
351   -
352   - __u16 readfreq;
353   - __s8 freqoff;
354   - __s8 rssi;
355   - __s8 snr;
356   - __s8 issi;
357   - __s8 lassi, hassi;
358   - __s8 mult;
359   - __u8 dev;
360   - __u16 readantcap;
361   - __s8 assi;
362   - __s8 usn;
363   -
364   - __u8 pilotdev;
365   - __u8 rdsdev;
366   - __u8 assidev;
367   - __u8 strongdev;
368   - __u16 rdspi;
369   -} __packed;
370   -
371   -/**
372   - * si476x_acf_status_report - ACF report results
373   - *
374   - * @blend_int: If set, indicates that stereo separation has crossed
375   - * below the blend threshold as set by FM_ACF_BLEND_THRESHOLD
376   - * @hblend_int: If set, indicates that HiBlend cutoff frequency is
377   - * lower than threshold as set by FM_ACF_HBLEND_THRESHOLD
378   - * @hicut_int: If set, indicates that HiCut cutoff frequency is lower
379   - * than the threshold set by ACF_
380   -
381   - */
382   -struct si476x_acf_status_report {
383   - __u8 blend_int;
384   - __u8 hblend_int;
385   - __u8 hicut_int;
386   - __u8 chbw_int;
387   - __u8 softmute_int;
388   - __u8 smute;
389   - __u8 smattn;
390   - __u8 chbw;
391   - __u8 hicut;
392   - __u8 hiblend;
393   - __u8 pilot;
394   - __u8 stblend;
395   -} __packed;
396   -
397   -enum si476x_fmagc {
398   - SI476X_FMAGC_10K_OHM = 0,
399   - SI476X_FMAGC_800_OHM = 1,
400   - SI476X_FMAGC_400_OHM = 2,
401   - SI476X_FMAGC_200_OHM = 4,
402   - SI476X_FMAGC_100_OHM = 8,
403   - SI476X_FMAGC_50_OHM = 16,
404   - SI476X_FMAGC_25_OHM = 32,
405   - SI476X_FMAGC_12P5_OHM = 64,
406   - SI476X_FMAGC_6P25_OHM = 128,
407   -};
408   -
409   -struct si476x_agc_status_report {
410   - __u8 mxhi;
411   - __u8 mxlo;
412   - __u8 lnahi;
413   - __u8 lnalo;
414   - __u8 fmagc1;
415   - __u8 fmagc2;
416   - __u8 pgagain;
417   - __u8 fmwblang;
418   -} __packed;
419   -
420   -struct si476x_rds_blockcount_report {
421   - __u16 expected;
422   - __u16 received;
423   - __u16 uncorrectable;
424   -} __packed;
425   -
426   -#endif /* SI476X_H*/