11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   ALSA driver for TEA5757/5759 Philips AM/FM radio tuner chips
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4c1017a4cdb68ae5368fbc9ee42c77f1f5dca8916Jaroslav Kysela *	Copyright (c) 2004 Jaroslav Kysela <perex@perex.cz>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   This program is free software; you can redistribute it and/or modify
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   it under the terms of the GNU General Public License as published by
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   the Free Software Foundation; either version 2 of the License, or
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   (at your option) any later version.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   This program is distributed in the hope that it will be useful,
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   but WITHOUT ANY WARRANTY; without even the implied warranty of
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   GNU General Public License for more details.
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   You should have received a copy of the GNU General Public License
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   along with this program; if not, write to the Free Software
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
214b29631db33292d416dc395c56122ea865e7635cIgor M. Liplianin */
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
24da155d5b40587815a4397e1a69382fe2366d940bPaul Gortmaker#include <linux/module.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
265a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
27d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil#include <linux/sched.h>
28eab924d0e2bdfd53c902162b0b499b8464c1fb4aMauro Carvalho Chehab#include <asm/io.h>
29d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil#include <media/v4l2-device.h>
304522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary#include <media/v4l2-dev.h>
31d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil#include <media/v4l2-fh.h>
324522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary#include <media/v4l2-ioctl.h>
33d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil#include <media/v4l2-event.h>
3459b564599bc66f086856b09e480f89555d47b35cOndrej Zary#include <media/tea575x.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36c1017a4cdb68ae5368fbc9ee42c77f1f5dca8916Jaroslav KyselaMODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips");
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * definitions
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_SEARCH	(1<<24)		/* 1 = search action, 0 = tuned */
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_UPDOWN	(1<<23)		/* 0 = search down, 1 = search up */
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_MONO	(1<<22)		/* 0 = stereo, 1 = mono */
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_BAND_MASK	(3<<20)
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_BAND_FM	(0<<20)
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_BAND_MW	(1<<20)
50fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede#define TEA575X_BIT_BAND_LW	(2<<20)
51fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede#define TEA575X_BIT_BAND_SW	(3<<20)
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_PORT_0	(1<<19)		/* user bit */
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_PORT_1	(1<<18)		/* user bit */
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_SEARCH_MASK	(3<<16)		/* search level */
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_SEARCH_5_28	     (0<<16)	/* FM >5uV, AM >28uV */
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_SEARCH_10_40     (1<<16)	/* FM >10uV, AM > 40uV */
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_SEARCH_30_63     (2<<16)	/* FM >30uV, AM > 63uV */
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_SEARCH_150_1000  (3<<16)	/* FM > 150uV, AM > 1000uV */
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_DUMMY	(1<<15)		/* buffer */
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_FREQ_MASK	0x7fff
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
62fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goedeenum { BAND_FM, BAND_FM_JAPAN, BAND_AM };
63fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede
64fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goedestatic const struct v4l2_frequency_band bands[] = {
65fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	{
66fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.type = V4L2_TUNER_RADIO,
67fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.index = 0,
68fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
69fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			      V4L2_TUNER_CAP_FREQ_BANDS,
70fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.rangelow   =  87500 * 16,
71fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.rangehigh  = 108000 * 16,
72fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.modulation = V4L2_BAND_MODULATION_FM,
73fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	},
74fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	{
75fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.type = V4L2_TUNER_RADIO,
76fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.index = 0,
77fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
78fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			      V4L2_TUNER_CAP_FREQ_BANDS,
79fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.rangelow   = 76000 * 16,
80fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.rangehigh  = 91000 * 16,
81fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.modulation = V4L2_BAND_MODULATION_FM,
82fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	},
83fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	{
84fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.type = V4L2_TUNER_RADIO,
85fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.index = 1,
86fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
87fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.rangelow   =  530 * 16,
88fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.rangehigh  = 1710 * 16,
89fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		.modulation = V4L2_BAND_MODULATION_AM,
90fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	},
91fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede};
92fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lowlevel part
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9714219d06592025541559027d0fd8f96ef75f313cOndrej Zarystatic void snd_tea575x_write(struct snd_tea575x *tea, unsigned int val)
9814219d06592025541559027d0fd8f96ef75f313cOndrej Zary{
9914219d06592025541559027d0fd8f96ef75f313cOndrej Zary	u16 l;
10014219d06592025541559027d0fd8f96ef75f313cOndrej Zary	u8 data;
10114219d06592025541559027d0fd8f96ef75f313cOndrej Zary
10231a62d415726d94bae5caf5f2e50232aa06babf6Hans de Goede	if (tea->ops->write_val)
10331a62d415726d94bae5caf5f2e50232aa06babf6Hans de Goede		return tea->ops->write_val(tea, val);
10431a62d415726d94bae5caf5f2e50232aa06babf6Hans de Goede
10514219d06592025541559027d0fd8f96ef75f313cOndrej Zary	tea->ops->set_direction(tea, 1);
10614219d06592025541559027d0fd8f96ef75f313cOndrej Zary	udelay(16);
10714219d06592025541559027d0fd8f96ef75f313cOndrej Zary
10814219d06592025541559027d0fd8f96ef75f313cOndrej Zary	for (l = 25; l > 0; l--) {
10914219d06592025541559027d0fd8f96ef75f313cOndrej Zary		data = (val >> 24) & TEA575X_DATA;
11014219d06592025541559027d0fd8f96ef75f313cOndrej Zary		val <<= 1;			/* shift data */
11114219d06592025541559027d0fd8f96ef75f313cOndrej Zary		tea->ops->set_pins(tea, data | TEA575X_WREN);
11214219d06592025541559027d0fd8f96ef75f313cOndrej Zary		udelay(2);
11314219d06592025541559027d0fd8f96ef75f313cOndrej Zary		tea->ops->set_pins(tea, data | TEA575X_WREN | TEA575X_CLK);
11414219d06592025541559027d0fd8f96ef75f313cOndrej Zary		udelay(2);
11514219d06592025541559027d0fd8f96ef75f313cOndrej Zary		tea->ops->set_pins(tea, data | TEA575X_WREN);
11614219d06592025541559027d0fd8f96ef75f313cOndrej Zary		udelay(2);
11714219d06592025541559027d0fd8f96ef75f313cOndrej Zary	}
11814219d06592025541559027d0fd8f96ef75f313cOndrej Zary
11914219d06592025541559027d0fd8f96ef75f313cOndrej Zary	if (!tea->mute)
12014219d06592025541559027d0fd8f96ef75f313cOndrej Zary		tea->ops->set_pins(tea, 0);
12114219d06592025541559027d0fd8f96ef75f313cOndrej Zary}
12214219d06592025541559027d0fd8f96ef75f313cOndrej Zary
123bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuilstatic u32 snd_tea575x_read(struct snd_tea575x *tea)
12414219d06592025541559027d0fd8f96ef75f313cOndrej Zary{
12514219d06592025541559027d0fd8f96ef75f313cOndrej Zary	u16 l, rdata;
12614219d06592025541559027d0fd8f96ef75f313cOndrej Zary	u32 data = 0;
12714219d06592025541559027d0fd8f96ef75f313cOndrej Zary
12831a62d415726d94bae5caf5f2e50232aa06babf6Hans de Goede	if (tea->ops->read_val)
12931a62d415726d94bae5caf5f2e50232aa06babf6Hans de Goede		return tea->ops->read_val(tea);
13031a62d415726d94bae5caf5f2e50232aa06babf6Hans de Goede
13114219d06592025541559027d0fd8f96ef75f313cOndrej Zary	tea->ops->set_direction(tea, 0);
13214219d06592025541559027d0fd8f96ef75f313cOndrej Zary	tea->ops->set_pins(tea, 0);
13314219d06592025541559027d0fd8f96ef75f313cOndrej Zary	udelay(16);
13414219d06592025541559027d0fd8f96ef75f313cOndrej Zary
13514219d06592025541559027d0fd8f96ef75f313cOndrej Zary	for (l = 24; l--;) {
13614219d06592025541559027d0fd8f96ef75f313cOndrej Zary		tea->ops->set_pins(tea, TEA575X_CLK);
13714219d06592025541559027d0fd8f96ef75f313cOndrej Zary		udelay(2);
13814219d06592025541559027d0fd8f96ef75f313cOndrej Zary		if (!l)
13914219d06592025541559027d0fd8f96ef75f313cOndrej Zary			tea->tuned = tea->ops->get_pins(tea) & TEA575X_MOST ? 0 : 1;
14014219d06592025541559027d0fd8f96ef75f313cOndrej Zary		tea->ops->set_pins(tea, 0);
14114219d06592025541559027d0fd8f96ef75f313cOndrej Zary		udelay(2);
14214219d06592025541559027d0fd8f96ef75f313cOndrej Zary		data <<= 1;			/* shift data */
14314219d06592025541559027d0fd8f96ef75f313cOndrej Zary		rdata = tea->ops->get_pins(tea);
14414219d06592025541559027d0fd8f96ef75f313cOndrej Zary		if (!l)
14514219d06592025541559027d0fd8f96ef75f313cOndrej Zary			tea->stereo = (rdata & TEA575X_MOST) ?  0 : 1;
14614219d06592025541559027d0fd8f96ef75f313cOndrej Zary		if (rdata & TEA575X_DATA)
14714219d06592025541559027d0fd8f96ef75f313cOndrej Zary			data++;
14814219d06592025541559027d0fd8f96ef75f313cOndrej Zary		udelay(2);
14914219d06592025541559027d0fd8f96ef75f313cOndrej Zary	}
15014219d06592025541559027d0fd8f96ef75f313cOndrej Zary
15114219d06592025541559027d0fd8f96ef75f313cOndrej Zary	if (tea->mute)
15214219d06592025541559027d0fd8f96ef75f313cOndrej Zary		tea->ops->set_pins(tea, TEA575X_WREN);
15314219d06592025541559027d0fd8f96ef75f313cOndrej Zary
15414219d06592025541559027d0fd8f96ef75f313cOndrej Zary	return data;
15514219d06592025541559027d0fd8f96ef75f313cOndrej Zary}
15614219d06592025541559027d0fd8f96ef75f313cOndrej Zary
15740e006aea811afb15e56164383b914cff7a078c7Hans de Goedestatic u32 snd_tea575x_val_to_freq(struct snd_tea575x *tea, u32 val)
158bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil{
15940e006aea811afb15e56164383b914cff7a078c7Hans de Goede	u32 freq = val & TEA575X_BIT_FREQ_MASK;
160bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil
161bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	if (freq == 0)
162bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil		return freq;
163bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil
164fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	switch (tea->band) {
165fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	case BAND_FM:
166fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		/* freq *= 12.5 */
167fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		freq *= 125;
168fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		freq /= 10;
169fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		/* crystal fixup */
170bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil		freq -= TEA575X_FMIF;
171fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		break;
172fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	case BAND_FM_JAPAN:
173fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		/* freq *= 12.5 */
174fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		freq *= 125;
175fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		freq /= 10;
176fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		/* crystal fixup */
177fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		freq += TEA575X_FMIF;
178fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		break;
179fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	case BAND_AM:
180fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		/* crystal fixup */
181fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		freq -= TEA575X_AMIF;
182fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		break;
183fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	}
184bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil
185fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	return clamp(freq * 16, bands[tea->band].rangelow,
186fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede				bands[tea->band].rangehigh); /* from kHz */
187bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil}
188bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil
18940e006aea811afb15e56164383b914cff7a078c7Hans de Goedestatic u32 snd_tea575x_get_freq(struct snd_tea575x *tea)
19040e006aea811afb15e56164383b914cff7a078c7Hans de Goede{
19140e006aea811afb15e56164383b914cff7a078c7Hans de Goede	return snd_tea575x_val_to_freq(tea, snd_tea575x_read(tea));
19240e006aea811afb15e56164383b914cff7a078c7Hans de Goede}
19340e006aea811afb15e56164383b914cff7a078c7Hans de Goede
194559c2009003bb8092e4927a4bac99cbf75834979Hans de Goedevoid snd_tea575x_set_freq(struct snd_tea575x *tea)
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
196fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	u32 freq = tea->freq / 16;	/* to kHz */
197fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	u32 band = 0;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
199fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	switch (tea->band) {
200fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	case BAND_FM:
201fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		band = TEA575X_BIT_BAND_FM;
202fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		/* crystal fixup */
203ea27316e4cd13b25727715c0db8adb0b1661f5e7Ondrej Zary		freq += TEA575X_FMIF;
204fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		/* freq /= 12.5 */
205fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		freq *= 10;
206fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		freq /= 125;
207fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		break;
208fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	case BAND_FM_JAPAN:
209fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		band = TEA575X_BIT_BAND_FM;
210fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		/* crystal fixup */
211fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		freq -= TEA575X_FMIF;
212fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		/* freq /= 12.5 */
213fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		freq *= 10;
214fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		freq /= 125;
215fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		break;
216fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	case BAND_AM:
217fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		band = TEA575X_BIT_BAND_MW;
218fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		/* crystal fixup */
219fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		freq += TEA575X_AMIF;
220fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		break;
221fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	}
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
223fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	tea->val &= ~(TEA575X_BIT_FREQ_MASK | TEA575X_BIT_BAND_MASK);
224fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	tea->val |= band;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tea->val |= freq & TEA575X_BIT_FREQ_MASK;
22614219d06592025541559027d0fd8f96ef75f313cOndrej Zary	snd_tea575x_write(tea, tea->val);
22740e006aea811afb15e56164383b914cff7a078c7Hans de Goede	tea->freq = snd_tea575x_val_to_freq(tea, tea->val);
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linux Video interface
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2349b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehabstatic int vidioc_querycap(struct file *file, void  *priv,
2359b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab					struct v4l2_capability *v)
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
237c170ecf434bceb0e188b14a6deb3bfa3ec9ef699Hans Verkuil	struct snd_tea575x *tea = video_drvdata(file);
2389b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
239d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	strlcpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver));
24010ca72014741554ad37c149ff0d9e93c1e3d5b7dOndrej Zary	strlcpy(v->card, tea->card, sizeof(v->card));
24110ca72014741554ad37c149ff0d9e93c1e3d5b7dOndrej Zary	strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card));
24210ca72014741554ad37c149ff0d9e93c1e3d5b7dOndrej Zary	strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
243d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
244d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	if (!tea->cannot_read_data)
245d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		v->device_caps |= V4L2_CAP_HW_FREQ_SEEK;
246d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
2479b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	return 0;
2489b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab}
2499b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
250fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goedestatic int vidioc_enum_freq_bands(struct file *file, void *priv,
251fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede					 struct v4l2_frequency_band *band)
252fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede{
253fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	struct snd_tea575x *tea = video_drvdata(file);
254fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	int index;
255fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede
256fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	if (band->tuner != 0)
257fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		return -EINVAL;
258fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede
259fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	switch (band->index) {
260fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	case 0:
261fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		if (tea->tea5759)
262fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			index = BAND_FM_JAPAN;
263fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		else
264fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			index = BAND_FM;
265fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		break;
266fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	case 1:
267fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		if (tea->has_am) {
268fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			index = BAND_AM;
269fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			break;
270fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		}
271fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		/* Fall through */
272fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	default:
273fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		return -EINVAL;
274fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	}
275fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede
276fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	*band = bands[index];
277fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	if (!tea->cannot_read_data)
278fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		band->capability |= V4L2_TUNER_CAP_HWSEEK_BOUNDED;
279fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede
280fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	return 0;
281fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede}
282fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede
2839b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehabstatic int vidioc_g_tuner(struct file *file, void *priv,
2849b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab					struct v4l2_tuner *v)
2859b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab{
286375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary	struct snd_tea575x *tea = video_drvdata(file);
287fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	struct v4l2_frequency_band band_fm = { 0, };
288375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary
2899b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	if (v->index > 0)
2909b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab		return -EINVAL;
2919b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
29214219d06592025541559027d0fd8f96ef75f313cOndrej Zary	snd_tea575x_read(tea);
293fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	vidioc_enum_freq_bands(file, priv, &band_fm);
294375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary
295fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	memset(v, 0, sizeof(*v));
296fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	strlcpy(v->name, tea->has_am ? "FM/AM" : "FM", sizeof(v->name));
2979b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	v->type = V4L2_TUNER_RADIO;
298fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	v->capability = band_fm.capability;
299fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	v->rangelow = tea->has_am ? bands[BAND_AM].rangelow : band_fm.rangelow;
300fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	v->rangehigh = band_fm.rangehigh;
301d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	v->rxsubchans = tea->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
302d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	v->audmode = (tea->val & TEA575X_BIT_MONO) ?
303d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO;
304375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary	v->signal = tea->tuned ? 0xffff : 0;
3059b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	return 0;
3069b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab}
3079b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
3089b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehabstatic int vidioc_s_tuner(struct file *file, void *priv,
3092f73c7c582a685b3198b974cd6d964d0338f8ab5Hans Verkuil					const struct v4l2_tuner *v)
3109b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab{
311d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	struct snd_tea575x *tea = video_drvdata(file);
312fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	u32 orig_val = tea->val;
313d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil
314d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	if (v->index)
3159b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab		return -EINVAL;
316d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	tea->val &= ~TEA575X_BIT_MONO;
317d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	if (v->audmode == V4L2_TUNER_MODE_MONO)
318d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		tea->val |= TEA575X_BIT_MONO;
319fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	/* Only apply changes if currently tuning FM */
320fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	if (tea->band != BAND_AM && tea->val != orig_val)
321fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		snd_tea575x_set_freq(tea);
322fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede
3239b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	return 0;
3249b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab}
3259b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
3269b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehabstatic int vidioc_g_frequency(struct file *file, void *priv,
3279b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab					struct v4l2_frequency *f)
3289b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab{
3299b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	struct snd_tea575x *tea = video_drvdata(file);
3309b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
331375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary	if (f->tuner != 0)
332375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary		return -EINVAL;
3339b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	f->type = V4L2_TUNER_RADIO;
3349b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	f->frequency = tea->freq;
3359b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	return 0;
3369b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab}
3379b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
3389b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehabstatic int vidioc_s_frequency(struct file *file, void *priv,
339b530a447bb588fdf43fdf4eb909e4ee1921d47acHans Verkuil					const struct v4l2_frequency *f)
3409b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab{
3419b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	struct snd_tea575x *tea = video_drvdata(file);
3429b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
343375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
344375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary		return -EINVAL;
345375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary
346fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	if (tea->has_am && f->frequency < (20000 * 16))
347fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		tea->band = BAND_AM;
348fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	else if (tea->tea5759)
349fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		tea->band = BAND_FM_JAPAN;
350fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	else
351fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		tea->band = BAND_FM;
352fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede
353b530a447bb588fdf43fdf4eb909e4ee1921d47acHans Verkuil	tea->freq = clamp_t(u32, f->frequency, bands[tea->band].rangelow,
354fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede					bands[tea->band].rangehigh);
3559b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	snd_tea575x_set_freq(tea);
3569b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	return 0;
3579b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab}
3589b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
359d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuilstatic int vidioc_s_hw_freq_seek(struct file *file, void *fh,
360ec6f4328108f1c83d5ac907c0d978fa886ef9627Hans Verkuil					const struct v4l2_hw_freq_seek *a)
3619b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab{
362d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	struct snd_tea575x *tea = video_drvdata(file);
363bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	unsigned long timeout;
364fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	int i, spacing;
3659b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
366d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	if (tea->cannot_read_data)
367d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		return -ENOTTY;
368d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	if (a->tuner || a->wrap_around)
3699b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab		return -EINVAL;
370bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil
371617ade61ea88a370c89960918eddfa10c41316f5Hans Verkuil	if (file->f_flags & O_NONBLOCK)
372617ade61ea88a370c89960918eddfa10c41316f5Hans Verkuil		return -EWOULDBLOCK;
373617ade61ea88a370c89960918eddfa10c41316f5Hans Verkuil
374fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	if (a->rangelow || a->rangehigh) {
375fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		for (i = 0; i < ARRAY_SIZE(bands); i++) {
376fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			if ((i == BAND_FM && tea->tea5759) ||
377fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			    (i == BAND_FM_JAPAN && !tea->tea5759) ||
378fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			    (i == BAND_AM && !tea->has_am))
379fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede				continue;
380fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			if (bands[i].rangelow  == a->rangelow &&
381fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			    bands[i].rangehigh == a->rangehigh)
382fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede				break;
383fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		}
384fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		if (i == ARRAY_SIZE(bands))
385fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			return -EINVAL; /* No matching band found */
386fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		if (i != tea->band) {
387fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			tea->band = i;
388fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			tea->freq = clamp(tea->freq, bands[i].rangelow,
389fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede						     bands[i].rangehigh);
390fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			snd_tea575x_set_freq(tea);
391fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede		}
392fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	}
393fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede
394fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	spacing = (tea->band == BAND_AM) ? 5 : 50; /* kHz */
395fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede
396bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	/* clear the frequency, HW will fill it in */
397bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	tea->val &= ~TEA575X_BIT_FREQ_MASK;
398d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	tea->val |= TEA575X_BIT_SEARCH;
399d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	if (a->seek_upward)
400d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		tea->val |= TEA575X_BIT_UPDOWN;
401bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	else
402bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil		tea->val &= ~TEA575X_BIT_UPDOWN;
403d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	snd_tea575x_write(tea, tea->val);
404bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	timeout = jiffies + msecs_to_jiffies(10000);
405d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	for (;;) {
406bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil		if (time_after(jiffies, timeout))
407bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			break;
408d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
409d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil			/* some signal arrived, stop search */
410d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil			tea->val &= ~TEA575X_BIT_SEARCH;
411bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			snd_tea575x_set_freq(tea);
412d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil			return -ERESTARTSYS;
413d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		}
414bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil		if (!(snd_tea575x_read(tea) & TEA575X_BIT_SEARCH)) {
415bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			u32 freq;
416bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil
417bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			/* Found a frequency, wait until it can be read */
418bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			for (i = 0; i < 100; i++) {
419bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil				msleep(10);
420bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil				freq = snd_tea575x_get_freq(tea);
421bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil				if (freq) /* available */
422bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil					break;
423bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			}
424bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			if (freq == 0) /* shouldn't happen */
425bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil				break;
426bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			/*
427fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			 * if we moved by less than the spacing, or in the
428fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			 * wrong direction, continue seeking
429bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			 */
430fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede			if (abs(tea->freq - freq) < 16 * spacing ||
431bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil					(a->seek_upward && freq < tea->freq) ||
432bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil					(!a->seek_upward && freq > tea->freq)) {
433bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil				snd_tea575x_write(tea, tea->val);
434bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil				continue;
435bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			}
436bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			tea->freq = freq;
437bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			tea->val &= ~TEA575X_BIT_SEARCH;
438bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			return 0;
439bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil		}
440d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	}
441bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	tea->val &= ~TEA575X_BIT_SEARCH;
442bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	snd_tea575x_set_freq(tea);
44354f6019b5860ec062d1149b3a97a5a63ad3e4da9Hans Verkuil	return -ENODATA;
4449b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab}
4459b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
4464522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zarystatic int tea575x_s_ctrl(struct v4l2_ctrl *ctrl)
4479b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab{
4484522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	struct snd_tea575x *tea = container_of(ctrl->handler, struct snd_tea575x, ctrl_handler);
4499b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
4509b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	switch (ctrl->id) {
4519b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	case V4L2_CID_AUDIO_MUTE:
4524522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary		tea->mute = ctrl->val;
4534522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary		snd_tea575x_set_freq(tea);
45414219d06592025541559027d0fd8f96ef75f313cOndrej Zary		return 0;
4559b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	}
4569b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
4579b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	return -EINVAL;
4589b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab}
4599b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
4609b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehabstatic const struct v4l2_file_operations tea575x_fops = {
4616a529c1a4a87e0f5d143ad3bc0d37179332f210eOndrej Zary	.unlocked_ioctl	= video_ioctl2,
462d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	.open           = v4l2_fh_open,
463d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	.release        = v4l2_fh_release,
464d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	.poll           = v4l2_ctrl_poll,
4659b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab};
4669b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
4679b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehabstatic const struct v4l2_ioctl_ops tea575x_ioctl_ops = {
4689b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	.vidioc_querycap    = vidioc_querycap,
4699b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	.vidioc_g_tuner     = vidioc_g_tuner,
4709b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	.vidioc_s_tuner     = vidioc_s_tuner,
4719b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	.vidioc_g_frequency = vidioc_g_frequency,
4729b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	.vidioc_s_frequency = vidioc_s_frequency,
473d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	.vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek,
474fc488517cc0d50bcc9e4ffa90fee5755f9c914fcHans de Goede	.vidioc_enum_freq_bands = vidioc_enum_freq_bands,
475d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	.vidioc_log_status  = v4l2_ctrl_log_status,
476d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
477d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
4789b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab};
4799b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
480d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuilstatic const struct video_device tea575x_radio = {
4819b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	.ioctl_ops 	= &tea575x_ioctl_ops,
482d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	.release        = video_device_release_empty,
4834522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary};
4844522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary
4854522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zarystatic const struct v4l2_ctrl_ops tea575x_ctrl_ops = {
4864522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	.s_ctrl = tea575x_s_ctrl,
4879b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab};
4889b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4908fd79579c9ccc6ac98d02c2c97d5fb367cfc0e29Ondrej Zaryint snd_tea575x_hw_init(struct snd_tea575x *tea)
4918fd79579c9ccc6ac98d02c2c97d5fb367cfc0e29Ondrej Zary{
492d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	tea->mute = true;
49314219d06592025541559027d0fd8f96ef75f313cOndrej Zary
494d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	/* Not all devices can or know how to read the data back.
495d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	   Such devices can set cannot_read_data to true. */
496d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	if (!tea->cannot_read_data) {
497d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		snd_tea575x_write(tea, 0x55AA);
498d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		if (snd_tea575x_read(tea) != 0x55AA)
499d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil			return -ENODEV;
500d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	}
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
502bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_5_28;
5039b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	tea->freq = 90500 * 16;		/* 90.5Mhz default */
5044522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	snd_tea575x_set_freq(tea);
5059b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
5068fd79579c9ccc6ac98d02c2c97d5fb367cfc0e29Ondrej Zary	return 0;
5078fd79579c9ccc6ac98d02c2c97d5fb367cfc0e29Ondrej Zary}
5088fd79579c9ccc6ac98d02c2c97d5fb367cfc0e29Ondrej ZaryEXPORT_SYMBOL(snd_tea575x_hw_init);
5098fd79579c9ccc6ac98d02c2c97d5fb367cfc0e29Ondrej Zary
5108fd79579c9ccc6ac98d02c2c97d5fb367cfc0e29Ondrej Zaryint snd_tea575x_init(struct snd_tea575x *tea, struct module *owner)
5118fd79579c9ccc6ac98d02c2c97d5fb367cfc0e29Ondrej Zary{
5128fd79579c9ccc6ac98d02c2c97d5fb367cfc0e29Ondrej Zary	int retval = snd_tea575x_hw_init(tea);
5138fd79579c9ccc6ac98d02c2c97d5fb367cfc0e29Ondrej Zary
5148fd79579c9ccc6ac98d02c2c97d5fb367cfc0e29Ondrej Zary	if (retval)
5158fd79579c9ccc6ac98d02c2c97d5fb367cfc0e29Ondrej Zary		return retval;
5168fd79579c9ccc6ac98d02c2c97d5fb367cfc0e29Ondrej Zary
5174522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	tea->vd = tea575x_radio;
5184522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	video_set_drvdata(&tea->vd, tea);
5196a529c1a4a87e0f5d143ad3bc0d37179332f210eOndrej Zary	mutex_init(&tea->mutex);
520d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	strlcpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name));
5216a529c1a4a87e0f5d143ad3bc0d37179332f210eOndrej Zary	tea->vd.lock = &tea->mutex;
522d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	tea->vd.v4l2_dev = tea->v4l2_dev;
5235daf53a6eb5c54c618c9def388d81c2769fd11a0Hans de Goede	tea->fops = tea575x_fops;
5245daf53a6eb5c54c618c9def388d81c2769fd11a0Hans de Goede	tea->fops.owner = owner;
5255daf53a6eb5c54c618c9def388d81c2769fd11a0Hans de Goede	tea->vd.fops = &tea->fops;
5266539799599f50e9ce36da784ee0f545540a9732cHans Verkuil	/* disable hw_freq_seek if we can't use it */
5276539799599f50e9ce36da784ee0f545540a9732cHans Verkuil	if (tea->cannot_read_data)
528152a3a7320d1582009db85d8be365ce430d079afHans Verkuil		v4l2_disable_ioctl(&tea->vd, VIDIOC_S_HW_FREQ_SEEK);
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5303d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede	if (!tea->cannot_mute) {
5313d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede		tea->vd.ctrl_handler = &tea->ctrl_handler;
5323d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede		v4l2_ctrl_handler_init(&tea->ctrl_handler, 1);
5333d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede		v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops,
5343d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede				  V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
5353d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede		retval = tea->ctrl_handler.error;
5364522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary		if (retval) {
5373d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede			v4l2_err(tea->v4l2_dev, "can't initialize controls\n");
5384522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary			v4l2_ctrl_handler_free(&tea->ctrl_handler);
5394522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary			return retval;
5404522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary		}
5419b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
5423d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede		if (tea->ext_init) {
5433d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede			retval = tea->ext_init(tea);
5443d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede			if (retval) {
5453d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede				v4l2_ctrl_handler_free(&tea->ctrl_handler);
5463d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede				return retval;
5473d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede			}
5483d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede		}
5493d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede
5503d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede		v4l2_ctrl_handler_setup(&tea->ctrl_handler);
5513d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede	}
5529b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
553d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, tea->radio_nr);
5549b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	if (retval) {
555d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		v4l2_err(tea->v4l2_dev, "can't register video device!\n");
5563d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede		v4l2_ctrl_handler_free(tea->vd.ctrl_handler);
55714219d06592025541559027d0fd8f96ef75f313cOndrej Zary		return retval;
5589b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	}
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
56014219d06592025541559027d0fd8f96ef75f313cOndrej Zary	return 0;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
56397f02e05f246a2346275c1c93a3079e8933e74b2Takashi Iwaivoid snd_tea575x_exit(struct snd_tea575x *tea)
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5654522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	video_unregister_device(&tea->vd);
5663d0fe51cfa3d07751224c034f8226136a7dd05f2Hans de Goede	v4l2_ctrl_handler_free(tea->vd.ctrl_handler);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init alsa_tea575x_module_init(void)
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5734b29631db33292d416dc395c56122ea865e7635cIgor M. Liplianin
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit alsa_tea575x_module_exit(void)
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5774b29631db33292d416dc395c56122ea865e7635cIgor M. Liplianin
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(alsa_tea575x_module_init)
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(alsa_tea575x_module_exit)
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(snd_tea575x_init);
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(snd_tea575x_exit);
583559c2009003bb8092e4927a4bac99cbf75834979Hans de GoedeEXPORT_SYMBOL(snd_tea575x_set_freq);
584