1/*
2 *  drivers/media/radio/si470x/radio-si470x-common.c
3 *
4 *  Driver for radios with Silicon Labs Si470x FM Radio Receivers
5 *
6 *  Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23
24/*
25 * History:
26 * 2008-01-12	Tobias Lorenz <tobias.lorenz@gmx.net>
27 *		Version 1.0.0
28 *		- First working version
29 * 2008-01-13	Tobias Lorenz <tobias.lorenz@gmx.net>
30 *		Version 1.0.1
31 *		- Improved error handling, every function now returns errno
32 *		- Improved multi user access (start/mute/stop)
33 *		- Channel doesn't get lost anymore after start/mute/stop
34 *		- RDS support added (polling mode via interrupt EP 1)
35 *		- marked default module parameters with *value*
36 *		- switched from bit structs to bit masks
37 *		- header file cleaned and integrated
38 * 2008-01-14	Tobias Lorenz <tobias.lorenz@gmx.net>
39 * 		Version 1.0.2
40 * 		- hex values are now lower case
41 * 		- commented USB ID for ADS/Tech moved on todo list
42 * 		- blacklisted si470x in hid-quirks.c
43 * 		- rds buffer handling functions integrated into *_work, *_read
44 * 		- rds_command in si470x_poll exchanged against simple retval
45 * 		- check for firmware version 15
46 * 		- code order and prototypes still remain the same
47 * 		- spacing and bottom of band codes remain the same
48 * 2008-01-16	Tobias Lorenz <tobias.lorenz@gmx.net>
49 *		Version 1.0.3
50 * 		- code reordered to avoid function prototypes
51 *		- switch/case defaults are now more user-friendly
52 *		- unified comment style
53 *		- applied all checkpatch.pl v1.12 suggestions
54 *		  except the warning about the too long lines with bit comments
55 *		- renamed FMRADIO to RADIO to cut line length (checkpatch.pl)
56 * 2008-01-22	Tobias Lorenz <tobias.lorenz@gmx.net>
57 *		Version 1.0.4
58 *		- avoid poss. locking when doing copy_to_user which may sleep
59 *		- RDS is automatically activated on read now
60 *		- code cleaned of unnecessary rds_commands
61 *		- USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified
62 *		  (thanks to Guillaume RAMOUSSE)
63 * 2008-01-27	Tobias Lorenz <tobias.lorenz@gmx.net>
64 *		Version 1.0.5
65 *		- number of seek_retries changed to tune_timeout
66 *		- fixed problem with incomplete tune operations by own buffers
67 *		- optimization of variables and printf types
68 *		- improved error logging
69 * 2008-01-31	Tobias Lorenz <tobias.lorenz@gmx.net>
70 *		Oliver Neukum <oliver@neukum.org>
71 *		Version 1.0.6
72 *		- fixed coverity checker warnings in *_usb_driver_disconnect
73 *		- probe()/open() race by correct ordering in probe()
74 *		- DMA coherency rules by separate allocation of all buffers
75 *		- use of endianness macros
76 *		- abuse of spinlock, replaced by mutex
77 *		- racy handling of timer in disconnect,
78 *		  replaced by delayed_work
79 *		- racy interruptible_sleep_on(),
80 *		  replaced with wait_event_interruptible()
81 *		- handle signals in read()
82 * 2008-02-08	Tobias Lorenz <tobias.lorenz@gmx.net>
83 *		Oliver Neukum <oliver@neukum.org>
84 *		Version 1.0.7
85 *		- usb autosuspend support
86 *		- unplugging fixed
87 * 2008-05-07	Tobias Lorenz <tobias.lorenz@gmx.net>
88 *		Version 1.0.8
89 *		- hardware frequency seek support
90 *		- afc indication
91 *		- more safety checks, let si470x_get_freq return errno
92 *		- vidioc behavior corrected according to v4l2 spec
93 * 2008-10-20	Alexey Klimov <klimov.linux@gmail.com>
94 * 		- add support for KWorld USB FM Radio FM700
95 * 		- blacklisted KWorld radio in hid-core.c and hid-ids.h
96 * 2008-12-03	Mark Lord <mlord@pobox.com>
97 *		- add support for DealExtreme USB Radio
98 * 2009-01-31	Bob Ross <pigiron@gmx.com>
99 *		- correction of stereo detection/setting
100 *		- correction of signal strength indicator scaling
101 * 2009-01-31	Rick Bronson <rick@efn.org>
102 *		Tobias Lorenz <tobias.lorenz@gmx.net>
103 *		- add LED status output
104 *		- get HW/SW version from scratchpad
105 * 2009-06-16   Edouard Lafargue <edouard@lafargue.name>
106 *		Version 1.0.10
107 *		- add support for interrupt mode for RDS endpoint,
108 *                instead of polling.
109 *                Improves RDS reception significantly
110 */
111
112
113/* kernel includes */
114#include "radio-si470x.h"
115
116
117
118/**************************************************************************
119 * Module Parameters
120 **************************************************************************/
121
122/* Spacing (kHz) */
123/* 0: 200 kHz (USA, Australia) */
124/* 1: 100 kHz (Europe, Japan) */
125/* 2:  50 kHz */
126static unsigned short space = 2;
127module_param(space, ushort, 0444);
128MODULE_PARM_DESC(space, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
129
130/* Bottom of Band (MHz) */
131/* 0: 87.5 - 108 MHz (USA, Europe)*/
132/* 1: 76   - 108 MHz (Japan wide band) */
133/* 2: 76   -  90 MHz (Japan) */
134static unsigned short band = 1;
135module_param(band, ushort, 0444);
136MODULE_PARM_DESC(band, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
137
138/* De-emphasis */
139/* 0: 75 us (USA) */
140/* 1: 50 us (Europe, Australia, Japan) */
141static unsigned short de = 1;
142module_param(de, ushort, 0444);
143MODULE_PARM_DESC(de, "De-emphasis: 0=75us *1=50us*");
144
145/* Tune timeout */
146static unsigned int tune_timeout = 3000;
147module_param(tune_timeout, uint, 0644);
148MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*");
149
150/* Seek timeout */
151static unsigned int seek_timeout = 5000;
152module_param(seek_timeout, uint, 0644);
153MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*");
154
155
156
157/**************************************************************************
158 * Generic Functions
159 **************************************************************************/
160
161/*
162 * si470x_set_chan - set the channel
163 */
164static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
165{
166	int retval;
167	unsigned long timeout;
168	bool timed_out = 0;
169
170	/* start tuning */
171	radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
172	radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
173	retval = si470x_set_register(radio, CHANNEL);
174	if (retval < 0)
175		goto done;
176
177	/* currently I2C driver only uses interrupt way to tune */
178	if (radio->stci_enabled) {
179		INIT_COMPLETION(radio->completion);
180
181		/* wait till tune operation has completed */
182		retval = wait_for_completion_timeout(&radio->completion,
183				msecs_to_jiffies(tune_timeout));
184		if (!retval)
185			timed_out = true;
186	} else {
187		/* wait till tune operation has completed */
188		timeout = jiffies + msecs_to_jiffies(tune_timeout);
189		do {
190			retval = si470x_get_register(radio, STATUSRSSI);
191			if (retval < 0)
192				goto stop;
193			timed_out = time_after(jiffies, timeout);
194		} while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
195				&& (!timed_out));
196	}
197
198	if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
199		dev_warn(&radio->videodev->dev, "tune does not complete\n");
200	if (timed_out)
201		dev_warn(&radio->videodev->dev,
202			"tune timed out after %u ms\n", tune_timeout);
203
204stop:
205	/* stop tuning */
206	radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
207	retval = si470x_set_register(radio, CHANNEL);
208
209done:
210	return retval;
211}
212
213
214/*
215 * si470x_get_freq - get the frequency
216 */
217static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq)
218{
219	unsigned int spacing, band_bottom;
220	unsigned short chan;
221	int retval;
222
223	/* Spacing (kHz) */
224	switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
225	/* 0: 200 kHz (USA, Australia) */
226	case 0:
227		spacing = 0.200 * FREQ_MUL; break;
228	/* 1: 100 kHz (Europe, Japan) */
229	case 1:
230		spacing = 0.100 * FREQ_MUL; break;
231	/* 2:  50 kHz */
232	default:
233		spacing = 0.050 * FREQ_MUL; break;
234	};
235
236	/* Bottom of Band (MHz) */
237	switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
238	/* 0: 87.5 - 108 MHz (USA, Europe) */
239	case 0:
240		band_bottom = 87.5 * FREQ_MUL; break;
241	/* 1: 76   - 108 MHz (Japan wide band) */
242	default:
243		band_bottom = 76   * FREQ_MUL; break;
244	/* 2: 76   -  90 MHz (Japan) */
245	case 2:
246		band_bottom = 76   * FREQ_MUL; break;
247	};
248
249	/* read channel */
250	retval = si470x_get_register(radio, READCHAN);
251	chan = radio->registers[READCHAN] & READCHAN_READCHAN;
252
253	/* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */
254	*freq = chan * spacing + band_bottom;
255
256	return retval;
257}
258
259
260/*
261 * si470x_set_freq - set the frequency
262 */
263int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
264{
265	unsigned int spacing, band_bottom;
266	unsigned short chan;
267
268	/* Spacing (kHz) */
269	switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
270	/* 0: 200 kHz (USA, Australia) */
271	case 0:
272		spacing = 0.200 * FREQ_MUL; break;
273	/* 1: 100 kHz (Europe, Japan) */
274	case 1:
275		spacing = 0.100 * FREQ_MUL; break;
276	/* 2:  50 kHz */
277	default:
278		spacing = 0.050 * FREQ_MUL; break;
279	};
280
281	/* Bottom of Band (MHz) */
282	switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
283	/* 0: 87.5 - 108 MHz (USA, Europe) */
284	case 0:
285		band_bottom = 87.5 * FREQ_MUL; break;
286	/* 1: 76   - 108 MHz (Japan wide band) */
287	default:
288		band_bottom = 76   * FREQ_MUL; break;
289	/* 2: 76   -  90 MHz (Japan) */
290	case 2:
291		band_bottom = 76   * FREQ_MUL; break;
292	};
293
294	/* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
295	chan = (freq - band_bottom) / spacing;
296
297	return si470x_set_chan(radio, chan);
298}
299
300
301/*
302 * si470x_set_seek - set seek
303 */
304static int si470x_set_seek(struct si470x_device *radio,
305		unsigned int wrap_around, unsigned int seek_upward)
306{
307	int retval = 0;
308	unsigned long timeout;
309	bool timed_out = 0;
310
311	/* start seeking */
312	radio->registers[POWERCFG] |= POWERCFG_SEEK;
313	if (wrap_around == 1)
314		radio->registers[POWERCFG] &= ~POWERCFG_SKMODE;
315	else
316		radio->registers[POWERCFG] |= POWERCFG_SKMODE;
317	if (seek_upward == 1)
318		radio->registers[POWERCFG] |= POWERCFG_SEEKUP;
319	else
320		radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP;
321	retval = si470x_set_register(radio, POWERCFG);
322	if (retval < 0)
323		goto done;
324
325	/* currently I2C driver only uses interrupt way to seek */
326	if (radio->stci_enabled) {
327		INIT_COMPLETION(radio->completion);
328
329		/* wait till seek operation has completed */
330		retval = wait_for_completion_timeout(&radio->completion,
331				msecs_to_jiffies(seek_timeout));
332		if (!retval)
333			timed_out = true;
334	} else {
335		/* wait till seek operation has completed */
336		timeout = jiffies + msecs_to_jiffies(seek_timeout);
337		do {
338			retval = si470x_get_register(radio, STATUSRSSI);
339			if (retval < 0)
340				goto stop;
341			timed_out = time_after(jiffies, timeout);
342		} while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
343				&& (!timed_out));
344	}
345
346	if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
347		dev_warn(&radio->videodev->dev, "seek does not complete\n");
348	if (radio->registers[STATUSRSSI] & STATUSRSSI_SF)
349		dev_warn(&radio->videodev->dev,
350			"seek failed / band limit reached\n");
351	if (timed_out)
352		dev_warn(&radio->videodev->dev,
353			"seek timed out after %u ms\n", seek_timeout);
354
355stop:
356	/* stop seeking */
357	radio->registers[POWERCFG] &= ~POWERCFG_SEEK;
358	retval = si470x_set_register(radio, POWERCFG);
359
360done:
361	/* try again, if timed out */
362	if ((retval == 0) && timed_out)
363		retval = -EAGAIN;
364
365	return retval;
366}
367
368
369/*
370 * si470x_start - switch on radio
371 */
372int si470x_start(struct si470x_device *radio)
373{
374	int retval;
375
376	/* powercfg */
377	radio->registers[POWERCFG] =
378		POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
379	retval = si470x_set_register(radio, POWERCFG);
380	if (retval < 0)
381		goto done;
382
383	/* sysconfig 1 */
384	radio->registers[SYSCONFIG1] =
385		(de << 11) & SYSCONFIG1_DE;		/* DE*/
386	retval = si470x_set_register(radio, SYSCONFIG1);
387	if (retval < 0)
388		goto done;
389
390	/* sysconfig 2 */
391	radio->registers[SYSCONFIG2] =
392		(0x3f  << 8) |				/* SEEKTH */
393		((band  << 6) & SYSCONFIG2_BAND)  |	/* BAND */
394		((space << 4) & SYSCONFIG2_SPACE) |	/* SPACE */
395		15;					/* VOLUME (max) */
396	retval = si470x_set_register(radio, SYSCONFIG2);
397	if (retval < 0)
398		goto done;
399
400	/* reset last channel */
401	retval = si470x_set_chan(radio,
402		radio->registers[CHANNEL] & CHANNEL_CHAN);
403
404done:
405	return retval;
406}
407
408
409/*
410 * si470x_stop - switch off radio
411 */
412int si470x_stop(struct si470x_device *radio)
413{
414	int retval;
415
416	/* sysconfig 1 */
417	radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
418	retval = si470x_set_register(radio, SYSCONFIG1);
419	if (retval < 0)
420		goto done;
421
422	/* powercfg */
423	radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
424	/* POWERCFG_ENABLE has to automatically go low */
425	radio->registers[POWERCFG] |= POWERCFG_ENABLE |	POWERCFG_DISABLE;
426	retval = si470x_set_register(radio, POWERCFG);
427
428done:
429	return retval;
430}
431
432
433/*
434 * si470x_rds_on - switch on rds reception
435 */
436static int si470x_rds_on(struct si470x_device *radio)
437{
438	int retval;
439
440	/* sysconfig 1 */
441	radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
442	retval = si470x_set_register(radio, SYSCONFIG1);
443	if (retval < 0)
444		radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
445
446	return retval;
447}
448
449
450
451/**************************************************************************
452 * File Operations Interface
453 **************************************************************************/
454
455/*
456 * si470x_fops_read - read RDS data
457 */
458static ssize_t si470x_fops_read(struct file *file, char __user *buf,
459		size_t count, loff_t *ppos)
460{
461	struct si470x_device *radio = video_drvdata(file);
462	int retval = 0;
463	unsigned int block_count = 0;
464
465	/* switch on rds reception */
466	mutex_lock(&radio->lock);
467	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
468		si470x_rds_on(radio);
469
470	/* block if no new data available */
471	while (radio->wr_index == radio->rd_index) {
472		if (file->f_flags & O_NONBLOCK) {
473			retval = -EWOULDBLOCK;
474			goto done;
475		}
476		if (wait_event_interruptible(radio->read_queue,
477			radio->wr_index != radio->rd_index) < 0) {
478			retval = -EINTR;
479			goto done;
480		}
481	}
482
483	/* calculate block count from byte count */
484	count /= 3;
485
486	/* copy RDS block out of internal buffer and to user buffer */
487	while (block_count < count) {
488		if (radio->rd_index == radio->wr_index)
489			break;
490
491		/* always transfer rds complete blocks */
492		if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3))
493			/* retval = -EFAULT; */
494			break;
495
496		/* increment and wrap read pointer */
497		radio->rd_index += 3;
498		if (radio->rd_index >= radio->buf_size)
499			radio->rd_index = 0;
500
501		/* increment counters */
502		block_count++;
503		buf += 3;
504		retval += 3;
505	}
506
507done:
508	mutex_unlock(&radio->lock);
509	return retval;
510}
511
512
513/*
514 * si470x_fops_poll - poll RDS data
515 */
516static unsigned int si470x_fops_poll(struct file *file,
517		struct poll_table_struct *pts)
518{
519	struct si470x_device *radio = video_drvdata(file);
520	int retval = 0;
521
522	/* switch on rds reception */
523
524	mutex_lock(&radio->lock);
525	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
526		si470x_rds_on(radio);
527	mutex_unlock(&radio->lock);
528
529	poll_wait(file, &radio->read_queue, pts);
530
531	if (radio->rd_index != radio->wr_index)
532		retval = POLLIN | POLLRDNORM;
533
534	return retval;
535}
536
537
538/*
539 * si470x_fops - file operations interface
540 */
541static const struct v4l2_file_operations si470x_fops = {
542	.owner			= THIS_MODULE,
543	.read			= si470x_fops_read,
544	.poll			= si470x_fops_poll,
545	.unlocked_ioctl		= video_ioctl2,
546	.open			= si470x_fops_open,
547	.release		= si470x_fops_release,
548};
549
550
551
552/**************************************************************************
553 * Video4Linux Interface
554 **************************************************************************/
555
556/*
557 * si470x_vidioc_queryctrl - enumerate control items
558 */
559static int si470x_vidioc_queryctrl(struct file *file, void *priv,
560		struct v4l2_queryctrl *qc)
561{
562	struct si470x_device *radio = video_drvdata(file);
563	int retval = -EINVAL;
564
565	/* abort if qc->id is below V4L2_CID_BASE */
566	if (qc->id < V4L2_CID_BASE)
567		goto done;
568
569	/* search video control */
570	switch (qc->id) {
571	case V4L2_CID_AUDIO_VOLUME:
572		return v4l2_ctrl_query_fill(qc, 0, 15, 1, 15);
573	case V4L2_CID_AUDIO_MUTE:
574		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
575	}
576
577	/* disable unsupported base controls */
578	/* to satisfy kradio and such apps */
579	if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) {
580		qc->flags = V4L2_CTRL_FLAG_DISABLED;
581		retval = 0;
582	}
583
584done:
585	if (retval < 0)
586		dev_warn(&radio->videodev->dev,
587			"query controls failed with %d\n", retval);
588	return retval;
589}
590
591
592/*
593 * si470x_vidioc_g_ctrl - get the value of a control
594 */
595static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
596		struct v4l2_control *ctrl)
597{
598	struct si470x_device *radio = video_drvdata(file);
599	int retval = 0;
600
601	mutex_lock(&radio->lock);
602	/* safety checks */
603	retval = si470x_disconnect_check(radio);
604	if (retval)
605		goto done;
606
607	switch (ctrl->id) {
608	case V4L2_CID_AUDIO_VOLUME:
609		ctrl->value = radio->registers[SYSCONFIG2] &
610				SYSCONFIG2_VOLUME;
611		break;
612	case V4L2_CID_AUDIO_MUTE:
613		ctrl->value = ((radio->registers[POWERCFG] &
614				POWERCFG_DMUTE) == 0) ? 1 : 0;
615		break;
616	default:
617		retval = -EINVAL;
618	}
619
620done:
621	if (retval < 0)
622		dev_warn(&radio->videodev->dev,
623			"get control failed with %d\n", retval);
624
625	mutex_unlock(&radio->lock);
626	return retval;
627}
628
629
630/*
631 * si470x_vidioc_s_ctrl - set the value of a control
632 */
633static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
634		struct v4l2_control *ctrl)
635{
636	struct si470x_device *radio = video_drvdata(file);
637	int retval = 0;
638
639	mutex_lock(&radio->lock);
640	/* safety checks */
641	retval = si470x_disconnect_check(radio);
642	if (retval)
643		goto done;
644
645	switch (ctrl->id) {
646	case V4L2_CID_AUDIO_VOLUME:
647		radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
648		radio->registers[SYSCONFIG2] |= ctrl->value;
649		retval = si470x_set_register(radio, SYSCONFIG2);
650		break;
651	case V4L2_CID_AUDIO_MUTE:
652		if (ctrl->value == 1)
653			radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
654		else
655			radio->registers[POWERCFG] |= POWERCFG_DMUTE;
656		retval = si470x_set_register(radio, POWERCFG);
657		break;
658	default:
659		retval = -EINVAL;
660	}
661
662done:
663	if (retval < 0)
664		dev_warn(&radio->videodev->dev,
665			"set control failed with %d\n", retval);
666	mutex_unlock(&radio->lock);
667	return retval;
668}
669
670
671/*
672 * si470x_vidioc_g_audio - get audio attributes
673 */
674static int si470x_vidioc_g_audio(struct file *file, void *priv,
675		struct v4l2_audio *audio)
676{
677	/* driver constants */
678	audio->index = 0;
679	strcpy(audio->name, "Radio");
680	audio->capability = V4L2_AUDCAP_STEREO;
681	audio->mode = 0;
682
683	return 0;
684}
685
686
687/*
688 * si470x_vidioc_g_tuner - get tuner attributes
689 */
690static int si470x_vidioc_g_tuner(struct file *file, void *priv,
691		struct v4l2_tuner *tuner)
692{
693	struct si470x_device *radio = video_drvdata(file);
694	int retval = 0;
695
696	mutex_lock(&radio->lock);
697	/* safety checks */
698	retval = si470x_disconnect_check(radio);
699	if (retval)
700		goto done;
701
702	if (tuner->index != 0) {
703		retval = -EINVAL;
704		goto done;
705	}
706
707	retval = si470x_get_register(radio, STATUSRSSI);
708	if (retval < 0)
709		goto done;
710
711	/* driver constants */
712	strcpy(tuner->name, "FM");
713	tuner->type = V4L2_TUNER_RADIO;
714	tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
715			    V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO;
716
717	/* range limits */
718	switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
719	/* 0: 87.5 - 108 MHz (USA, Europe, default) */
720	default:
721		tuner->rangelow  =  87.5 * FREQ_MUL;
722		tuner->rangehigh = 108   * FREQ_MUL;
723		break;
724	/* 1: 76   - 108 MHz (Japan wide band) */
725	case 1:
726		tuner->rangelow  =  76   * FREQ_MUL;
727		tuner->rangehigh = 108   * FREQ_MUL;
728		break;
729	/* 2: 76   -  90 MHz (Japan) */
730	case 2:
731		tuner->rangelow  =  76   * FREQ_MUL;
732		tuner->rangehigh =  90   * FREQ_MUL;
733		break;
734	};
735
736	/* stereo indicator == stereo (instead of mono) */
737	if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0)
738		tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
739	else
740		tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
741	/* If there is a reliable method of detecting an RDS channel,
742	   then this code should check for that before setting this
743	   RDS subchannel. */
744	tuner->rxsubchans |= V4L2_TUNER_SUB_RDS;
745
746	/* mono/stereo selector */
747	if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0)
748		tuner->audmode = V4L2_TUNER_MODE_STEREO;
749	else
750		tuner->audmode = V4L2_TUNER_MODE_MONO;
751
752	/* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
753	/* measured in units of dbµV in 1 db increments (max at ~75 dbµV) */
754	tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI);
755	/* the ideal factor is 0xffff/75 = 873,8 */
756	tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10);
757
758	/* automatic frequency control: -1: freq to low, 1 freq to high */
759	/* AFCRL does only indicate that freq. differs, not if too low/high */
760	tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0;
761
762done:
763	if (retval < 0)
764		dev_warn(&radio->videodev->dev,
765			"get tuner failed with %d\n", retval);
766	mutex_unlock(&radio->lock);
767	return retval;
768}
769
770
771/*
772 * si470x_vidioc_s_tuner - set tuner attributes
773 */
774static int si470x_vidioc_s_tuner(struct file *file, void *priv,
775		struct v4l2_tuner *tuner)
776{
777	struct si470x_device *radio = video_drvdata(file);
778	int retval = 0;
779
780	mutex_lock(&radio->lock);
781	/* safety checks */
782	retval = si470x_disconnect_check(radio);
783	if (retval)
784		goto done;
785
786	if (tuner->index != 0)
787		goto done;
788
789	/* mono/stereo selector */
790	switch (tuner->audmode) {
791	case V4L2_TUNER_MODE_MONO:
792		radio->registers[POWERCFG] |= POWERCFG_MONO;  /* force mono */
793		break;
794	case V4L2_TUNER_MODE_STEREO:
795		radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
796		break;
797	default:
798		goto done;
799	}
800
801	retval = si470x_set_register(radio, POWERCFG);
802
803done:
804	if (retval < 0)
805		dev_warn(&radio->videodev->dev,
806			"set tuner failed with %d\n", retval);
807	mutex_unlock(&radio->lock);
808	return retval;
809}
810
811
812/*
813 * si470x_vidioc_g_frequency - get tuner or modulator radio frequency
814 */
815static int si470x_vidioc_g_frequency(struct file *file, void *priv,
816		struct v4l2_frequency *freq)
817{
818	struct si470x_device *radio = video_drvdata(file);
819	int retval = 0;
820
821	/* safety checks */
822	mutex_lock(&radio->lock);
823	retval = si470x_disconnect_check(radio);
824	if (retval)
825		goto done;
826
827	if (freq->tuner != 0) {
828		retval = -EINVAL;
829		goto done;
830	}
831
832	freq->type = V4L2_TUNER_RADIO;
833	retval = si470x_get_freq(radio, &freq->frequency);
834
835done:
836	if (retval < 0)
837		dev_warn(&radio->videodev->dev,
838			"get frequency failed with %d\n", retval);
839	mutex_unlock(&radio->lock);
840	return retval;
841}
842
843
844/*
845 * si470x_vidioc_s_frequency - set tuner or modulator radio frequency
846 */
847static int si470x_vidioc_s_frequency(struct file *file, void *priv,
848		struct v4l2_frequency *freq)
849{
850	struct si470x_device *radio = video_drvdata(file);
851	int retval = 0;
852
853	mutex_lock(&radio->lock);
854	/* safety checks */
855	retval = si470x_disconnect_check(radio);
856	if (retval)
857		goto done;
858
859	if (freq->tuner != 0) {
860		retval = -EINVAL;
861		goto done;
862	}
863
864	retval = si470x_set_freq(radio, freq->frequency);
865
866done:
867	if (retval < 0)
868		dev_warn(&radio->videodev->dev,
869			"set frequency failed with %d\n", retval);
870	mutex_unlock(&radio->lock);
871	return retval;
872}
873
874
875/*
876 * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek
877 */
878static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
879		struct v4l2_hw_freq_seek *seek)
880{
881	struct si470x_device *radio = video_drvdata(file);
882	int retval = 0;
883
884	mutex_lock(&radio->lock);
885	/* safety checks */
886	retval = si470x_disconnect_check(radio);
887	if (retval)
888		goto done;
889
890	if (seek->tuner != 0) {
891		retval = -EINVAL;
892		goto done;
893	}
894
895	retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward);
896
897done:
898	if (retval < 0)
899		dev_warn(&radio->videodev->dev,
900			"set hardware frequency seek failed with %d\n", retval);
901	mutex_unlock(&radio->lock);
902	return retval;
903}
904
905
906/*
907 * si470x_ioctl_ops - video device ioctl operations
908 */
909static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
910	.vidioc_querycap	= si470x_vidioc_querycap,
911	.vidioc_queryctrl	= si470x_vidioc_queryctrl,
912	.vidioc_g_ctrl		= si470x_vidioc_g_ctrl,
913	.vidioc_s_ctrl		= si470x_vidioc_s_ctrl,
914	.vidioc_g_audio		= si470x_vidioc_g_audio,
915	.vidioc_g_tuner		= si470x_vidioc_g_tuner,
916	.vidioc_s_tuner		= si470x_vidioc_s_tuner,
917	.vidioc_g_frequency	= si470x_vidioc_g_frequency,
918	.vidioc_s_frequency	= si470x_vidioc_s_frequency,
919	.vidioc_s_hw_freq_seek	= si470x_vidioc_s_hw_freq_seek,
920};
921
922
923/*
924 * si470x_viddev_template - video device interface
925 */
926struct video_device si470x_viddev_template = {
927	.fops			= &si470x_fops,
928	.name			= DRIVER_NAME,
929	.release		= video_device_release,
930	.ioctl_ops		= &si470x_ioctl_ops,
931};
932