1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * drivers/media/radio/radio-si476x.c -- V4L2 driver for SI476X chips
4 *
5 * Copyright (C) 2012 Innovative Converged Devices(ICD)
6 * Copyright (C) 2013 Andrey Smirnov
7 *
8 * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
9 */
10
11#include <linux/module.h>
12#include <linux/delay.h>
13#include <linux/interrupt.h>
14#include <linux/slab.h>
15#include <linux/atomic.h>
16#include <linux/videodev2.h>
17#include <linux/mutex.h>
18#include <linux/debugfs.h>
19#include <media/v4l2-common.h>
20#include <media/v4l2-ioctl.h>
21#include <media/v4l2-ctrls.h>
22#include <media/v4l2-event.h>
23#include <media/v4l2-device.h>
24
25#include <media/drv-intf/si476x.h>
26#include <linux/mfd/si476x-core.h>
27
28#define FM_FREQ_RANGE_LOW   64000000
29#define FM_FREQ_RANGE_HIGH 108000000
30
31#define AM_FREQ_RANGE_LOW    520000
32#define AM_FREQ_RANGE_HIGH 30000000
33
34#define PWRLINEFLTR (1 << 8)
35
36#define FREQ_MUL (10000000 / 625)
37
38#define SI476X_PHDIV_STATUS_LINK_LOCKED(status) (0x80 & (status))
39
40#define DRIVER_NAME "si476x-radio"
41#define DRIVER_CARD "SI476x AM/FM Receiver"
42
43enum si476x_freq_bands {
44	SI476X_BAND_FM,
45	SI476X_BAND_AM,
46};
47
48static const struct v4l2_frequency_band si476x_bands[] = {
49	[SI476X_BAND_FM] = {
50		.type		= V4L2_TUNER_RADIO,
51		.index		= SI476X_BAND_FM,
52		.capability	= V4L2_TUNER_CAP_LOW
53		| V4L2_TUNER_CAP_STEREO
54		| V4L2_TUNER_CAP_RDS
55		| V4L2_TUNER_CAP_RDS_BLOCK_IO
56		| V4L2_TUNER_CAP_FREQ_BANDS,
57		.rangelow	=  64 * FREQ_MUL,
58		.rangehigh	= 108 * FREQ_MUL,
59		.modulation	= V4L2_BAND_MODULATION_FM,
60	},
61	[SI476X_BAND_AM] = {
62		.type		= V4L2_TUNER_RADIO,
63		.index		= SI476X_BAND_AM,
64		.capability	= V4L2_TUNER_CAP_LOW
65		| V4L2_TUNER_CAP_FREQ_BANDS,
66		.rangelow	= 0.52 * FREQ_MUL,
67		.rangehigh	= 30 * FREQ_MUL,
68		.modulation	= V4L2_BAND_MODULATION_AM,
69	},
70};
71
72static inline bool si476x_radio_freq_is_inside_of_the_band(u32 freq, int band)
73{
74	return freq >= si476x_bands[band].rangelow &&
75		freq <= si476x_bands[band].rangehigh;
76}
77
78static inline bool si476x_radio_range_is_inside_of_the_band(u32 low, u32 high,
79							    int band)
80{
81	return low  >= si476x_bands[band].rangelow &&
82		high <= si476x_bands[band].rangehigh;
83}
84
85static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl);
86static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl);
87
88enum phase_diversity_modes_idx {
89	SI476X_IDX_PHDIV_DISABLED,
90	SI476X_IDX_PHDIV_PRIMARY_COMBINING,
91	SI476X_IDX_PHDIV_PRIMARY_ANTENNA,
92	SI476X_IDX_PHDIV_SECONDARY_ANTENNA,
93	SI476X_IDX_PHDIV_SECONDARY_COMBINING,
94};
95
96static const char * const phase_diversity_modes[] = {
97	[SI476X_IDX_PHDIV_DISABLED]		= "Disabled",
98	[SI476X_IDX_PHDIV_PRIMARY_COMBINING]	= "Primary with Secondary",
99	[SI476X_IDX_PHDIV_PRIMARY_ANTENNA]	= "Primary Antenna",
100	[SI476X_IDX_PHDIV_SECONDARY_ANTENNA]	= "Secondary Antenna",
101	[SI476X_IDX_PHDIV_SECONDARY_COMBINING]	= "Secondary with Primary",
102};
103
104static inline enum phase_diversity_modes_idx
105si476x_phase_diversity_mode_to_idx(enum si476x_phase_diversity_mode mode)
106{
107	switch (mode) {
108	default:
109		fallthrough;
110	case SI476X_PHDIV_DISABLED:
111		return SI476X_IDX_PHDIV_DISABLED;
112	case SI476X_PHDIV_PRIMARY_COMBINING:
113		return SI476X_IDX_PHDIV_PRIMARY_COMBINING;
114	case SI476X_PHDIV_PRIMARY_ANTENNA:
115		return SI476X_IDX_PHDIV_PRIMARY_ANTENNA;
116	case SI476X_PHDIV_SECONDARY_ANTENNA:
117		return SI476X_IDX_PHDIV_SECONDARY_ANTENNA;
118	case SI476X_PHDIV_SECONDARY_COMBINING:
119		return SI476X_IDX_PHDIV_SECONDARY_COMBINING;
120	}
121}
122
123static inline enum si476x_phase_diversity_mode
124si476x_phase_diversity_idx_to_mode(enum phase_diversity_modes_idx idx)
125{
126	static const int idx_to_value[] = {
127		[SI476X_IDX_PHDIV_DISABLED]		= SI476X_PHDIV_DISABLED,
128		[SI476X_IDX_PHDIV_PRIMARY_COMBINING]	= SI476X_PHDIV_PRIMARY_COMBINING,
129		[SI476X_IDX_PHDIV_PRIMARY_ANTENNA]	= SI476X_PHDIV_PRIMARY_ANTENNA,
130		[SI476X_IDX_PHDIV_SECONDARY_ANTENNA]	= SI476X_PHDIV_SECONDARY_ANTENNA,
131		[SI476X_IDX_PHDIV_SECONDARY_COMBINING]	= SI476X_PHDIV_SECONDARY_COMBINING,
132	};
133
134	return idx_to_value[idx];
135}
136
137static const struct v4l2_ctrl_ops si476x_ctrl_ops = {
138	.g_volatile_ctrl	= si476x_radio_g_volatile_ctrl,
139	.s_ctrl			= si476x_radio_s_ctrl,
140};
141
142
143enum si476x_ctrl_idx {
144	SI476X_IDX_RSSI_THRESHOLD,
145	SI476X_IDX_SNR_THRESHOLD,
146	SI476X_IDX_MAX_TUNE_ERROR,
147	SI476X_IDX_HARMONICS_COUNT,
148	SI476X_IDX_DIVERSITY_MODE,
149	SI476X_IDX_INTERCHIP_LINK,
150};
151static struct v4l2_ctrl_config si476x_ctrls[] = {
152
153	/*
154	 * SI476X during its station seeking(or tuning) process uses several
155	 * parameters to detrmine if "the station" is valid:
156	 *
157	 *	- Signal's SNR(in dBuV) must be lower than
158	 *	#V4L2_CID_SI476X_SNR_THRESHOLD
159	 *	- Signal's RSSI(in dBuV) must be greater than
160	 *	#V4L2_CID_SI476X_RSSI_THRESHOLD
161	 *	- Signal's frequency deviation(in units of 2ppm) must not be
162	 *	more than #V4L2_CID_SI476X_MAX_TUNE_ERROR
163	 */
164	[SI476X_IDX_RSSI_THRESHOLD] = {
165		.ops	= &si476x_ctrl_ops,
166		.id	= V4L2_CID_SI476X_RSSI_THRESHOLD,
167		.name	= "Valid RSSI Threshold",
168		.type	= V4L2_CTRL_TYPE_INTEGER,
169		.min	= -128,
170		.max	= 127,
171		.step	= 1,
172	},
173	[SI476X_IDX_SNR_THRESHOLD] = {
174		.ops	= &si476x_ctrl_ops,
175		.id	= V4L2_CID_SI476X_SNR_THRESHOLD,
176		.type	= V4L2_CTRL_TYPE_INTEGER,
177		.name	= "Valid SNR Threshold",
178		.min	= -128,
179		.max	= 127,
180		.step	= 1,
181	},
182	[SI476X_IDX_MAX_TUNE_ERROR] = {
183		.ops	= &si476x_ctrl_ops,
184		.id	= V4L2_CID_SI476X_MAX_TUNE_ERROR,
185		.type	= V4L2_CTRL_TYPE_INTEGER,
186		.name	= "Max Tune Errors",
187		.min	= 0,
188		.max	= 126 * 2,
189		.step	= 2,
190	},
191
192	/*
193	 * #V4L2_CID_SI476X_HARMONICS_COUNT -- number of harmonics
194	 * built-in power-line noise supression filter is to reject
195	 * during AM-mode operation.
196	 */
197	[SI476X_IDX_HARMONICS_COUNT] = {
198		.ops	= &si476x_ctrl_ops,
199		.id	= V4L2_CID_SI476X_HARMONICS_COUNT,
200		.type	= V4L2_CTRL_TYPE_INTEGER,
201
202		.name	= "Count of Harmonics to Reject",
203		.min	= 0,
204		.max	= 20,
205		.step	= 1,
206	},
207
208	/*
209	 * #V4L2_CID_SI476X_DIVERSITY_MODE -- configuration which
210	 * two tuners working in diversity mode are to work in.
211	 *
212	 *  - #SI476X_IDX_PHDIV_DISABLED diversity mode disabled
213	 *  - #SI476X_IDX_PHDIV_PRIMARY_COMBINING diversity mode is
214	 *  on, primary tuner's antenna is the main one.
215	 *  - #SI476X_IDX_PHDIV_PRIMARY_ANTENNA diversity mode is
216	 *  off, primary tuner's antenna is the main one.
217	 *  - #SI476X_IDX_PHDIV_SECONDARY_ANTENNA diversity mode is
218	 *  off, secondary tuner's antenna is the main one.
219	 *  - #SI476X_IDX_PHDIV_SECONDARY_COMBINING diversity mode is
220	 *  on, secondary tuner's antenna is the main one.
221	 */
222	[SI476X_IDX_DIVERSITY_MODE] = {
223		.ops	= &si476x_ctrl_ops,
224		.id	= V4L2_CID_SI476X_DIVERSITY_MODE,
225		.type	= V4L2_CTRL_TYPE_MENU,
226		.name	= "Phase Diversity Mode",
227		.qmenu	= phase_diversity_modes,
228		.min	= 0,
229		.max	= ARRAY_SIZE(phase_diversity_modes) - 1,
230	},
231
232	/*
233	 * #V4L2_CID_SI476X_INTERCHIP_LINK -- inter-chip link in
234	 * diversity mode indicator. Allows user to determine if two
235	 * chips working in diversity mode have established a link
236	 * between each other and if the system as a whole uses
237	 * signals from both antennas to receive FM radio.
238	 */
239	[SI476X_IDX_INTERCHIP_LINK] = {
240		.ops	= &si476x_ctrl_ops,
241		.id	= V4L2_CID_SI476X_INTERCHIP_LINK,
242		.type	= V4L2_CTRL_TYPE_BOOLEAN,
243		.flags  = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE,
244		.name	= "Inter-Chip Link",
245		.min	= 0,
246		.max	= 1,
247		.step	= 1,
248	},
249};
250
251struct si476x_radio;
252
253/**
254 * struct si476x_radio_ops - vtable of tuner functions
255 *
256 * This table holds pointers to functions implementing particular
257 * operations depending on the mode in which the tuner chip was
258 * configured to start in. If the function is not supported
259 * corresponding element is set to #NULL.
260 *
261 * @tune_freq: Tune chip to a specific frequency
262 * @seek_start: Star station seeking
263 * @rsq_status: Get Received Signal Quality(RSQ) status
264 * @rds_blckcnt: Get received RDS blocks count
265 * @phase_diversity: Change phase diversity mode of the tuner
266 * @phase_div_status: Get phase diversity mode status
267 * @acf_status: Get the status of Automatically Controlled
268 * Features(ACF)
269 * @agc_status: Get Automatic Gain Control(AGC) status
270 */
271struct si476x_radio_ops {
272	int (*tune_freq)(struct si476x_core *, struct si476x_tune_freq_args *);
273	int (*seek_start)(struct si476x_core *, bool, bool);
274	int (*rsq_status)(struct si476x_core *, struct si476x_rsq_status_args *,
275			  struct si476x_rsq_status_report *);
276	int (*rds_blckcnt)(struct si476x_core *, bool,
277			   struct si476x_rds_blockcount_report *);
278
279	int (*phase_diversity)(struct si476x_core *,
280			       enum si476x_phase_diversity_mode);
281	int (*phase_div_status)(struct si476x_core *);
282	int (*acf_status)(struct si476x_core *,
283			  struct si476x_acf_status_report *);
284	int (*agc_status)(struct si476x_core *,
285			  struct si476x_agc_status_report *);
286};
287
288/**
289 * struct si476x_radio - radio device
290 *
291 * @v4l2dev: Pointer to V4L2 device created by V4L2 subsystem
292 * @videodev: Pointer to video device created by V4L2 subsystem
293 * @ctrl_handler: V4L2 controls handler
294 * @core: Pointer to underlying core device
295 * @ops: Vtable of functions. See struct si476x_radio_ops for details
296 * @debugfs: pointer to &strucd dentry for debugfs
297 * @audmode: audio mode, as defined for the rxsubchans field
298 *	     at videodev2.h
299 *
300 * core structure is the radio device is being used
301 */
302struct si476x_radio {
303	struct v4l2_device v4l2dev;
304	struct video_device videodev;
305	struct v4l2_ctrl_handler ctrl_handler;
306
307	struct si476x_core  *core;
308	/* This field should not be accesses unless core lock is held */
309	const struct si476x_radio_ops *ops;
310
311	struct dentry	*debugfs;
312	u32 audmode;
313};
314
315static inline struct si476x_radio *
316v4l2_dev_to_radio(struct v4l2_device *d)
317{
318	return container_of(d, struct si476x_radio, v4l2dev);
319}
320
321static inline struct si476x_radio *
322v4l2_ctrl_handler_to_radio(struct v4l2_ctrl_handler *d)
323{
324	return container_of(d, struct si476x_radio, ctrl_handler);
325}
326
327/*
328 * si476x_vidioc_querycap - query device capabilities
329 */
330static int si476x_radio_querycap(struct file *file, void *priv,
331				 struct v4l2_capability *capability)
332{
333	struct si476x_radio *radio = video_drvdata(file);
334
335	strscpy(capability->driver, radio->v4l2dev.name,
336		sizeof(capability->driver));
337	strscpy(capability->card,   DRIVER_CARD, sizeof(capability->card));
338	snprintf(capability->bus_info, sizeof(capability->bus_info),
339		 "platform:%s", radio->v4l2dev.name);
340	return 0;
341}
342
343static int si476x_radio_enum_freq_bands(struct file *file, void *priv,
344					struct v4l2_frequency_band *band)
345{
346	int err;
347	struct si476x_radio *radio = video_drvdata(file);
348
349	if (band->tuner != 0)
350		return -EINVAL;
351
352	switch (radio->core->chip_id) {
353		/* AM/FM tuners -- all bands are supported */
354	case SI476X_CHIP_SI4761:
355	case SI476X_CHIP_SI4764:
356		if (band->index < ARRAY_SIZE(si476x_bands)) {
357			*band = si476x_bands[band->index];
358			err = 0;
359		} else {
360			err = -EINVAL;
361		}
362		break;
363		/* FM companion tuner chips -- only FM bands are
364		 * supported */
365	case SI476X_CHIP_SI4768:
366		if (band->index == SI476X_BAND_FM) {
367			*band = si476x_bands[band->index];
368			err = 0;
369		} else {
370			err = -EINVAL;
371		}
372		break;
373	default:
374		err = -EINVAL;
375	}
376
377	return err;
378}
379
380static int si476x_radio_g_tuner(struct file *file, void *priv,
381				struct v4l2_tuner *tuner)
382{
383	int err;
384	struct si476x_rsq_status_report report;
385	struct si476x_radio *radio = video_drvdata(file);
386
387	struct si476x_rsq_status_args args = {
388		.primary	= false,
389		.rsqack		= false,
390		.attune		= false,
391		.cancel		= false,
392		.stcack		= false,
393	};
394
395	if (tuner->index != 0)
396		return -EINVAL;
397
398	tuner->type       = V4L2_TUNER_RADIO;
399	tuner->capability = V4L2_TUNER_CAP_LOW /* Measure frequencies
400						 * in multiples of
401						 * 62.5 Hz */
402		| V4L2_TUNER_CAP_STEREO
403		| V4L2_TUNER_CAP_HWSEEK_BOUNDED
404		| V4L2_TUNER_CAP_HWSEEK_WRAP
405		| V4L2_TUNER_CAP_HWSEEK_PROG_LIM;
406
407	si476x_core_lock(radio->core);
408
409	if (si476x_core_is_a_secondary_tuner(radio->core)) {
410		strscpy(tuner->name, "FM (secondary)", sizeof(tuner->name));
411		tuner->rxsubchans = 0;
412		tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow;
413	} else if (si476x_core_has_am(radio->core)) {
414		if (si476x_core_is_a_primary_tuner(radio->core))
415			strscpy(tuner->name, "AM/FM (primary)",
416				sizeof(tuner->name));
417		else
418			strscpy(tuner->name, "AM/FM", sizeof(tuner->name));
419
420		tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO
421			| V4L2_TUNER_SUB_RDS;
422		tuner->capability |= V4L2_TUNER_CAP_RDS
423			| V4L2_TUNER_CAP_RDS_BLOCK_IO
424			| V4L2_TUNER_CAP_FREQ_BANDS;
425
426		tuner->rangelow = si476x_bands[SI476X_BAND_AM].rangelow;
427	} else {
428		strscpy(tuner->name, "FM", sizeof(tuner->name));
429		tuner->rxsubchans = V4L2_TUNER_SUB_RDS;
430		tuner->capability |= V4L2_TUNER_CAP_RDS
431			| V4L2_TUNER_CAP_RDS_BLOCK_IO
432			| V4L2_TUNER_CAP_FREQ_BANDS;
433		tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow;
434	}
435
436	tuner->audmode = radio->audmode;
437
438	tuner->afc = 1;
439	tuner->rangehigh = si476x_bands[SI476X_BAND_FM].rangehigh;
440
441	err = radio->ops->rsq_status(radio->core,
442				     &args, &report);
443	if (err < 0) {
444		tuner->signal = 0;
445	} else {
446		/*
447		 * tuner->signal value range: 0x0000 .. 0xFFFF,
448		 * report.rssi: -128 .. 127
449		 */
450		tuner->signal = (report.rssi + 128) * 257;
451	}
452	si476x_core_unlock(radio->core);
453
454	return err;
455}
456
457static int si476x_radio_s_tuner(struct file *file, void *priv,
458				const struct v4l2_tuner *tuner)
459{
460	struct si476x_radio *radio = video_drvdata(file);
461
462	if (tuner->index != 0)
463		return -EINVAL;
464
465	if (tuner->audmode == V4L2_TUNER_MODE_MONO ||
466	    tuner->audmode == V4L2_TUNER_MODE_STEREO)
467		radio->audmode = tuner->audmode;
468	else
469		radio->audmode = V4L2_TUNER_MODE_STEREO;
470
471	return 0;
472}
473
474static int si476x_radio_init_vtable(struct si476x_radio *radio,
475				    enum si476x_func func)
476{
477	static const struct si476x_radio_ops fm_ops = {
478		.tune_freq		= si476x_core_cmd_fm_tune_freq,
479		.seek_start		= si476x_core_cmd_fm_seek_start,
480		.rsq_status		= si476x_core_cmd_fm_rsq_status,
481		.rds_blckcnt		= si476x_core_cmd_fm_rds_blockcount,
482		.phase_diversity	= si476x_core_cmd_fm_phase_diversity,
483		.phase_div_status	= si476x_core_cmd_fm_phase_div_status,
484		.acf_status		= si476x_core_cmd_fm_acf_status,
485		.agc_status		= si476x_core_cmd_agc_status,
486	};
487
488	static const struct si476x_radio_ops am_ops = {
489		.tune_freq		= si476x_core_cmd_am_tune_freq,
490		.seek_start		= si476x_core_cmd_am_seek_start,
491		.rsq_status		= si476x_core_cmd_am_rsq_status,
492		.rds_blckcnt		= NULL,
493		.phase_diversity	= NULL,
494		.phase_div_status	= NULL,
495		.acf_status		= si476x_core_cmd_am_acf_status,
496		.agc_status		= NULL,
497	};
498
499	switch (func) {
500	case SI476X_FUNC_FM_RECEIVER:
501		radio->ops = &fm_ops;
502		return 0;
503
504	case SI476X_FUNC_AM_RECEIVER:
505		radio->ops = &am_ops;
506		return 0;
507	default:
508		WARN(1, "Unexpected tuner function value\n");
509		return -EINVAL;
510	}
511}
512
513static int si476x_radio_pretune(struct si476x_radio *radio,
514				enum si476x_func func)
515{
516	int retval;
517
518	struct si476x_tune_freq_args args = {
519		.zifsr		= false,
520		.hd		= false,
521		.injside	= SI476X_INJSIDE_AUTO,
522		.tunemode	= SI476X_TM_VALIDATED_NORMAL_TUNE,
523		.smoothmetrics	= SI476X_SM_INITIALIZE_AUDIO,
524		.antcap		= 0,
525	};
526
527	switch (func) {
528	case SI476X_FUNC_FM_RECEIVER:
529		args.freq = v4l2_to_si476x(radio->core,
530					   92 * FREQ_MUL);
531		retval = radio->ops->tune_freq(radio->core, &args);
532		break;
533	case SI476X_FUNC_AM_RECEIVER:
534		args.freq = v4l2_to_si476x(radio->core,
535					   0.6 * FREQ_MUL);
536		retval = radio->ops->tune_freq(radio->core, &args);
537		break;
538	default:
539		WARN(1, "Unexpected tuner function value\n");
540		retval = -EINVAL;
541	}
542
543	return retval;
544}
545static int si476x_radio_do_post_powerup_init(struct si476x_radio *radio,
546					     enum si476x_func func)
547{
548	int err;
549
550	/* regcache_mark_dirty(radio->core->regmap); */
551	err = regcache_sync_region(radio->core->regmap,
552				   SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE,
553				   SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT);
554	if (err < 0)
555		return err;
556
557	err = regcache_sync_region(radio->core->regmap,
558				   SI476X_PROP_AUDIO_DEEMPHASIS,
559				   SI476X_PROP_AUDIO_PWR_LINE_FILTER);
560	if (err < 0)
561		return err;
562
563	err = regcache_sync_region(radio->core->regmap,
564				   SI476X_PROP_INT_CTL_ENABLE,
565				   SI476X_PROP_INT_CTL_ENABLE);
566	if (err < 0)
567		return err;
568
569	/*
570	 * Is there any point in restoring SNR and the like
571	 * when switching between AM/FM?
572	 */
573	err = regcache_sync_region(radio->core->regmap,
574				   SI476X_PROP_VALID_MAX_TUNE_ERROR,
575				   SI476X_PROP_VALID_MAX_TUNE_ERROR);
576	if (err < 0)
577		return err;
578
579	err = regcache_sync_region(radio->core->regmap,
580				   SI476X_PROP_VALID_SNR_THRESHOLD,
581				   SI476X_PROP_VALID_RSSI_THRESHOLD);
582	if (err < 0)
583		return err;
584
585	if (func == SI476X_FUNC_FM_RECEIVER) {
586		if (si476x_core_has_diversity(radio->core)) {
587			err = si476x_core_cmd_fm_phase_diversity(radio->core,
588								 radio->core->diversity_mode);
589			if (err < 0)
590				return err;
591		}
592
593		err = regcache_sync_region(radio->core->regmap,
594					   SI476X_PROP_FM_RDS_INTERRUPT_SOURCE,
595					   SI476X_PROP_FM_RDS_CONFIG);
596		if (err < 0)
597			return err;
598	}
599
600	return si476x_radio_init_vtable(radio, func);
601
602}
603
604static int si476x_radio_change_func(struct si476x_radio *radio,
605				    enum si476x_func func)
606{
607	int err;
608	bool soft;
609	/*
610	 * Since power/up down is a very time consuming operation,
611	 * try to avoid doing it if the requested mode matches the one
612	 * the tuner is in
613	 */
614	if (func == radio->core->power_up_parameters.func)
615		return 0;
616
617	soft = true;
618	err = si476x_core_stop(radio->core, soft);
619	if (err < 0) {
620		/*
621		 * OK, if the chip does not want to play nice let's
622		 * try to reset it in more brutal way
623		 */
624		soft = false;
625		err = si476x_core_stop(radio->core, soft);
626		if (err < 0)
627			return err;
628	}
629	/*
630	  Set the desired radio tuner function
631	 */
632	radio->core->power_up_parameters.func = func;
633
634	err = si476x_core_start(radio->core, soft);
635	if (err < 0)
636		return err;
637
638	/*
639	 * No need to do the rest of manipulations for the bootlader
640	 * mode
641	 */
642	if (func != SI476X_FUNC_FM_RECEIVER &&
643	    func != SI476X_FUNC_AM_RECEIVER)
644		return err;
645
646	return si476x_radio_do_post_powerup_init(radio, func);
647}
648
649static int si476x_radio_g_frequency(struct file *file, void *priv,
650			      struct v4l2_frequency *f)
651{
652	int err;
653	struct si476x_radio *radio = video_drvdata(file);
654
655	if (f->tuner != 0 ||
656	    f->type  != V4L2_TUNER_RADIO)
657		return -EINVAL;
658
659	si476x_core_lock(radio->core);
660
661	if (radio->ops->rsq_status) {
662		struct si476x_rsq_status_report report;
663		struct si476x_rsq_status_args   args = {
664			.primary	= false,
665			.rsqack		= false,
666			.attune		= true,
667			.cancel		= false,
668			.stcack		= false,
669		};
670
671		err = radio->ops->rsq_status(radio->core, &args, &report);
672		if (!err)
673			f->frequency = si476x_to_v4l2(radio->core,
674						      report.readfreq);
675	} else {
676		err = -EINVAL;
677	}
678
679	si476x_core_unlock(radio->core);
680
681	return err;
682}
683
684static int si476x_radio_s_frequency(struct file *file, void *priv,
685				    const struct v4l2_frequency *f)
686{
687	int err;
688	u32 freq = f->frequency;
689	struct si476x_tune_freq_args args;
690	struct si476x_radio *radio = video_drvdata(file);
691
692	const u32 midrange = (si476x_bands[SI476X_BAND_AM].rangehigh +
693			      si476x_bands[SI476X_BAND_FM].rangelow) / 2;
694	const int band = (freq > midrange) ?
695		SI476X_BAND_FM : SI476X_BAND_AM;
696	const enum si476x_func func = (band == SI476X_BAND_AM) ?
697		SI476X_FUNC_AM_RECEIVER : SI476X_FUNC_FM_RECEIVER;
698
699	if (f->tuner != 0 ||
700	    f->type  != V4L2_TUNER_RADIO)
701		return -EINVAL;
702
703	si476x_core_lock(radio->core);
704
705	freq = clamp(freq,
706		     si476x_bands[band].rangelow,
707		     si476x_bands[band].rangehigh);
708
709	if (si476x_radio_freq_is_inside_of_the_band(freq,
710						    SI476X_BAND_AM) &&
711	    (!si476x_core_has_am(radio->core) ||
712	     si476x_core_is_a_secondary_tuner(radio->core))) {
713		err = -EINVAL;
714		goto unlock;
715	}
716
717	err = si476x_radio_change_func(radio, func);
718	if (err < 0)
719		goto unlock;
720
721	args.zifsr		= false;
722	args.hd			= false;
723	args.injside		= SI476X_INJSIDE_AUTO;
724	args.freq		= v4l2_to_si476x(radio->core, freq);
725	args.tunemode		= SI476X_TM_VALIDATED_NORMAL_TUNE;
726	args.smoothmetrics	= SI476X_SM_INITIALIZE_AUDIO;
727	args.antcap		= 0;
728
729	err = radio->ops->tune_freq(radio->core, &args);
730
731unlock:
732	si476x_core_unlock(radio->core);
733	return err;
734}
735
736static int si476x_radio_s_hw_freq_seek(struct file *file, void *priv,
737				       const struct v4l2_hw_freq_seek *seek)
738{
739	int err;
740	enum si476x_func func;
741	u32 rangelow = seek->rangelow, rangehigh = seek->rangehigh;
742	struct si476x_radio *radio = video_drvdata(file);
743
744	if (file->f_flags & O_NONBLOCK)
745		return -EAGAIN;
746
747	if (seek->tuner != 0 ||
748	    seek->type  != V4L2_TUNER_RADIO)
749		return -EINVAL;
750
751	si476x_core_lock(radio->core);
752
753	if (!rangelow) {
754		err = regmap_read(radio->core->regmap,
755				  SI476X_PROP_SEEK_BAND_BOTTOM,
756				  &rangelow);
757		if (err)
758			goto unlock;
759		rangelow = si476x_to_v4l2(radio->core, rangelow);
760	}
761	if (!rangehigh) {
762		err = regmap_read(radio->core->regmap,
763				  SI476X_PROP_SEEK_BAND_TOP,
764				  &rangehigh);
765		if (err)
766			goto unlock;
767		rangehigh = si476x_to_v4l2(radio->core, rangehigh);
768	}
769
770	if (rangelow > rangehigh) {
771		err = -EINVAL;
772		goto unlock;
773	}
774
775	if (si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh,
776						     SI476X_BAND_FM)) {
777		func = SI476X_FUNC_FM_RECEIVER;
778
779	} else if (si476x_core_has_am(radio->core) &&
780		   si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh,
781							    SI476X_BAND_AM)) {
782		func = SI476X_FUNC_AM_RECEIVER;
783	} else {
784		err = -EINVAL;
785		goto unlock;
786	}
787
788	err = si476x_radio_change_func(radio, func);
789	if (err < 0)
790		goto unlock;
791
792	if (seek->rangehigh) {
793		err = regmap_write(radio->core->regmap,
794				   SI476X_PROP_SEEK_BAND_TOP,
795				   v4l2_to_si476x(radio->core,
796						  seek->rangehigh));
797		if (err)
798			goto unlock;
799	}
800	if (seek->rangelow) {
801		err = regmap_write(radio->core->regmap,
802				   SI476X_PROP_SEEK_BAND_BOTTOM,
803				   v4l2_to_si476x(radio->core,
804						  seek->rangelow));
805		if (err)
806			goto unlock;
807	}
808	if (seek->spacing) {
809		err = regmap_write(radio->core->regmap,
810				     SI476X_PROP_SEEK_FREQUENCY_SPACING,
811				     v4l2_to_si476x(radio->core,
812						    seek->spacing));
813		if (err)
814			goto unlock;
815	}
816
817	err = radio->ops->seek_start(radio->core,
818				     seek->seek_upward,
819				     seek->wrap_around);
820unlock:
821	si476x_core_unlock(radio->core);
822
823
824
825	return err;
826}
827
828static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
829{
830	int retval;
831	struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler);
832
833	si476x_core_lock(radio->core);
834
835	switch (ctrl->id) {
836	case V4L2_CID_SI476X_INTERCHIP_LINK:
837		if (si476x_core_has_diversity(radio->core)) {
838			if (radio->ops->phase_diversity) {
839				retval = radio->ops->phase_div_status(radio->core);
840				if (retval < 0)
841					break;
842
843				ctrl->val = !!SI476X_PHDIV_STATUS_LINK_LOCKED(retval);
844				retval = 0;
845				break;
846			} else {
847				retval = -ENOTTY;
848				break;
849			}
850		}
851		retval = -EINVAL;
852		break;
853	default:
854		retval = -EINVAL;
855		break;
856	}
857	si476x_core_unlock(radio->core);
858	return retval;
859
860}
861
862static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl)
863{
864	int retval;
865	enum si476x_phase_diversity_mode mode;
866	struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler);
867
868	si476x_core_lock(radio->core);
869
870	switch (ctrl->id) {
871	case V4L2_CID_SI476X_HARMONICS_COUNT:
872		retval = regmap_update_bits(radio->core->regmap,
873					    SI476X_PROP_AUDIO_PWR_LINE_FILTER,
874					    SI476X_PROP_PWR_HARMONICS_MASK,
875					    ctrl->val);
876		break;
877	case V4L2_CID_POWER_LINE_FREQUENCY:
878		switch (ctrl->val) {
879		case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
880			retval = regmap_update_bits(radio->core->regmap,
881						    SI476X_PROP_AUDIO_PWR_LINE_FILTER,
882						    SI476X_PROP_PWR_ENABLE_MASK,
883						    0);
884			break;
885		case V4L2_CID_POWER_LINE_FREQUENCY_50HZ:
886			retval = regmap_update_bits(radio->core->regmap,
887						    SI476X_PROP_AUDIO_PWR_LINE_FILTER,
888						    SI476X_PROP_PWR_GRID_MASK,
889						    SI476X_PROP_PWR_GRID_50HZ);
890			break;
891		case V4L2_CID_POWER_LINE_FREQUENCY_60HZ:
892			retval = regmap_update_bits(radio->core->regmap,
893						    SI476X_PROP_AUDIO_PWR_LINE_FILTER,
894						    SI476X_PROP_PWR_GRID_MASK,
895						    SI476X_PROP_PWR_GRID_60HZ);
896			break;
897		default:
898			retval = -EINVAL;
899			break;
900		}
901		break;
902	case V4L2_CID_SI476X_RSSI_THRESHOLD:
903		retval = regmap_write(radio->core->regmap,
904				      SI476X_PROP_VALID_RSSI_THRESHOLD,
905				      ctrl->val);
906		break;
907	case V4L2_CID_SI476X_SNR_THRESHOLD:
908		retval = regmap_write(radio->core->regmap,
909				      SI476X_PROP_VALID_SNR_THRESHOLD,
910				      ctrl->val);
911		break;
912	case V4L2_CID_SI476X_MAX_TUNE_ERROR:
913		retval = regmap_write(radio->core->regmap,
914				      SI476X_PROP_VALID_MAX_TUNE_ERROR,
915				      ctrl->val);
916		break;
917	case V4L2_CID_RDS_RECEPTION:
918		/*
919		 * It looks like RDS related properties are
920		 * inaccesable when tuner is in AM mode, so cache the
921		 * changes
922		 */
923		if (si476x_core_is_in_am_receiver_mode(radio->core))
924			regcache_cache_only(radio->core->regmap, true);
925
926		if (ctrl->val) {
927			retval = regmap_write(radio->core->regmap,
928					      SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT,
929					      radio->core->rds_fifo_depth);
930			if (retval < 0)
931				break;
932
933			if (radio->core->client->irq) {
934				retval = regmap_write(radio->core->regmap,
935						      SI476X_PROP_FM_RDS_INTERRUPT_SOURCE,
936						      SI476X_RDSRECV);
937				if (retval < 0)
938					break;
939			}
940
941			/* Drain RDS FIFO before enabling RDS processing */
942			retval = si476x_core_cmd_fm_rds_status(radio->core,
943							       false,
944							       true,
945							       true,
946							       NULL);
947			if (retval < 0)
948				break;
949
950			retval = regmap_update_bits(radio->core->regmap,
951						    SI476X_PROP_FM_RDS_CONFIG,
952						    SI476X_PROP_RDSEN_MASK,
953						    SI476X_PROP_RDSEN);
954		} else {
955			retval = regmap_update_bits(radio->core->regmap,
956						    SI476X_PROP_FM_RDS_CONFIG,
957						    SI476X_PROP_RDSEN_MASK,
958						    !SI476X_PROP_RDSEN);
959		}
960
961		if (si476x_core_is_in_am_receiver_mode(radio->core))
962			regcache_cache_only(radio->core->regmap, false);
963		break;
964	case V4L2_CID_TUNE_DEEMPHASIS:
965		retval = regmap_write(radio->core->regmap,
966				      SI476X_PROP_AUDIO_DEEMPHASIS,
967				      ctrl->val);
968		break;
969
970	case V4L2_CID_SI476X_DIVERSITY_MODE:
971		mode = si476x_phase_diversity_idx_to_mode(ctrl->val);
972
973		if (mode == radio->core->diversity_mode) {
974			retval = 0;
975			break;
976		}
977
978		if (si476x_core_is_in_am_receiver_mode(radio->core)) {
979			/*
980			 * Diversity cannot be configured while tuner
981			 * is in AM mode so save the changes and carry on.
982			 */
983			radio->core->diversity_mode = mode;
984			retval = 0;
985		} else {
986			retval = radio->ops->phase_diversity(radio->core, mode);
987			if (!retval)
988				radio->core->diversity_mode = mode;
989		}
990		break;
991
992	default:
993		retval = -EINVAL;
994		break;
995	}
996
997	si476x_core_unlock(radio->core);
998
999	return retval;
1000}
1001
1002#ifdef CONFIG_VIDEO_ADV_DEBUG
1003static int si476x_radio_g_register(struct file *file, void *fh,
1004				   struct v4l2_dbg_register *reg)
1005{
1006	int err;
1007	unsigned int value;
1008	struct si476x_radio *radio = video_drvdata(file);
1009
1010	si476x_core_lock(radio->core);
1011	reg->size = 2;
1012	err = regmap_read(radio->core->regmap,
1013			  (unsigned int)reg->reg, &value);
1014	reg->val = value;
1015	si476x_core_unlock(radio->core);
1016
1017	return err;
1018}
1019static int si476x_radio_s_register(struct file *file, void *fh,
1020				   const struct v4l2_dbg_register *reg)
1021{
1022
1023	int err;
1024	struct si476x_radio *radio = video_drvdata(file);
1025
1026	si476x_core_lock(radio->core);
1027	err = regmap_write(radio->core->regmap,
1028			   (unsigned int)reg->reg,
1029			   (unsigned int)reg->val);
1030	si476x_core_unlock(radio->core);
1031
1032	return err;
1033}
1034#endif
1035
1036static int si476x_radio_fops_open(struct file *file)
1037{
1038	struct si476x_radio *radio = video_drvdata(file);
1039	int err;
1040
1041	err = v4l2_fh_open(file);
1042	if (err)
1043		return err;
1044
1045	if (v4l2_fh_is_singular_file(file)) {
1046		si476x_core_lock(radio->core);
1047		err = si476x_core_set_power_state(radio->core,
1048						  SI476X_POWER_UP_FULL);
1049		if (err < 0)
1050			goto done;
1051
1052		err = si476x_radio_do_post_powerup_init(radio,
1053							radio->core->power_up_parameters.func);
1054		if (err < 0)
1055			goto power_down;
1056
1057		err = si476x_radio_pretune(radio,
1058					   radio->core->power_up_parameters.func);
1059		if (err < 0)
1060			goto power_down;
1061
1062		si476x_core_unlock(radio->core);
1063		/*Must be done after si476x_core_unlock to prevent a deadlock*/
1064		v4l2_ctrl_handler_setup(&radio->ctrl_handler);
1065	}
1066
1067	return err;
1068
1069power_down:
1070	si476x_core_set_power_state(radio->core,
1071				    SI476X_POWER_DOWN);
1072done:
1073	si476x_core_unlock(radio->core);
1074	v4l2_fh_release(file);
1075
1076	return err;
1077}
1078
1079static int si476x_radio_fops_release(struct file *file)
1080{
1081	int err;
1082	struct si476x_radio *radio = video_drvdata(file);
1083
1084	if (v4l2_fh_is_singular_file(file) &&
1085	    atomic_read(&radio->core->is_alive))
1086		si476x_core_set_power_state(radio->core,
1087					    SI476X_POWER_DOWN);
1088
1089	err = v4l2_fh_release(file);
1090
1091	return err;
1092}
1093
1094static ssize_t si476x_radio_fops_read(struct file *file, char __user *buf,
1095				      size_t count, loff_t *ppos)
1096{
1097	ssize_t      rval;
1098	size_t       fifo_len;
1099	unsigned int copied;
1100
1101	struct si476x_radio *radio = video_drvdata(file);
1102
1103	/* block if no new data available */
1104	if (kfifo_is_empty(&radio->core->rds_fifo)) {
1105		if (file->f_flags & O_NONBLOCK)
1106			return -EWOULDBLOCK;
1107
1108		rval = wait_event_interruptible(radio->core->rds_read_queue,
1109						(!kfifo_is_empty(&radio->core->rds_fifo) ||
1110						 !atomic_read(&radio->core->is_alive)));
1111		if (rval < 0)
1112			return -EINTR;
1113
1114		if (!atomic_read(&radio->core->is_alive))
1115			return -ENODEV;
1116	}
1117
1118	fifo_len = kfifo_len(&radio->core->rds_fifo);
1119
1120	if (kfifo_to_user(&radio->core->rds_fifo, buf,
1121			  min(fifo_len, count),
1122			  &copied) != 0) {
1123		dev_warn(&radio->videodev.dev,
1124			 "Error during FIFO to userspace copy\n");
1125		rval = -EIO;
1126	} else {
1127		rval = (ssize_t)copied;
1128	}
1129
1130	return rval;
1131}
1132
1133static __poll_t si476x_radio_fops_poll(struct file *file,
1134				struct poll_table_struct *pts)
1135{
1136	struct si476x_radio *radio = video_drvdata(file);
1137	__poll_t req_events = poll_requested_events(pts);
1138	__poll_t err = v4l2_ctrl_poll(file, pts);
1139
1140	if (req_events & (EPOLLIN | EPOLLRDNORM)) {
1141		if (atomic_read(&radio->core->is_alive))
1142			poll_wait(file, &radio->core->rds_read_queue, pts);
1143
1144		if (!atomic_read(&radio->core->is_alive))
1145			err = EPOLLHUP;
1146
1147		if (!kfifo_is_empty(&radio->core->rds_fifo))
1148			err = EPOLLIN | EPOLLRDNORM;
1149	}
1150
1151	return err;
1152}
1153
1154static const struct v4l2_file_operations si476x_fops = {
1155	.owner			= THIS_MODULE,
1156	.read			= si476x_radio_fops_read,
1157	.poll			= si476x_radio_fops_poll,
1158	.unlocked_ioctl		= video_ioctl2,
1159	.open			= si476x_radio_fops_open,
1160	.release		= si476x_radio_fops_release,
1161};
1162
1163
1164static const struct v4l2_ioctl_ops si4761_ioctl_ops = {
1165	.vidioc_querycap		= si476x_radio_querycap,
1166	.vidioc_g_tuner			= si476x_radio_g_tuner,
1167	.vidioc_s_tuner			= si476x_radio_s_tuner,
1168
1169	.vidioc_g_frequency		= si476x_radio_g_frequency,
1170	.vidioc_s_frequency		= si476x_radio_s_frequency,
1171	.vidioc_s_hw_freq_seek		= si476x_radio_s_hw_freq_seek,
1172	.vidioc_enum_freq_bands		= si476x_radio_enum_freq_bands,
1173
1174	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
1175	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
1176
1177#ifdef CONFIG_VIDEO_ADV_DEBUG
1178	.vidioc_g_register		= si476x_radio_g_register,
1179	.vidioc_s_register		= si476x_radio_s_register,
1180#endif
1181};
1182
1183
1184static const struct video_device si476x_viddev_template = {
1185	.fops			= &si476x_fops,
1186	.name			= DRIVER_NAME,
1187	.release		= video_device_release_empty,
1188};
1189
1190
1191
1192static ssize_t si476x_radio_read_acf_blob(struct file *file,
1193					  char __user *user_buf,
1194					  size_t count, loff_t *ppos)
1195{
1196	int err;
1197	struct si476x_radio *radio = file->private_data;
1198	struct si476x_acf_status_report report;
1199
1200	si476x_core_lock(radio->core);
1201	if (radio->ops->acf_status)
1202		err = radio->ops->acf_status(radio->core, &report);
1203	else
1204		err = -ENOENT;
1205	si476x_core_unlock(radio->core);
1206
1207	if (err < 0)
1208		return err;
1209
1210	return simple_read_from_buffer(user_buf, count, ppos, &report,
1211				       sizeof(report));
1212}
1213
1214static const struct file_operations radio_acf_fops = {
1215	.open	= simple_open,
1216	.llseek = default_llseek,
1217	.read	= si476x_radio_read_acf_blob,
1218};
1219
1220static ssize_t si476x_radio_read_rds_blckcnt_blob(struct file *file,
1221						  char __user *user_buf,
1222						  size_t count, loff_t *ppos)
1223{
1224	int err;
1225	struct si476x_radio *radio = file->private_data;
1226	struct si476x_rds_blockcount_report report;
1227
1228	si476x_core_lock(radio->core);
1229	if (radio->ops->rds_blckcnt)
1230		err = radio->ops->rds_blckcnt(radio->core, true,
1231					       &report);
1232	else
1233		err = -ENOENT;
1234	si476x_core_unlock(radio->core);
1235
1236	if (err < 0)
1237		return err;
1238
1239	return simple_read_from_buffer(user_buf, count, ppos, &report,
1240				       sizeof(report));
1241}
1242
1243static const struct file_operations radio_rds_blckcnt_fops = {
1244	.open	= simple_open,
1245	.llseek = default_llseek,
1246	.read	= si476x_radio_read_rds_blckcnt_blob,
1247};
1248
1249static ssize_t si476x_radio_read_agc_blob(struct file *file,
1250					  char __user *user_buf,
1251					  size_t count, loff_t *ppos)
1252{
1253	int err;
1254	struct si476x_radio *radio = file->private_data;
1255	struct si476x_agc_status_report report;
1256
1257	si476x_core_lock(radio->core);
1258	if (radio->ops->rds_blckcnt)
1259		err = radio->ops->agc_status(radio->core, &report);
1260	else
1261		err = -ENOENT;
1262	si476x_core_unlock(radio->core);
1263
1264	if (err < 0)
1265		return err;
1266
1267	return simple_read_from_buffer(user_buf, count, ppos, &report,
1268				       sizeof(report));
1269}
1270
1271static const struct file_operations radio_agc_fops = {
1272	.open	= simple_open,
1273	.llseek = default_llseek,
1274	.read	= si476x_radio_read_agc_blob,
1275};
1276
1277static ssize_t si476x_radio_read_rsq_blob(struct file *file,
1278					  char __user *user_buf,
1279					  size_t count, loff_t *ppos)
1280{
1281	int err;
1282	struct si476x_radio *radio = file->private_data;
1283	struct si476x_rsq_status_report report;
1284	struct si476x_rsq_status_args args = {
1285		.primary	= false,
1286		.rsqack		= false,
1287		.attune		= false,
1288		.cancel		= false,
1289		.stcack		= false,
1290	};
1291
1292	si476x_core_lock(radio->core);
1293	if (radio->ops->rds_blckcnt)
1294		err = radio->ops->rsq_status(radio->core, &args, &report);
1295	else
1296		err = -ENOENT;
1297	si476x_core_unlock(radio->core);
1298
1299	if (err < 0)
1300		return err;
1301
1302	return simple_read_from_buffer(user_buf, count, ppos, &report,
1303				       sizeof(report));
1304}
1305
1306static const struct file_operations radio_rsq_fops = {
1307	.open	= simple_open,
1308	.llseek = default_llseek,
1309	.read	= si476x_radio_read_rsq_blob,
1310};
1311
1312static ssize_t si476x_radio_read_rsq_primary_blob(struct file *file,
1313						  char __user *user_buf,
1314						  size_t count, loff_t *ppos)
1315{
1316	int err;
1317	struct si476x_radio *radio = file->private_data;
1318	struct si476x_rsq_status_report report;
1319	struct si476x_rsq_status_args args = {
1320		.primary	= true,
1321		.rsqack		= false,
1322		.attune		= false,
1323		.cancel		= false,
1324		.stcack		= false,
1325	};
1326
1327	si476x_core_lock(radio->core);
1328	if (radio->ops->rds_blckcnt)
1329		err = radio->ops->rsq_status(radio->core, &args, &report);
1330	else
1331		err = -ENOENT;
1332	si476x_core_unlock(radio->core);
1333
1334	if (err < 0)
1335		return err;
1336
1337	return simple_read_from_buffer(user_buf, count, ppos, &report,
1338				       sizeof(report));
1339}
1340
1341static const struct file_operations radio_rsq_primary_fops = {
1342	.open	= simple_open,
1343	.llseek = default_llseek,
1344	.read	= si476x_radio_read_rsq_primary_blob,
1345};
1346
1347
1348static void si476x_radio_init_debugfs(struct si476x_radio *radio)
1349{
1350	radio->debugfs = debugfs_create_dir(dev_name(radio->v4l2dev.dev), NULL);
1351
1352	debugfs_create_file("acf", S_IRUGO, radio->debugfs, radio,
1353			    &radio_acf_fops);
1354
1355	debugfs_create_file("rds_blckcnt", S_IRUGO, radio->debugfs, radio,
1356			    &radio_rds_blckcnt_fops);
1357
1358	debugfs_create_file("agc", S_IRUGO, radio->debugfs, radio,
1359			    &radio_agc_fops);
1360
1361	debugfs_create_file("rsq", S_IRUGO, radio->debugfs, radio,
1362			    &radio_rsq_fops);
1363
1364	debugfs_create_file("rsq_primary", S_IRUGO, radio->debugfs, radio,
1365			    &radio_rsq_primary_fops);
1366}
1367
1368
1369static int si476x_radio_add_new_custom(struct si476x_radio *radio,
1370				       enum si476x_ctrl_idx idx)
1371{
1372	int rval;
1373	struct v4l2_ctrl *ctrl;
1374
1375	ctrl = v4l2_ctrl_new_custom(&radio->ctrl_handler,
1376				    &si476x_ctrls[idx],
1377				    NULL);
1378	rval = radio->ctrl_handler.error;
1379	if (ctrl == NULL && rval)
1380		dev_err(radio->v4l2dev.dev,
1381			"Could not initialize '%s' control %d\n",
1382			si476x_ctrls[idx].name, rval);
1383
1384	return rval;
1385}
1386
1387static int si476x_radio_probe(struct platform_device *pdev)
1388{
1389	int rval;
1390	struct si476x_radio *radio;
1391	struct v4l2_ctrl *ctrl;
1392
1393	static atomic_t instance = ATOMIC_INIT(0);
1394
1395	radio = devm_kzalloc(&pdev->dev, sizeof(*radio), GFP_KERNEL);
1396	if (!radio)
1397		return -ENOMEM;
1398
1399	radio->core = i2c_mfd_cell_to_core(&pdev->dev);
1400
1401	v4l2_device_set_name(&radio->v4l2dev, DRIVER_NAME, &instance);
1402
1403	rval = v4l2_device_register(&pdev->dev, &radio->v4l2dev);
1404	if (rval) {
1405		dev_err(&pdev->dev, "Cannot register v4l2_device.\n");
1406		return rval;
1407	}
1408
1409	memcpy(&radio->videodev, &si476x_viddev_template,
1410	       sizeof(struct video_device));
1411
1412	radio->videodev.v4l2_dev  = &radio->v4l2dev;
1413	radio->videodev.ioctl_ops = &si4761_ioctl_ops;
1414	radio->videodev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
1415				      V4L2_CAP_HW_FREQ_SEEK;
1416
1417	si476x_core_lock(radio->core);
1418	if (!si476x_core_is_a_secondary_tuner(radio->core))
1419		radio->videodev.device_caps |= V4L2_CAP_RDS_CAPTURE |
1420					       V4L2_CAP_READWRITE;
1421	si476x_core_unlock(radio->core);
1422
1423	video_set_drvdata(&radio->videodev, radio);
1424	platform_set_drvdata(pdev, radio);
1425
1426
1427	radio->v4l2dev.ctrl_handler = &radio->ctrl_handler;
1428	v4l2_ctrl_handler_init(&radio->ctrl_handler,
1429			       1 + ARRAY_SIZE(si476x_ctrls));
1430
1431	if (si476x_core_has_am(radio->core)) {
1432		ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler,
1433					      &si476x_ctrl_ops,
1434					      V4L2_CID_POWER_LINE_FREQUENCY,
1435					      V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
1436					      0, 0);
1437		rval = radio->ctrl_handler.error;
1438		if (ctrl == NULL && rval) {
1439			dev_err(&pdev->dev, "Could not initialize V4L2_CID_POWER_LINE_FREQUENCY control %d\n",
1440				rval);
1441			goto exit;
1442		}
1443
1444		rval = si476x_radio_add_new_custom(radio,
1445						   SI476X_IDX_HARMONICS_COUNT);
1446		if (rval < 0)
1447			goto exit;
1448	}
1449
1450	rval = si476x_radio_add_new_custom(radio, SI476X_IDX_RSSI_THRESHOLD);
1451	if (rval < 0)
1452		goto exit;
1453
1454	rval = si476x_radio_add_new_custom(radio, SI476X_IDX_SNR_THRESHOLD);
1455	if (rval < 0)
1456		goto exit;
1457
1458	rval = si476x_radio_add_new_custom(radio, SI476X_IDX_MAX_TUNE_ERROR);
1459	if (rval < 0)
1460		goto exit;
1461
1462	ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler,
1463				      &si476x_ctrl_ops,
1464				      V4L2_CID_TUNE_DEEMPHASIS,
1465				      V4L2_DEEMPHASIS_75_uS, 0, 0);
1466	rval = radio->ctrl_handler.error;
1467	if (ctrl == NULL && rval) {
1468		dev_err(&pdev->dev, "Could not initialize V4L2_CID_TUNE_DEEMPHASIS control %d\n",
1469			rval);
1470		goto exit;
1471	}
1472
1473	ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &si476x_ctrl_ops,
1474				 V4L2_CID_RDS_RECEPTION,
1475				 0, 1, 1, 1);
1476	rval = radio->ctrl_handler.error;
1477	if (ctrl == NULL && rval) {
1478		dev_err(&pdev->dev, "Could not initialize V4L2_CID_RDS_RECEPTION control %d\n",
1479			rval);
1480		goto exit;
1481	}
1482
1483	if (si476x_core_has_diversity(radio->core)) {
1484		si476x_ctrls[SI476X_IDX_DIVERSITY_MODE].def =
1485			si476x_phase_diversity_mode_to_idx(radio->core->diversity_mode);
1486		rval = si476x_radio_add_new_custom(radio, SI476X_IDX_DIVERSITY_MODE);
1487		if (rval < 0)
1488			goto exit;
1489
1490		rval = si476x_radio_add_new_custom(radio, SI476X_IDX_INTERCHIP_LINK);
1491		if (rval < 0)
1492			goto exit;
1493	}
1494
1495	/* register video device */
1496	rval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, -1);
1497	if (rval < 0) {
1498		dev_err(&pdev->dev, "Could not register video device\n");
1499		goto exit;
1500	}
1501
1502	si476x_radio_init_debugfs(radio);
1503
1504	return 0;
1505exit:
1506	v4l2_ctrl_handler_free(radio->videodev.ctrl_handler);
1507	return rval;
1508}
1509
1510static int si476x_radio_remove(struct platform_device *pdev)
1511{
1512	struct si476x_radio *radio = platform_get_drvdata(pdev);
1513
1514	v4l2_ctrl_handler_free(radio->videodev.ctrl_handler);
1515	video_unregister_device(&radio->videodev);
1516	v4l2_device_unregister(&radio->v4l2dev);
1517	debugfs_remove_recursive(radio->debugfs);
1518
1519	return 0;
1520}
1521
1522MODULE_ALIAS("platform:si476x-radio");
1523
1524static struct platform_driver si476x_radio_driver = {
1525	.driver		= {
1526		.name	= DRIVER_NAME,
1527	},
1528	.probe		= si476x_radio_probe,
1529	.remove		= si476x_radio_remove,
1530};
1531module_platform_driver(si476x_radio_driver);
1532
1533MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
1534MODULE_DESCRIPTION("Driver for Si4761/64/68 AM/FM Radio MFD Cell");
1535MODULE_LICENSE("GPL");
1536