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