[media] Fix VIDIOC_TRY_EXT_CTRLS regression
[deliverable/linux.git] / sound / i2c / other / tea575x-tuner.c
CommitLineData
1da177e4
LT
1/*
2 * ALSA driver for TEA5757/5759 Philips AM/FM radio tuner chips
3 *
c1017a4c 4 * Copyright (c) 2004 Jaroslav Kysela <perex@perex.cz>
1da177e4
LT
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
4b29631d 21 */
1da177e4 22
1da177e4
LT
23#include <asm/io.h>
24#include <linux/delay.h>
da155d5b 25#include <linux/module.h>
1da177e4 26#include <linux/init.h>
5a0e3ad6 27#include <linux/slab.h>
d4ecc83b
HV
28#include <linux/sched.h>
29#include <media/v4l2-device.h>
4522e825 30#include <media/v4l2-dev.h>
d4ecc83b 31#include <media/v4l2-fh.h>
4522e825 32#include <media/v4l2-ioctl.h>
d4ecc83b 33#include <media/v4l2-event.h>
1da177e4
LT
34#include <sound/tea575x-tuner.h>
35
c1017a4c 36MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
1da177e4
LT
37MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips");
38MODULE_LICENSE("GPL");
39
0875eb75
HG
40#define FREQ_LO ((tea->tea5759 ? 760 : 875) * 1600U)
41#define FREQ_HI ((tea->tea5759 ? 910 : 1080) * 1600U)
9b76ede4 42
1da177e4
LT
43/*
44 * definitions
45 */
46
47#define TEA575X_BIT_SEARCH (1<<24) /* 1 = search action, 0 = tuned */
48#define TEA575X_BIT_UPDOWN (1<<23) /* 0 = search down, 1 = search up */
49#define TEA575X_BIT_MONO (1<<22) /* 0 = stereo, 1 = mono */
50#define TEA575X_BIT_BAND_MASK (3<<20)
51#define TEA575X_BIT_BAND_FM (0<<20)
52#define TEA575X_BIT_BAND_MW (1<<20)
53#define TEA575X_BIT_BAND_LW (1<<21)
54#define TEA575X_BIT_BAND_SW (1<<22)
55#define TEA575X_BIT_PORT_0 (1<<19) /* user bit */
56#define TEA575X_BIT_PORT_1 (1<<18) /* user bit */
57#define TEA575X_BIT_SEARCH_MASK (3<<16) /* search level */
58#define TEA575X_BIT_SEARCH_5_28 (0<<16) /* FM >5uV, AM >28uV */
59#define TEA575X_BIT_SEARCH_10_40 (1<<16) /* FM >10uV, AM > 40uV */
60#define TEA575X_BIT_SEARCH_30_63 (2<<16) /* FM >30uV, AM > 63uV */
61#define TEA575X_BIT_SEARCH_150_1000 (3<<16) /* FM > 150uV, AM > 1000uV */
62#define TEA575X_BIT_DUMMY (1<<15) /* buffer */
63#define TEA575X_BIT_FREQ_MASK 0x7fff
64
65/*
66 * lowlevel part
67 */
68
14219d06
OZ
69static void snd_tea575x_write(struct snd_tea575x *tea, unsigned int val)
70{
71 u16 l;
72 u8 data;
73
74 tea->ops->set_direction(tea, 1);
75 udelay(16);
76
77 for (l = 25; l > 0; l--) {
78 data = (val >> 24) & TEA575X_DATA;
79 val <<= 1; /* shift data */
80 tea->ops->set_pins(tea, data | TEA575X_WREN);
81 udelay(2);
82 tea->ops->set_pins(tea, data | TEA575X_WREN | TEA575X_CLK);
83 udelay(2);
84 tea->ops->set_pins(tea, data | TEA575X_WREN);
85 udelay(2);
86 }
87
88 if (!tea->mute)
89 tea->ops->set_pins(tea, 0);
90}
91
bc2b395c 92static u32 snd_tea575x_read(struct snd_tea575x *tea)
14219d06
OZ
93{
94 u16 l, rdata;
95 u32 data = 0;
96
97 tea->ops->set_direction(tea, 0);
98 tea->ops->set_pins(tea, 0);
99 udelay(16);
100
101 for (l = 24; l--;) {
102 tea->ops->set_pins(tea, TEA575X_CLK);
103 udelay(2);
104 if (!l)
105 tea->tuned = tea->ops->get_pins(tea) & TEA575X_MOST ? 0 : 1;
106 tea->ops->set_pins(tea, 0);
107 udelay(2);
108 data <<= 1; /* shift data */
109 rdata = tea->ops->get_pins(tea);
110 if (!l)
111 tea->stereo = (rdata & TEA575X_MOST) ? 0 : 1;
112 if (rdata & TEA575X_DATA)
113 data++;
114 udelay(2);
115 }
116
117 if (tea->mute)
118 tea->ops->set_pins(tea, TEA575X_WREN);
119
120 return data;
121}
122
40e006ae 123static u32 snd_tea575x_val_to_freq(struct snd_tea575x *tea, u32 val)
bc2b395c 124{
40e006ae 125 u32 freq = val & TEA575X_BIT_FREQ_MASK;
bc2b395c
HV
126
127 if (freq == 0)
128 return freq;
129
130 /* freq *= 12.5 */
131 freq *= 125;
132 freq /= 10;
133 /* crystal fixup */
134 if (tea->tea5759)
135 freq += TEA575X_FMIF;
136 else
137 freq -= TEA575X_FMIF;
138
139 return clamp(freq * 16, FREQ_LO, FREQ_HI); /* from kHz */
140}
141
40e006ae
HG
142static u32 snd_tea575x_get_freq(struct snd_tea575x *tea)
143{
144 return snd_tea575x_val_to_freq(tea, snd_tea575x_read(tea));
145}
146
97f02e05 147static void snd_tea575x_set_freq(struct snd_tea575x *tea)
1da177e4 148{
d4ecc83b 149 u32 freq = tea->freq;
1da177e4 150
375d1358 151 freq /= 16; /* to kHz */
1da177e4
LT
152 /* crystal fixup */
153 if (tea->tea5759)
ea27316e 154 freq -= TEA575X_FMIF;
1da177e4 155 else
ea27316e 156 freq += TEA575X_FMIF;
1da177e4
LT
157 /* freq /= 12.5 */
158 freq *= 10;
159 freq /= 125;
160
161 tea->val &= ~TEA575X_BIT_FREQ_MASK;
162 tea->val |= freq & TEA575X_BIT_FREQ_MASK;
14219d06 163 snd_tea575x_write(tea, tea->val);
40e006ae 164 tea->freq = snd_tea575x_val_to_freq(tea, tea->val);
1da177e4
LT
165}
166
167/*
168 * Linux Video interface
169 */
170
9b76ede4
MCC
171static int vidioc_querycap(struct file *file, void *priv,
172 struct v4l2_capability *v)
1da177e4 173{
c170ecf4 174 struct snd_tea575x *tea = video_drvdata(file);
9b76ede4 175
d4ecc83b 176 strlcpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver));
10ca7201
OZ
177 strlcpy(v->card, tea->card, sizeof(v->card));
178 strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card));
179 strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
d4ecc83b
HV
180 v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
181 if (!tea->cannot_read_data)
182 v->device_caps |= V4L2_CAP_HW_FREQ_SEEK;
183 v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
9b76ede4
MCC
184 return 0;
185}
186
187static int vidioc_g_tuner(struct file *file, void *priv,
188 struct v4l2_tuner *v)
189{
375d1358
OZ
190 struct snd_tea575x *tea = video_drvdata(file);
191
9b76ede4
MCC
192 if (v->index > 0)
193 return -EINVAL;
194
14219d06 195 snd_tea575x_read(tea);
375d1358 196
9b76ede4
MCC
197 strcpy(v->name, "FM");
198 v->type = V4L2_TUNER_RADIO;
375d1358 199 v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
54f6019b
HV
200 if (!tea->cannot_read_data)
201 v->capability |= V4L2_TUNER_CAP_HWSEEK_BOUNDED;
9b76ede4
MCC
202 v->rangelow = FREQ_LO;
203 v->rangehigh = FREQ_HI;
d4ecc83b
HV
204 v->rxsubchans = tea->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
205 v->audmode = (tea->val & TEA575X_BIT_MONO) ?
206 V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO;
375d1358 207 v->signal = tea->tuned ? 0xffff : 0;
9b76ede4
MCC
208 return 0;
209}
210
211static int vidioc_s_tuner(struct file *file, void *priv,
212 struct v4l2_tuner *v)
213{
d4ecc83b
HV
214 struct snd_tea575x *tea = video_drvdata(file);
215
216 if (v->index)
9b76ede4 217 return -EINVAL;
d4ecc83b
HV
218 tea->val &= ~TEA575X_BIT_MONO;
219 if (v->audmode == V4L2_TUNER_MODE_MONO)
220 tea->val |= TEA575X_BIT_MONO;
221 snd_tea575x_write(tea, tea->val);
9b76ede4
MCC
222 return 0;
223}
224
225static int vidioc_g_frequency(struct file *file, void *priv,
226 struct v4l2_frequency *f)
227{
228 struct snd_tea575x *tea = video_drvdata(file);
229
375d1358
OZ
230 if (f->tuner != 0)
231 return -EINVAL;
9b76ede4
MCC
232 f->type = V4L2_TUNER_RADIO;
233 f->frequency = tea->freq;
234 return 0;
235}
236
237static int vidioc_s_frequency(struct file *file, void *priv,
238 struct v4l2_frequency *f)
239{
240 struct snd_tea575x *tea = video_drvdata(file);
241
375d1358
OZ
242 if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
243 return -EINVAL;
244
d4ecc83b
HV
245 tea->val &= ~TEA575X_BIT_SEARCH;
246 tea->freq = clamp(f->frequency, FREQ_LO, FREQ_HI);
9b76ede4 247 snd_tea575x_set_freq(tea);
9b76ede4
MCC
248 return 0;
249}
250
d4ecc83b
HV
251static int vidioc_s_hw_freq_seek(struct file *file, void *fh,
252 struct v4l2_hw_freq_seek *a)
9b76ede4 253{
d4ecc83b 254 struct snd_tea575x *tea = video_drvdata(file);
bc2b395c
HV
255 unsigned long timeout;
256 int i;
9b76ede4 257
d4ecc83b
HV
258 if (tea->cannot_read_data)
259 return -ENOTTY;
260 if (a->tuner || a->wrap_around)
9b76ede4 261 return -EINVAL;
bc2b395c
HV
262
263 /* clear the frequency, HW will fill it in */
264 tea->val &= ~TEA575X_BIT_FREQ_MASK;
d4ecc83b 265 tea->val |= TEA575X_BIT_SEARCH;
d4ecc83b
HV
266 if (a->seek_upward)
267 tea->val |= TEA575X_BIT_UPDOWN;
bc2b395c
HV
268 else
269 tea->val &= ~TEA575X_BIT_UPDOWN;
d4ecc83b 270 snd_tea575x_write(tea, tea->val);
bc2b395c 271 timeout = jiffies + msecs_to_jiffies(10000);
d4ecc83b 272 for (;;) {
bc2b395c
HV
273 if (time_after(jiffies, timeout))
274 break;
d4ecc83b
HV
275 if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
276 /* some signal arrived, stop search */
277 tea->val &= ~TEA575X_BIT_SEARCH;
bc2b395c 278 snd_tea575x_set_freq(tea);
d4ecc83b
HV
279 return -ERESTARTSYS;
280 }
bc2b395c
HV
281 if (!(snd_tea575x_read(tea) & TEA575X_BIT_SEARCH)) {
282 u32 freq;
283
284 /* Found a frequency, wait until it can be read */
285 for (i = 0; i < 100; i++) {
286 msleep(10);
287 freq = snd_tea575x_get_freq(tea);
288 if (freq) /* available */
289 break;
290 }
291 if (freq == 0) /* shouldn't happen */
292 break;
293 /*
294 * if we moved by less than 50 kHz, or in the wrong
295 * direction, continue seeking
296 */
297 if (abs(tea->freq - freq) < 16 * 50 ||
298 (a->seek_upward && freq < tea->freq) ||
299 (!a->seek_upward && freq > tea->freq)) {
300 snd_tea575x_write(tea, tea->val);
301 continue;
302 }
303 tea->freq = freq;
304 tea->val &= ~TEA575X_BIT_SEARCH;
305 return 0;
306 }
d4ecc83b 307 }
bc2b395c
HV
308 tea->val &= ~TEA575X_BIT_SEARCH;
309 snd_tea575x_set_freq(tea);
54f6019b 310 return -ENODATA;
9b76ede4
MCC
311}
312
4522e825 313static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl)
9b76ede4 314{
4522e825 315 struct snd_tea575x *tea = container_of(ctrl->handler, struct snd_tea575x, ctrl_handler);
9b76ede4
MCC
316
317 switch (ctrl->id) {
318 case V4L2_CID_AUDIO_MUTE:
4522e825
OZ
319 tea->mute = ctrl->val;
320 snd_tea575x_set_freq(tea);
14219d06 321 return 0;
9b76ede4 322 }
9b76ede4 323
9b76ede4
MCC
324 return -EINVAL;
325}
326
9b76ede4 327static const struct v4l2_file_operations tea575x_fops = {
6a529c1a 328 .unlocked_ioctl = video_ioctl2,
d4ecc83b
HV
329 .open = v4l2_fh_open,
330 .release = v4l2_fh_release,
331 .poll = v4l2_ctrl_poll,
9b76ede4
MCC
332};
333
334static const struct v4l2_ioctl_ops tea575x_ioctl_ops = {
335 .vidioc_querycap = vidioc_querycap,
336 .vidioc_g_tuner = vidioc_g_tuner,
337 .vidioc_s_tuner = vidioc_s_tuner,
9b76ede4
MCC
338 .vidioc_g_frequency = vidioc_g_frequency,
339 .vidioc_s_frequency = vidioc_s_frequency,
d4ecc83b
HV
340 .vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek,
341 .vidioc_log_status = v4l2_ctrl_log_status,
342 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
343 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
9b76ede4
MCC
344};
345
d4ecc83b 346static const struct video_device tea575x_radio = {
9b76ede4 347 .ioctl_ops = &tea575x_ioctl_ops,
d4ecc83b 348 .release = video_device_release_empty,
4522e825
OZ
349};
350
351static const struct v4l2_ctrl_ops tea575x_ctrl_ops = {
352 .s_ctrl = tea575x_s_ctrl,
9b76ede4
MCC
353};
354
1da177e4
LT
355/*
356 * initialize all the tea575x chips
357 */
5daf53a6 358int snd_tea575x_init(struct snd_tea575x *tea, struct module *owner)
1da177e4 359{
9b76ede4 360 int retval;
1da177e4 361
d4ecc83b 362 tea->mute = true;
14219d06 363
d4ecc83b
HV
364 /* Not all devices can or know how to read the data back.
365 Such devices can set cannot_read_data to true. */
366 if (!tea->cannot_read_data) {
367 snd_tea575x_write(tea, 0x55AA);
368 if (snd_tea575x_read(tea) != 0x55AA)
369 return -ENODEV;
370 }
1da177e4 371
bc2b395c 372 tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_5_28;
9b76ede4 373 tea->freq = 90500 * 16; /* 90.5Mhz default */
4522e825 374 snd_tea575x_set_freq(tea);
9b76ede4 375
4522e825
OZ
376 tea->vd = tea575x_radio;
377 video_set_drvdata(&tea->vd, tea);
6a529c1a 378 mutex_init(&tea->mutex);
d4ecc83b 379 strlcpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name));
6a529c1a 380 tea->vd.lock = &tea->mutex;
d4ecc83b
HV
381 tea->vd.v4l2_dev = tea->v4l2_dev;
382 tea->vd.ctrl_handler = &tea->ctrl_handler;
5daf53a6
HG
383 tea->fops = tea575x_fops;
384 tea->fops.owner = owner;
385 tea->vd.fops = &tea->fops;
d4ecc83b 386 set_bit(V4L2_FL_USE_FH_PRIO, &tea->vd.flags);
65397995
HV
387 /* disable hw_freq_seek if we can't use it */
388 if (tea->cannot_read_data)
152a3a73 389 v4l2_disable_ioctl(&tea->vd, VIDIOC_S_HW_FREQ_SEEK);
1da177e4 390
4522e825 391 v4l2_ctrl_handler_init(&tea->ctrl_handler, 1);
4522e825
OZ
392 v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops, V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
393 retval = tea->ctrl_handler.error;
394 if (retval) {
d4ecc83b 395 v4l2_err(tea->v4l2_dev, "can't initialize controls\n");
4522e825
OZ
396 v4l2_ctrl_handler_free(&tea->ctrl_handler);
397 return retval;
398 }
9b76ede4 399
4522e825
OZ
400 if (tea->ext_init) {
401 retval = tea->ext_init(tea);
402 if (retval) {
403 v4l2_ctrl_handler_free(&tea->ctrl_handler);
404 return retval;
405 }
406 }
9b76ede4 407
4522e825 408 v4l2_ctrl_handler_setup(&tea->ctrl_handler);
9b76ede4 409
d4ecc83b 410 retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, tea->radio_nr);
9b76ede4 411 if (retval) {
d4ecc83b 412 v4l2_err(tea->v4l2_dev, "can't register video device!\n");
4522e825 413 v4l2_ctrl_handler_free(&tea->ctrl_handler);
14219d06 414 return retval;
9b76ede4 415 }
1da177e4 416
14219d06 417 return 0;
1da177e4
LT
418}
419
97f02e05 420void snd_tea575x_exit(struct snd_tea575x *tea)
1da177e4 421{
4522e825
OZ
422 video_unregister_device(&tea->vd);
423 v4l2_ctrl_handler_free(&tea->ctrl_handler);
1da177e4
LT
424}
425
426static int __init alsa_tea575x_module_init(void)
427{
428 return 0;
429}
4b29631d 430
1da177e4
LT
431static void __exit alsa_tea575x_module_exit(void)
432{
433}
4b29631d 434
1da177e4
LT
435module_init(alsa_tea575x_module_init)
436module_exit(alsa_tea575x_module_exit)
437
438EXPORT_SYMBOL(snd_tea575x_init);
439EXPORT_SYMBOL(snd_tea575x_exit);
This page took 0.579255 seconds and 5 git commands to generate.