tea575x.c revision 54f6019b5860ec062d1149b3a97a5a63ad3e4da9
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 <asm/io.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
25da155d5b40587815a4397e1a69382fe2366d940bPaul Gortmaker#include <linux/module.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
275a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
28d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil#include <linux/sched.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>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sound/tea575x-tuner.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
40d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil#define FREQ_LO		 (76U * 16000)
41d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil#define FREQ_HI		(108U * 16000)
429b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * definitions
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_SEARCH	(1<<24)		/* 1 = search action, 0 = tuned */
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_UPDOWN	(1<<23)		/* 0 = search down, 1 = search up */
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_MONO	(1<<22)		/* 0 = stereo, 1 = mono */
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_BAND_MASK	(3<<20)
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_BAND_FM	(0<<20)
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_BAND_MW	(1<<20)
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_BAND_LW	(1<<21)
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_BAND_SW	(1<<22)
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_PORT_0	(1<<19)		/* user bit */
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_PORT_1	(1<<18)		/* user bit */
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_SEARCH_MASK	(3<<16)		/* search level */
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_SEARCH_5_28	     (0<<16)	/* FM >5uV, AM >28uV */
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_SEARCH_10_40     (1<<16)	/* FM >10uV, AM > 40uV */
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_SEARCH_30_63     (2<<16)	/* FM >30uV, AM > 63uV */
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_SEARCH_150_1000  (3<<16)	/* FM > 150uV, AM > 1000uV */
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_DUMMY	(1<<15)		/* buffer */
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEA575X_BIT_FREQ_MASK	0x7fff
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lowlevel part
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6914219d06592025541559027d0fd8f96ef75f313cOndrej Zarystatic void snd_tea575x_write(struct snd_tea575x *tea, unsigned int val)
7014219d06592025541559027d0fd8f96ef75f313cOndrej Zary{
7114219d06592025541559027d0fd8f96ef75f313cOndrej Zary	u16 l;
7214219d06592025541559027d0fd8f96ef75f313cOndrej Zary	u8 data;
7314219d06592025541559027d0fd8f96ef75f313cOndrej Zary
7414219d06592025541559027d0fd8f96ef75f313cOndrej Zary	tea->ops->set_direction(tea, 1);
7514219d06592025541559027d0fd8f96ef75f313cOndrej Zary	udelay(16);
7614219d06592025541559027d0fd8f96ef75f313cOndrej Zary
7714219d06592025541559027d0fd8f96ef75f313cOndrej Zary	for (l = 25; l > 0; l--) {
7814219d06592025541559027d0fd8f96ef75f313cOndrej Zary		data = (val >> 24) & TEA575X_DATA;
7914219d06592025541559027d0fd8f96ef75f313cOndrej Zary		val <<= 1;			/* shift data */
8014219d06592025541559027d0fd8f96ef75f313cOndrej Zary		tea->ops->set_pins(tea, data | TEA575X_WREN);
8114219d06592025541559027d0fd8f96ef75f313cOndrej Zary		udelay(2);
8214219d06592025541559027d0fd8f96ef75f313cOndrej Zary		tea->ops->set_pins(tea, data | TEA575X_WREN | TEA575X_CLK);
8314219d06592025541559027d0fd8f96ef75f313cOndrej Zary		udelay(2);
8414219d06592025541559027d0fd8f96ef75f313cOndrej Zary		tea->ops->set_pins(tea, data | TEA575X_WREN);
8514219d06592025541559027d0fd8f96ef75f313cOndrej Zary		udelay(2);
8614219d06592025541559027d0fd8f96ef75f313cOndrej Zary	}
8714219d06592025541559027d0fd8f96ef75f313cOndrej Zary
8814219d06592025541559027d0fd8f96ef75f313cOndrej Zary	if (!tea->mute)
8914219d06592025541559027d0fd8f96ef75f313cOndrej Zary		tea->ops->set_pins(tea, 0);
9014219d06592025541559027d0fd8f96ef75f313cOndrej Zary}
9114219d06592025541559027d0fd8f96ef75f313cOndrej Zary
92bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuilstatic u32 snd_tea575x_read(struct snd_tea575x *tea)
9314219d06592025541559027d0fd8f96ef75f313cOndrej Zary{
9414219d06592025541559027d0fd8f96ef75f313cOndrej Zary	u16 l, rdata;
9514219d06592025541559027d0fd8f96ef75f313cOndrej Zary	u32 data = 0;
9614219d06592025541559027d0fd8f96ef75f313cOndrej Zary
9714219d06592025541559027d0fd8f96ef75f313cOndrej Zary	tea->ops->set_direction(tea, 0);
9814219d06592025541559027d0fd8f96ef75f313cOndrej Zary	tea->ops->set_pins(tea, 0);
9914219d06592025541559027d0fd8f96ef75f313cOndrej Zary	udelay(16);
10014219d06592025541559027d0fd8f96ef75f313cOndrej Zary
10114219d06592025541559027d0fd8f96ef75f313cOndrej Zary	for (l = 24; l--;) {
10214219d06592025541559027d0fd8f96ef75f313cOndrej Zary		tea->ops->set_pins(tea, TEA575X_CLK);
10314219d06592025541559027d0fd8f96ef75f313cOndrej Zary		udelay(2);
10414219d06592025541559027d0fd8f96ef75f313cOndrej Zary		if (!l)
10514219d06592025541559027d0fd8f96ef75f313cOndrej Zary			tea->tuned = tea->ops->get_pins(tea) & TEA575X_MOST ? 0 : 1;
10614219d06592025541559027d0fd8f96ef75f313cOndrej Zary		tea->ops->set_pins(tea, 0);
10714219d06592025541559027d0fd8f96ef75f313cOndrej Zary		udelay(2);
10814219d06592025541559027d0fd8f96ef75f313cOndrej Zary		data <<= 1;			/* shift data */
10914219d06592025541559027d0fd8f96ef75f313cOndrej Zary		rdata = tea->ops->get_pins(tea);
11014219d06592025541559027d0fd8f96ef75f313cOndrej Zary		if (!l)
11114219d06592025541559027d0fd8f96ef75f313cOndrej Zary			tea->stereo = (rdata & TEA575X_MOST) ?  0 : 1;
11214219d06592025541559027d0fd8f96ef75f313cOndrej Zary		if (rdata & TEA575X_DATA)
11314219d06592025541559027d0fd8f96ef75f313cOndrej Zary			data++;
11414219d06592025541559027d0fd8f96ef75f313cOndrej Zary		udelay(2);
11514219d06592025541559027d0fd8f96ef75f313cOndrej Zary	}
11614219d06592025541559027d0fd8f96ef75f313cOndrej Zary
11714219d06592025541559027d0fd8f96ef75f313cOndrej Zary	if (tea->mute)
11814219d06592025541559027d0fd8f96ef75f313cOndrej Zary		tea->ops->set_pins(tea, TEA575X_WREN);
11914219d06592025541559027d0fd8f96ef75f313cOndrej Zary
12014219d06592025541559027d0fd8f96ef75f313cOndrej Zary	return data;
12114219d06592025541559027d0fd8f96ef75f313cOndrej Zary}
12214219d06592025541559027d0fd8f96ef75f313cOndrej Zary
123bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuilstatic u32 snd_tea575x_get_freq(struct snd_tea575x *tea)
124bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil{
125bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	u32 freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK;
126bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil
127bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	if (freq == 0)
128bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil		return freq;
129bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil
130bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	/* freq *= 12.5 */
131bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	freq *= 125;
132bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	freq /= 10;
133bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	/* crystal fixup */
134bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	if (tea->tea5759)
135bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil		freq += TEA575X_FMIF;
136bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	else
137bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil		freq -= TEA575X_FMIF;
138bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil
139bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	return clamp(freq * 16, FREQ_LO, FREQ_HI); /* from kHz */
140bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil}
141bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil
14297f02e05f246a2346275c1c93a3079e8933e74b2Takashi Iwaistatic void snd_tea575x_set_freq(struct snd_tea575x *tea)
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
144d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	u32 freq = tea->freq;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
146375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary	freq /= 16;		/* to kHz */
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* crystal fixup */
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tea->tea5759)
149ea27316e4cd13b25727715c0db8adb0b1661f5e7Ondrej Zary		freq -= TEA575X_FMIF;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
151ea27316e4cd13b25727715c0db8adb0b1661f5e7Ondrej Zary		freq += TEA575X_FMIF;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* freq /= 12.5 */
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	freq *= 10;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	freq /= 125;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tea->val &= ~TEA575X_BIT_FREQ_MASK;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tea->val |= freq & TEA575X_BIT_FREQ_MASK;
15814219d06592025541559027d0fd8f96ef75f313cOndrej Zary	snd_tea575x_write(tea, tea->val);
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linux Video interface
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1659b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehabstatic int vidioc_querycap(struct file *file, void  *priv,
1669b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab					struct v4l2_capability *v)
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
168c170ecf434bceb0e188b14a6deb3bfa3ec9ef699Hans Verkuil	struct snd_tea575x *tea = video_drvdata(file);
1699b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
170d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	strlcpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver));
17110ca72014741554ad37c149ff0d9e93c1e3d5b7dOndrej Zary	strlcpy(v->card, tea->card, sizeof(v->card));
17210ca72014741554ad37c149ff0d9e93c1e3d5b7dOndrej Zary	strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card));
17310ca72014741554ad37c149ff0d9e93c1e3d5b7dOndrej Zary	strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
174d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
175d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	if (!tea->cannot_read_data)
176d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		v->device_caps |= V4L2_CAP_HW_FREQ_SEEK;
177d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
1789b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	return 0;
1799b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab}
1809b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
1819b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehabstatic int vidioc_g_tuner(struct file *file, void *priv,
1829b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab					struct v4l2_tuner *v)
1839b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab{
184375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary	struct snd_tea575x *tea = video_drvdata(file);
185375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary
1869b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	if (v->index > 0)
1879b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab		return -EINVAL;
1889b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
18914219d06592025541559027d0fd8f96ef75f313cOndrej Zary	snd_tea575x_read(tea);
190375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary
1919b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	strcpy(v->name, "FM");
1929b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	v->type = V4L2_TUNER_RADIO;
193375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
19454f6019b5860ec062d1149b3a97a5a63ad3e4da9Hans Verkuil	if (!tea->cannot_read_data)
19554f6019b5860ec062d1149b3a97a5a63ad3e4da9Hans Verkuil		v->capability |= V4L2_TUNER_CAP_HWSEEK_BOUNDED;
1969b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	v->rangelow = FREQ_LO;
1979b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	v->rangehigh = FREQ_HI;
198d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	v->rxsubchans = tea->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
199d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	v->audmode = (tea->val & TEA575X_BIT_MONO) ?
200d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO;
201375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary	v->signal = tea->tuned ? 0xffff : 0;
2029b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	return 0;
2039b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab}
2049b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
2059b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehabstatic int vidioc_s_tuner(struct file *file, void *priv,
2069b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab					struct v4l2_tuner *v)
2079b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab{
208d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	struct snd_tea575x *tea = video_drvdata(file);
209d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil
210d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	if (v->index)
2119b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab		return -EINVAL;
212d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	tea->val &= ~TEA575X_BIT_MONO;
213d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	if (v->audmode == V4L2_TUNER_MODE_MONO)
214d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		tea->val |= TEA575X_BIT_MONO;
215d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	snd_tea575x_write(tea, tea->val);
2169b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	return 0;
2179b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab}
2189b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
2199b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehabstatic int vidioc_g_frequency(struct file *file, void *priv,
2209b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab					struct v4l2_frequency *f)
2219b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab{
2229b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	struct snd_tea575x *tea = video_drvdata(file);
2239b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
224375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary	if (f->tuner != 0)
225375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary		return -EINVAL;
2269b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	f->type = V4L2_TUNER_RADIO;
2279b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	f->frequency = tea->freq;
2289b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	return 0;
2299b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab}
2309b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
2319b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehabstatic int vidioc_s_frequency(struct file *file, void *priv,
2329b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab					struct v4l2_frequency *f)
2339b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab{
2349b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	struct snd_tea575x *tea = video_drvdata(file);
2359b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
236375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
237375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary		return -EINVAL;
238375d135818f32bbe7b3f071bd54d977c4ff8d84aOndrej Zary
239d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	tea->val &= ~TEA575X_BIT_SEARCH;
240d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	tea->freq = clamp(f->frequency, FREQ_LO, FREQ_HI);
2419b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	snd_tea575x_set_freq(tea);
2429b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	return 0;
2439b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab}
2449b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
245d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuilstatic int vidioc_s_hw_freq_seek(struct file *file, void *fh,
246d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil					struct v4l2_hw_freq_seek *a)
2479b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab{
248d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	struct snd_tea575x *tea = video_drvdata(file);
249bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	unsigned long timeout;
250bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	int i;
2519b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
252d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	if (tea->cannot_read_data)
253d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		return -ENOTTY;
254d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	if (a->tuner || a->wrap_around)
2559b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab		return -EINVAL;
256bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil
257bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	/* clear the frequency, HW will fill it in */
258bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	tea->val &= ~TEA575X_BIT_FREQ_MASK;
259d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	tea->val |= TEA575X_BIT_SEARCH;
260d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	if (a->seek_upward)
261d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		tea->val |= TEA575X_BIT_UPDOWN;
262bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	else
263bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil		tea->val &= ~TEA575X_BIT_UPDOWN;
264d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	snd_tea575x_write(tea, tea->val);
265bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	timeout = jiffies + msecs_to_jiffies(10000);
266d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	for (;;) {
267bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil		if (time_after(jiffies, timeout))
268bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			break;
269d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
270d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil			/* some signal arrived, stop search */
271d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil			tea->val &= ~TEA575X_BIT_SEARCH;
272bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			snd_tea575x_set_freq(tea);
273d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil			return -ERESTARTSYS;
274d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		}
275bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil		if (!(snd_tea575x_read(tea) & TEA575X_BIT_SEARCH)) {
276bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			u32 freq;
277bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil
278bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			/* Found a frequency, wait until it can be read */
279bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			for (i = 0; i < 100; i++) {
280bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil				msleep(10);
281bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil				freq = snd_tea575x_get_freq(tea);
282bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil				if (freq) /* available */
283bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil					break;
284bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			}
285bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			if (freq == 0) /* shouldn't happen */
286bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil				break;
287bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			/*
288bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			 * if we moved by less than 50 kHz, or in the wrong
289bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			 * direction, continue seeking
290bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			 */
291bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			if (abs(tea->freq - freq) < 16 * 50 ||
292bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil					(a->seek_upward && freq < tea->freq) ||
293bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil					(!a->seek_upward && freq > tea->freq)) {
294bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil				snd_tea575x_write(tea, tea->val);
295bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil				continue;
296bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			}
297bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			tea->freq = freq;
298bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			tea->val &= ~TEA575X_BIT_SEARCH;
299bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil			return 0;
300bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil		}
301d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	}
302bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	tea->val &= ~TEA575X_BIT_SEARCH;
303bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	snd_tea575x_set_freq(tea);
30454f6019b5860ec062d1149b3a97a5a63ad3e4da9Hans Verkuil	return -ENODATA;
3059b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab}
3069b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
3074522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zarystatic int tea575x_s_ctrl(struct v4l2_ctrl *ctrl)
3089b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab{
3094522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	struct snd_tea575x *tea = container_of(ctrl->handler, struct snd_tea575x, ctrl_handler);
3109b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
3119b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	switch (ctrl->id) {
3129b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	case V4L2_CID_AUDIO_MUTE:
3134522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary		tea->mute = ctrl->val;
3144522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary		snd_tea575x_set_freq(tea);
31514219d06592025541559027d0fd8f96ef75f313cOndrej Zary		return 0;
3169b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	}
3179b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
3189b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	return -EINVAL;
3199b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab}
3209b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
3219b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehabstatic const struct v4l2_file_operations tea575x_fops = {
3229b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	.owner		= THIS_MODULE,
3236a529c1a4a87e0f5d143ad3bc0d37179332f210eOndrej Zary	.unlocked_ioctl	= video_ioctl2,
324d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	.open           = v4l2_fh_open,
325d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	.release        = v4l2_fh_release,
326d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	.poll           = v4l2_ctrl_poll,
3279b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab};
3289b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
3299b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehabstatic const struct v4l2_ioctl_ops tea575x_ioctl_ops = {
3309b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	.vidioc_querycap    = vidioc_querycap,
3319b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	.vidioc_g_tuner     = vidioc_g_tuner,
3329b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	.vidioc_s_tuner     = vidioc_s_tuner,
3339b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	.vidioc_g_frequency = vidioc_g_frequency,
3349b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	.vidioc_s_frequency = vidioc_s_frequency,
335d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	.vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek,
336d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	.vidioc_log_status  = v4l2_ctrl_log_status,
337d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
338d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
3399b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab};
3409b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
341d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuilstatic const struct video_device tea575x_radio = {
3429b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	.fops           = &tea575x_fops,
3439b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	.ioctl_ops 	= &tea575x_ioctl_ops,
344d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	.release        = video_device_release_empty,
3454522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary};
3464522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary
3474522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zarystatic const struct v4l2_ctrl_ops tea575x_ctrl_ops = {
3484522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	.s_ctrl = tea575x_s_ctrl,
3499b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab};
3509b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * initialize all the tea575x chips
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
35414219d06592025541559027d0fd8f96ef75f313cOndrej Zaryint snd_tea575x_init(struct snd_tea575x *tea)
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3569b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	int retval;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
358d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	tea->mute = true;
35914219d06592025541559027d0fd8f96ef75f313cOndrej Zary
360d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	/* Not all devices can or know how to read the data back.
361d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	   Such devices can set cannot_read_data to true. */
362d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	if (!tea->cannot_read_data) {
363d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		snd_tea575x_write(tea, 0x55AA);
364d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		if (snd_tea575x_read(tea) != 0x55AA)
365d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil			return -ENODEV;
366d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	}
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
368bc2b395c031430639e5ad5dcb2669cfcf1fa5fd2Hans Verkuil	tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_5_28;
3699b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	tea->freq = 90500 * 16;		/* 90.5Mhz default */
3704522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	snd_tea575x_set_freq(tea);
3719b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
3724522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	tea->vd = tea575x_radio;
3734522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	video_set_drvdata(&tea->vd, tea);
3746a529c1a4a87e0f5d143ad3bc0d37179332f210eOndrej Zary	mutex_init(&tea->mutex);
375d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	strlcpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name));
3766a529c1a4a87e0f5d143ad3bc0d37179332f210eOndrej Zary	tea->vd.lock = &tea->mutex;
377d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	tea->vd.v4l2_dev = tea->v4l2_dev;
378d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	tea->vd.ctrl_handler = &tea->ctrl_handler;
379d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	set_bit(V4L2_FL_USE_FH_PRIO, &tea->vd.flags);
3806539799599f50e9ce36da784ee0f545540a9732cHans Verkuil	/* disable hw_freq_seek if we can't use it */
3816539799599f50e9ce36da784ee0f545540a9732cHans Verkuil	if (tea->cannot_read_data)
382152a3a7320d1582009db85d8be365ce430d079afHans Verkuil		v4l2_disable_ioctl(&tea->vd, VIDIOC_S_HW_FREQ_SEEK);
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3844522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	v4l2_ctrl_handler_init(&tea->ctrl_handler, 1);
3854522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops, V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
3864522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	retval = tea->ctrl_handler.error;
3874522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	if (retval) {
388d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		v4l2_err(tea->v4l2_dev, "can't initialize controls\n");
3894522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary		v4l2_ctrl_handler_free(&tea->ctrl_handler);
3904522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary		return retval;
3914522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	}
3929b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
3934522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	if (tea->ext_init) {
3944522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary		retval = tea->ext_init(tea);
3954522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary		if (retval) {
3964522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary			v4l2_ctrl_handler_free(&tea->ctrl_handler);
3974522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary			return retval;
3984522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary		}
3994522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	}
4009b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
4014522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	v4l2_ctrl_handler_setup(&tea->ctrl_handler);
4029b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab
403d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil	retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, tea->radio_nr);
4049b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	if (retval) {
405d4ecc83b79cc290eadf1ffb33a589c3c72bbc295Hans Verkuil		v4l2_err(tea->v4l2_dev, "can't register video device!\n");
4064522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary		v4l2_ctrl_handler_free(&tea->ctrl_handler);
40714219d06592025541559027d0fd8f96ef75f313cOndrej Zary		return retval;
4089b76ede411145d7456ae5e467b65003ca7990b06Mauro Carvalho Chehab	}
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41014219d06592025541559027d0fd8f96ef75f313cOndrej Zary	return 0;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41397f02e05f246a2346275c1c93a3079e8933e74b2Takashi Iwaivoid snd_tea575x_exit(struct snd_tea575x *tea)
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4154522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	video_unregister_device(&tea->vd);
4164522e825dbfc19537a08f65719dc3d69c46fe661Ondrej Zary	v4l2_ctrl_handler_free(&tea->ctrl_handler);
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init alsa_tea575x_module_init(void)
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4234b29631db33292d416dc395c56122ea865e7635cIgor M. Liplianin
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit alsa_tea575x_module_exit(void)
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4274b29631db33292d416dc395c56122ea865e7635cIgor M. Liplianin
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(alsa_tea575x_module_init)
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(alsa_tea575x_module_exit)
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(snd_tea575x_init);
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(snd_tea575x_exit);
433